硬汉嵌入式论坛

 找回密码
 立即注册
查看: 4469|回复: 6
收起左侧

[FreeRTOS教程] 第31章 FreeRTOS低功耗之停机模式

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2016-9-13 17:01:38 | 显示全部楼层 |阅读模式




第31章      FreeRTOS低功耗之停机模式


        低功耗是MCU的一项重要的指标,本章节为大家讲解STM32F103,STM32F407和STM32F429的低功耗方式之停机模式在FreeRTOS操作系统上面的实现方法。
        本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
31.1 STM32F103停机模式介绍
31.2 STM32F4xx停机模式介绍
31.3 如何有效降低停机模式下的功耗
31.4 实验例程说明
31.5      总结



31.1  STM32F103停机模式介绍


        说明:在FreeRTOS系统上面实现停机方式仅需了解这里讲解的知识基本就够用了,更多停机方式的知识请看STM32F103参考手册和Cortex-M3权威指南。
       在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时,用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
         STM32F103有三种低功耗模式:
    (1)睡眠模式(Cortex™-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统滴答定时器Systick等仍在运行)
    (2)停机模式(所有的时钟都已停止)
    (3)待机模式(1.8V电源关闭)
       本章节我们主要讲解停机模式,停机模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停机模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止, PLL、 HSI和HSE RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来。在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
       在实际的停机模式编程时需要清楚哪些问题呢? 请继续往下看。

31.1.1  STM32F103如何进入停机模式


        在FreeRTOS系统中,让STM32进入停机模式比较容易,调用固件库函数PWR_EnterSTOPMode即可,不过要注意:为了进入停机模式,所有的外部中断的请求位(挂起寄存器(EXTI_PR))和RTC的闹钟标志都必须被清除,否则停止模式的进入流程将会被跳过,程序继续运行。

31.1.2 STM32F103如何退出停机模式


       由于我们是采用指令WFI指令进入停机模式,那么设置任一外部中断线EXTI为中断模式并且在NVIC中必须使能相应的外部中断向量,就可以使用此中断唤醒停机模式。
        在开发板上面是将实体按键K2对应的引脚设置为中断方式触发。按下此按键会将系统从停机模式唤醒。

31.1.3 STM32F103使用停机模式注意事项


        使用停机模式注意以下两个问题:
    (1)进入停机模式前,一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
    (2)当一个中断或唤醒事件导致退出停机模式时,HSI RC振荡器被选为系统时钟。这个时候用户要根据需要重新配置时钟,如果使用的HSE时钟,那么要重新配置并使能HSEPLL
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-13 17:05:32 | 显示全部楼层
31.2 STM32F4xx停机模式介绍


        说明:本小节的内容含STM32F407和STM32F429,在FreeRTOS系统上面实现停机方式仅需了解这里讲解的知识基本就够用了,更多停机方式的知识请看STM32F4xx参考手册和Cortex-M4权威指南。
        在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时,用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
        STM32F4xx有三种低功耗模式:
    (1)睡眠模式(Cortex™-M4内核停止,所有外设包括Cortex-M4核心的外设,如NVIC、系统滴答定时器Systick等仍在运行)
    (2)停机模式(所有的时钟都已停止)
    (3)待机模式(1.2V电源关闭)
        本章节我们主要讲解停机模式,停机模式基于Cortex™-M4F深度睡眠模式与外设时钟门控。调压器既可以配置为正常模式,也可以配置为低功耗模式。在停止模式下,1.2 V域中的所有时钟都会停止, PLL、 HSI和HSE RC振荡器也被禁止。内部SRAM和寄存器内容将保留。在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
        在实际的停机模式编程时需要清楚哪些问题呢? 请继续往下看。

31.2.1 STM32Fxx如何进入停机模式


        在FreeRTOS系统中,让STM32进入停机模式比较容易,调用固件库函数PWR_EnterSTOPMode即可,不过要注意:为了进入停机模式,所有EXTI线挂起位(在挂起寄存器(EXTI_PR)中)、RTC闹钟(闹钟 A和闹钟B)、RTC唤醒、RTC入侵和RTC时间戳标志必须复位,否则停机模式的进入流程将会被跳过,程序继续运行。

31.2.2 STM32F4xx如何退出停机模式


        由于我们是采用指令WFI指令进入停机模式,那么设置任一外部中断线EXTI为中断模式并且在NVIC中必须使能相应的外部中断向量,就可以使用此中断唤醒停机模式。
        在开发板上面是将实体按键K2对应的引脚设置为中断方式触发,按下此按键会将系统从停机模式唤醒。

31.2.3 STM32F4xx使用停机模式注意事项


        使用停机模式注意以下两个问题:
    (1)进入停机模式前,一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
    (2)当一个中断或唤醒事件导致退出停机模式时,HSI RC振荡器被选为系统时钟。这个时候用户要根据需要重新配置时钟,如果使用的HSE时钟,那么要重新配置并使能HSEPLL
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-13 17:07:22 | 显示全部楼层
31.3 如何有效降低停机模式下的功耗


        设计低功耗主要从以下几方面着手:
1、注意I/O的状态。因为在停机状态下,所有的I/O引脚都保持它们在运行模式时的状态。
    (1)如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
    (2)如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
2、注意I/O和外设IC的连接。
3、测试低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-13 17:14:49 | 显示全部楼层
31.4 实验例程说明



31.4.1 STM32F103开发板实验


配套例子:
        V4-337_FreeRTOS实验_低功耗(停机模式)
实验目的:
        1.     学习FreeRTOS的低功耗(停机模式)。
        2.     通过函数DBGMCU_Config(DBGMCU_STOP,ENABLE);保证停机模式下调试器正常连接使用。
实验内容:
        1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
        2.     K2按键按下将系统从停机模式模式恢复,通过PA0引脚的EXTI中断唤醒。
        3.     K3按键按下让系统进入停机模式。
        4.     关于低功耗的停机模式说明:
                     (1)  停机模式是在Cortex-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停机模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止,PLL、HSI和HSE的RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
                     (2)  在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                     (3)  一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
                     (4)  当一个中断或唤醒事件导致退出停机模式时, HSI RC振荡器被选为系统时钟。
                     (5)  退出低功耗的停机模式后,需要重新配置使用HSE。
        5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
        6.     设计低功耗主要从以下几方面着手:
                    (1)  用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。可以使用的低功耗方式有睡眠模式,待机模式,停机模式。
                    (2)  选择了低功耗方式后就是关闭可以关闭的外设时钟。
                    (3)  降低系统主频。
                    (4)  注意I/O的状态。
                              如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
                              如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
                                    a.     在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                                    b.    在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                                    c.     在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
                                       c-01:复位引脚(始终有效)。
                                       c-02:当被设置为防侵入或校准输出时的TAMPER引脚。
                                       c-03:被使能的唤醒引脚。
                    (5)  注意I/O和外设IC的连接。
                    (6)  测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
FreeRTOS的配置:
      FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. #endif
  6. #define configUSE_PREEMPTION         1
  7. #define configUSE_IDLE_HOOK          0
  8. #define configUSE_TICK_HOOK          0
  9. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 72000000 )  
  10. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  11. #define configMAX_PRIORITIES         ( 5 )
  12. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  13. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  14. #define configMAX_TASK_NAME_LEN      ( 16 )
  15. #define configUSE_TRACE_FACILITY      1
  16. #define configUSE_16_BIT_TICKS       0
  17. #define configIDLE_SHOULD_YIELD      1
  18. /* Run time and task stats gathering related definitions. */
  19. #define configGENERATE_RUN_TIME_STATS                1
  20. #define configUSE_STATS_FORMATTING_FUNCTIONS         1
  21. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)
  22. #define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks
  23. //#define portALT_GET_RUN_TIME_COUNTER_VALUE           1
  24. /* Co-routine definitions. */
  25. #define configUSE_CO_ROUTINES            0
  26. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  27. /* Set the following definitions to 1 to include the API function, or zero
  28. to exclude the API function. */
  29. #define INCLUDE_vTaskPrioritySet          1
  30. #define INCLUDE_uxTaskPriorityGet         1
  31. #define INCLUDE_vTaskDelete               1
  32. #define INCLUDE_vTaskCleanUpResources      0
  33. #define INCLUDE_vTaskSuspend              1
  34. #define INCLUDE_vTaskDelayUntil           1
  35. #define INCLUDE_vTaskDelay                1
  36. /* Cortex-M specific definitions. */
  37. #ifdef __NVIC_PRIO_BITS
  38.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  39.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  40. #else
  41.      #define configPRIO_BITS              4        /* 15 priority levels */
  42. #endif
  43. /* The lowest interrupt priority that can be used in a call to a "set priority"
  44. function. */
  45. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  46. /* The highest interrupt priority that can be used by any interrupt service
  47. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  48. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  49. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  50. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
         使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 72000000 )   
         系统主频72MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
        系统时钟节拍1KHz,即1ms。
4、#define configMAX_PRIORITIES          ( 5 )
        定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
       定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
        定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
      更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
31.1.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
      #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
      #definetskREADY_CHAR           ( 'R' ) 任务就绪
      #definetskDELETED_CHAR           ( 'D' )  任务删除
      #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
程序设计:
任务栈大小分配:
      vTaskUserIF任务   :2048字节
      vTaskLED任务     :2048字节
      vTaskMsgPro任务 :2048字节
      vTaskStart任务    :2048字节
      任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
      #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 17 * 1024 ) )
系统栈大小分配:
31.2.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.    
  25.      /* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项
  26.            目中不要使用,因为这个功能比较影响系统实时性。
  27.         2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。
  28.      */
  29.      vSetupSysInfoTest();
  30.    
  31.      /* 创建任务 */
  32.      AppTaskCreate();
  33.    
  34.     /* 启动调度,开始执行任务 */
  35.     vTaskStartScheduler();
  36.      /*
  37.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  38.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  39.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  40.      */
  41.      while(1);
  42. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
  5. *             全局变量。
  6. *    形    参: 无
  7. *    返 回 值: 无
  8. *********************************************************************************************************
  9. */
  10. void bsp_Init(void)
  11. {
  12.      /*
  13.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  14.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  15.          系统时钟缺省配置为72MHz,如果需要更改,可以修改 system_stm32f10x.c 文件
  16.      */
  17.      /* 保证停机模式下调试器继续可以连接使用 */
  18.      DBGMCU_Config(DBGMCU_STOP, ENABLE);
  19.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  20.      bsp_InitUart();    /* 初始化串口 */
  21.      bsp_InitLed();     /* 初始LED指示灯端口 */
  22.      bsp_InitKey();     /* 初始化按键 */
  23. }
复制代码
FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,              /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码
四个FreeRTOS任务的实现
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.      uint8_t pcWriteBuffer[500];
  14.    
  15.    
  16.     while(1)
  17.     {
  18.          ucKeyCode = bsp_GetKey();
  19.         
  20.          if (ucKeyCode != KEY_NONE)
  21.          {
  22.               switch (ucKeyCode)
  23.               {
  24.                    /* K1键按下 打印任务执行情况 */
  25.                    case KEY_DOWN_K1:         
  26.                        printf("=================================================\\r\\n");
  27.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  28.                        vTaskList((char *)&pcWriteBuffer);
  29.                        printf("%s\\r\\n", pcWriteBuffer);
  30.                   
  31.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  32.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  33.                        printf("%s\\r\\n", pcWriteBuffer);
  34.                        break;
  35.                   
  36.                    /* K3键按下 进入到停机模式 */
  37.                    case KEY_DOWN_K3:         
  38.                        printf("K3按键按下,系统进入待机模式,按K2按键将唤醒\\r\\n");
  39.                        /*
  40.                          1. 停止模式是在Cortex-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电
  41. 压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止, PLL、
  42. HSI和HSE的RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来。
  43.                          2. 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
  44.                          3. 一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
  45.                        */
  46.                        SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  /* 关闭滴答定时器 */
  47.                        PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);                 
  48.                        portENTER_CRITICAL();
  49.                      
  50.                        /*
  51.                          1、当一个中断或唤醒事件导致退出停止模式时, HSI RC振荡器被选为系统时钟。
  52.                          2、退出低功耗的停机模式后,需要重新配置使用HSE。     
  53.                        */
  54.                        RCC_HSEConfig(RCC_HSE_ON);
  55.                        while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET){}
  56.                        RCC_PLLCmd(ENABLE);
  57.                        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}
  58.                        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  59.                            
  60.                        while (RCC_GetSYSCLKSource() != 0x08){}
  61.                        SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 使能滴答定时器 */
  62.                        portEXIT_CRITICAL();
  63.                        break;
  64.                   
  65.                    /* 其他的键值不处理 */
  66.                    default:                    
  67.                        break;
  68.               }
  69.          }
  70.         
  71.          vTaskDelay(20);
  72.      }
  73. }
  74. /*
  75. *********************************************************************************************************
  76. *    函 数 名: vTaskLED
  77. *    功能说明: LED闪烁
  78. *    形    参: pvParameters 是在创建该任务时传递的形参
  79. *    返 回 值: 无
  80. *   优 先 级: 2
  81. *********************************************************************************************************
  82. */
  83. static void vTaskLED(void *pvParameters)
  84. {
  85.      TickType_t xLastWakeTime;
  86.      const TickType_t xFrequency = 500;
  87.      /* 获取当前的系统时间 */
  88.     xLastWakeTime = xTaskGetTickCount();
  89.    
  90.     while(1)
  91.     {
  92.          bsp_LedToggle(2);
  93.          bsp_LedToggle(3);
  94.         
  95.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  96.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  97.     }
  98. }
  99. /*
  100. *********************************************************************************************************
  101. *    函 数 名: vTaskMsgPro
  102. *    功能说明: 消息处理,这里用作LED闪烁
  103. *    形    参: pvParameters 是在创建该任务时传递的形参
  104. *    返 回 值: 无
  105. *   优 先 级: 3
  106. *********************************************************************************************************
  107. */
  108. static void vTaskMsgPro(void *pvParameters)
  109. {
  110.      TickType_t xLastWakeTime;
  111.      const TickType_t xFrequency = 1000;
  112.      /* 获取当前的系统时间 */
  113.     xLastWakeTime = xTaskGetTickCount();
  114.    
  115.     while(1)
  116.     {
  117.          bsp_LedToggle(1);
  118.          bsp_LedToggle(4);
  119.         
  120.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  121.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  122.     }
  123. }
  124. /*
  125. *********************************************************************************************************
  126. *    函 数 名: vTaskStart
  127. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  128. *    形    参: pvParameters 是在创建该任务时传递的形参
  129. *    返 回 值: 无
  130. *   优 先 级: 4
  131. *********************************************************************************************************
  132. */
  133. static void vTaskStart(void *pvParameters)
  134. {
  135.     while(1)
  136.     {
  137.          /* 按键扫描 */
  138.          bsp_KeyScan();
  139.         vTaskDelay(10);
  140.     }
  141. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-13 17:22:48 | 显示全部楼层
31.4.2 STM32F407开发板实验


配套例子:
    V5-337_FreeRTOS实验_低功耗(停机模式)
实验目的:
    1.     学习FreeRTOS的低功耗(停机模式)。
    2.     通过函数DBGMCU_Config(DBGMCU_STOP,ENABLE);保证停机模式下调试器正常连接使用。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2按键按下将系统从停机模式模式恢复,通过PA0引脚的EXTI中断唤醒。
    3.     K3按键按下让系统进入停机模式。
    4.     关于低功耗的停机模式说明:
        (1)  停机模式是在Cortex-M4F的深睡眠模式基础上结合了外设的时钟控制机制,在停机模式下电压调节器可运行在正常或低功耗模式。此时在1.2V供电区域的的所有时钟都被停止,PLL、HSI和HSE的RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
        (2)  在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
        (3)  一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
        (4)  当一个中断或唤醒事件导致退出停机模式时, HSI RC振荡器被选为系统时钟。
        (5)  退出低功耗的停机模式后,需要重新配置使用HSE。
    5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    6.     设计低功耗主要从以下几方面着手:
         (1)  用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。可以使用的低功耗方式有睡眠模式,待机模式,停机模式。
        (2)  选择了低功耗方式后就是关闭可以关闭的外设时钟。
        (3)  降低系统主频。
        (4)  注意I/O的状态。
            如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
            如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
                a.     在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                b.    在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                c.     在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
                               01:复位引脚(始终有效)
                               02:当被设置为防侵入或校准输出时的TAMPER引脚。
                               03:被使能的唤醒引脚。
        (5)  注意I/O和外设IC的连接。
        (6)  测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
FreeRTOS的配置:
    FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. /* Ensure stdint is only used by the compiler, and not the assembler. */
  6. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  7. #include <stdint.h>
  8. extern volatile uint32_t ulHighFrequencyTimerTicks;
  9. #endif
  10. #define configUSE_PREEMPTION         1
  11. #define configUSE_IDLE_HOOK          0
  12. #define configUSE_TICK_HOOK          0
  13. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 )
  14. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  15. #define configMAX_PRIORITIES         ( 5 )
  16. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  17. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
  18. #define configMAX_TASK_NAME_LEN      ( 16 )
  19. #define configUSE_TRACE_FACILITY      1
  20. #define configUSE_16_BIT_TICKS       0
  21. #define configIDLE_SHOULD_YIELD      1
  22. /* Run time and task stats gathering related definitions. */
  23. #define configGENERATE_RUN_TIME_STATS                1
  24. #define configUSE_STATS_FORMATTING_FUNCTIONS         1
  25. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)
  26. #define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks
  27. //#define portALT_GET_RUN_TIME_COUNTER_VALUE           1
  28. /* Co-routine definitions. */
  29. #define configUSE_CO_ROUTINES             0
  30. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  31. /* Set the following definitions to 1 to include the API function, or zero
  32. to exclude the API function. */
  33. #define INCLUDE_vTaskPrioritySet     1
  34. #define INCLUDE_uxTaskPriorityGet         1
  35. #define INCLUDE_vTaskDelete               1
  36. #define INCLUDE_vTaskCleanUpResources 0
  37. #define INCLUDE_vTaskSuspend              1
  38. #define INCLUDE_vTaskDelayUntil           1
  39. #define INCLUDE_vTaskDelay                1
  40. /* Cortex-M specific definitions. */
  41. #ifdef __NVIC_PRIO_BITS
  42.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  43.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  44. #else
  45.      #define configPRIO_BITS              4        /* 15 priority levels */
  46. #endif
  47. /* The lowest interrupt priority that can be used in a call to a "set priority"
  48. function. */
  49. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  50. /* The highest interrupt priority that can be used by any interrupt service
  51. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  52. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  53. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  54. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
         使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )
        系统主频168MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
         系统时钟节拍1KHz,即1ms。
4、#define configMAX_PRIORITIES          ( 5 )
         定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
       定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
        定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
      更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
31.3.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
      #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
      #definetskREADY_CHAR           ( 'R' ) 任务就绪
      #definetskDELETED_CHAR           ( 'D' )  任务删除
      #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
程序设计:
任务栈大小分配:
      vTaskUserIF任务   :2048字节
      vTaskLED任务     :2048字节
      vTaskMsgPro任务 :2048字节
      vTaskStart任务    :2048字节
      任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
      #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
31.4.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.    
  25.      /* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项
  26.            目中不要使用,因为这个功能比较影响系统实时性。
  27.         2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。
  28.      */
  29.      vSetupSysInfoTest();
  30.    
  31.      /* 创建任务 */
  32.      AppTaskCreate();
  33.    
  34.     /* 启动调度,开始执行任务 */
  35.     vTaskStartScheduler();
  36.      /*
  37.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  38.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  39.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  40.      */
  41.      while(1);
  42. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 保证停机模式下调试器继续可以连接使用 */
  17.      DBGMCU_Config(DBGMCU_STOP, ENABLE);
  18.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  19.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  20.      bsp_InitUart();    /* 初始化串口 */
  21.      bsp_InitKey();     /* 初始化按键变量 */
  22.      bsp_InitLed();     /* 初始LED指示灯端口 */
  23. }
复制代码
FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,              /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码
四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.      uint8_t pcWriteBuffer[500];
  14.    
  15.    
  16.     while(1)
  17.     {
  18.          ucKeyCode = bsp_GetKey();
  19.         
  20.          if (ucKeyCode != KEY_NONE)
  21.          {
  22.               switch (ucKeyCode)
  23.               {
  24.                    /* K1键按下 打印任务执行情况 */
  25.                    case KEY_DOWN_K1:         
  26.                        printf("=================================================\\r\\n");
  27.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  28.                        vTaskList((char *)&pcWriteBuffer);
  29.                        printf("%s\\r\\n", pcWriteBuffer);
  30.                   
  31.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  32.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  33.                        printf("%s\\r\\n", pcWriteBuffer);
  34.                        break;
  35.                   
  36.                    /* K3键按下 进入到停机模式 */
  37.                    case KEY_DOWN_K3:         
  38.                        printf("K3按键按下,系统进入待机模式,按K2按键将唤醒\\r\\n");
  39.                        /*
  40.                          1. 停止模式是在Cortex-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电
  41. 压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止, PLL、
  42. HSI和HSE的RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来。
  43.                          2. 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
  44.                          3. 一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
  45.                        */
  46.                        SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  /* 关闭滴答定时器 */
  47.                        PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);                 
  48.                        portENTER_CRITICAL();
  49.                      
  50.                        /*
  51.                          1、当一个中断或唤醒事件导致退出停止模式时, HSI RC振荡器被选为系统时钟。
  52.                          2、退出低功耗的停机模式后,需要重新配置使用HSE。     
  53.                        */
  54.                        RCC_HSEConfig(RCC_HSE_ON);
  55.                        while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET){}
  56.                        RCC_PLLCmd(ENABLE);
  57.                        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}
  58.                        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  59.                            
  60.                        while (RCC_GetSYSCLKSource() != 0x08){}
  61.                        SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 使能滴答定时器 */
  62.                        portEXIT_CRITICAL();
  63.                        break;
  64.                   
  65.                    /* 其他的键值不处理 */
  66.                    default:                    
  67.                        break;
  68.               }
  69.          }
  70.         
  71.          vTaskDelay(20);
  72.      }
  73. }
  74. /*
  75. *********************************************************************************************************
  76. *    函 数 名: vTaskLED
  77. *    功能说明: LED闪烁
  78. *    形    参: pvParameters 是在创建该任务时传递的形参
  79. *    返 回 值: 无
  80. *   优 先 级: 2
  81. *********************************************************************************************************
  82. */
  83. static void vTaskLED(void *pvParameters)
  84. {
  85.      TickType_t xLastWakeTime;
  86.      const TickType_t xFrequency = 500;
  87.      /* 获取当前的系统时间 */
  88.     xLastWakeTime = xTaskGetTickCount();
  89.    
  90.     while(1)
  91.     {
  92.          bsp_LedToggle(2);
  93.          bsp_LedToggle(3);
  94.         
  95.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  96.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  97.     }
  98. }
  99. /*
  100. *********************************************************************************************************
  101. *    函 数 名: vTaskMsgPro
  102. *    功能说明: 消息处理,这里用作LED闪烁
  103. *    形    参: pvParameters 是在创建该任务时传递的形参
  104. *    返 回 值: 无
  105. *   优 先 级: 3
  106. *********************************************************************************************************
  107. */
  108. static void vTaskMsgPro(void *pvParameters)
  109. {
  110.      TickType_t xLastWakeTime;
  111.      const TickType_t xFrequency = 1000;
  112.      /* 获取当前的系统时间 */
  113.     xLastWakeTime = xTaskGetTickCount();
  114.    
  115.     while(1)
  116.     {
  117.          bsp_LedToggle(1);
  118.          bsp_LedToggle(4);
  119.         
  120.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  121.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  122.     }
  123. }
  124. /*
  125. *********************************************************************************************************
  126. *    函 数 名: vTaskStart
  127. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  128. *    形    参: pvParameters 是在创建该任务时传递的形参
  129. *    返 回 值: 无
  130. *   优 先 级: 4
  131. *********************************************************************************************************
  132. */
  133. static void vTaskStart(void *pvParameters)
  134. {
  135.     while(1)
  136.     {
  137.          /* 按键扫描 */
  138.          bsp_KeyScan();
  139.         vTaskDelay(10);
  140.     }
  141. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-13 17:28:34 | 显示全部楼层
31.4.3 STM32F429开发板实验


配套例子:
    V6-337_FreeRTOS实验_低功耗(停机模式)
实验目的:
    1.     学习FreeRTOS的低功耗(停机模式)。
    2.     通过函数DBGMCU_Config(DBGMCU_STOP,ENABLE);保证停机模式下调试器正常连接使用。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2按键按下将系统从停机模式模式恢复,通过PA0引脚的EXTI中断唤醒。
    3.     K3按键按下让系统进入停机模式。
    4.     关于低功耗的停机模式说明:
        (1)  停机模式是在Cortex-M4F的深睡眠模式基础上结合了外设的时钟控制机制,在停机模式下电压调节器可运行在正常或低功耗模式。此时在1.2V供电区域的的所有时钟都被停止,PLL、HSI和HSE的RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
        (2)  在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
        (3)  一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
        (4)  当一个中断或唤醒事件导致退出停机模式时, HSI RC振荡器被选为系统时钟。
        (5)  退出低功耗的停机模式后,需要重新配置使用HSE。
    5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    6.     设计低功耗主要从以下几方面着手:
        (1)  用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。可以使用的低功耗方式有睡眠模式,待机模式,停机模式。
        (2)  选择了低功耗方式后就是关闭可以关闭的外设时钟。
        (3)  降低系统主频。
        (4)  注意I/O的状态。
            如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
            如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
                  a.     在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                  b.    在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
                  c.     在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
                          01:复位引脚(始终有效)
                          02:当被设置为防侵入或校准输出时的TAMPER引脚。
                          03:被使能的唤醒引脚。
(5)  注意I/O和外设IC的连接。
(6)  测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
FreeRTOS的配置:
     FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. #endif
  6. #define configUSE_PREEMPTION         1
  7. #define configUSE_IDLE_HOOK          0
  8. #define configUSE_TICK_HOOK          0
  9. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 )
  10. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  11. #define configMAX_PRIORITIES         ( 5 )
  12. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  13. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
  14. #define configMAX_TASK_NAME_LEN      ( 16 )
  15. #define configUSE_TRACE_FACILITY      1
  16. #define configUSE_16_BIT_TICKS       0
  17. #define configIDLE_SHOULD_YIELD      1
  18. /* Run time and task stats gathering related definitions. */
  19. #define configGENERATE_RUN_TIME_STATS                1
  20. #define configUSE_STATS_FORMATTING_FUNCTIONS         1
  21. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)
  22. #define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks
  23. //#define portALT_GET_RUN_TIME_COUNTER_VALUE           1
  24. /* Co-routine definitions. */
  25. #define configUSE_CO_ROUTINES            0
  26. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  27. /* Set the following definitions to 1 to include the API function, or zero
  28. to exclude the API function. */
  29. #define INCLUDE_vTaskPrioritySet          1
  30. #define INCLUDE_uxTaskPriorityGet         1
  31. #define INCLUDE_vTaskDelete               1
  32. #define INCLUDE_vTaskCleanUpResources      0
  33. #define INCLUDE_vTaskSuspend              1
  34. #define INCLUDE_vTaskDelayUntil           1
  35. #define INCLUDE_vTaskDelay                1
  36. /* Cortex-M specific definitions. */
  37. #ifdef __NVIC_PRIO_BITS
  38.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  39.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  40. #else
  41.      #define configPRIO_BITS              4        /* 15 priority levels */
  42. #endif
  43. /* The lowest interrupt priority that can be used in a call to a "set priority"
  44. function. */
  45. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  46. /* The highest interrupt priority that can be used by any interrupt service
  47. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  48. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  49. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  50. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
        使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )
         系统主频168MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
        系统时钟节拍1KHz,即1ms。
4、#define configMAX_PRIORITIES          ( 5 )
        定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
        定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
        定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
    更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
31.5.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
     #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
     #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
程序设计:
任务栈大小分配:
      vTaskUserIF任务   :2048字节
      vTaskLED任务     :2048字节
      vTaskMsgPro任务 :2048字节
      vTaskStart任务    :2048字节
      任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
      #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
31.6.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.    
  25.      /* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项
  26.            目中不要使用,因为这个功能比较影响系统实时性。
  27.         2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。
  28.      */
  29.      vSetupSysInfoTest();
  30.    
  31.      /* 创建任务 */
  32.      AppTaskCreate();
  33.    
  34.     /* 启动调度,开始执行任务 */
  35.     vTaskStartScheduler();
  36.      /*
  37.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  38.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  39.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  40.      */
  41.      while(1);
  42. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 保证停机模式下调试器继续可以连接使用 */
  17.      DBGMCU_Config(DBGMCU_STOP, ENABLE);
  18.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  19.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  20.    
  21.      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
  22.      bsp_InitUart();    /* 初始化串口 */
  23.      bsp_InitKey();     /* 初始化按键变量 */
  24.      bsp_InitExtIO();   /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
  25.      bsp_InitLed();     /* 初始LED指示灯端口 */
  26. }
复制代码
FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,              /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码
四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.      uint8_t pcWriteBuffer[500];
  14.    
  15.    
  16.     while(1)
  17.     {
  18.          ucKeyCode = bsp_GetKey();
  19.         
  20.          if (ucKeyCode != KEY_NONE)
  21.          {
  22.               switch (ucKeyCode)
  23.               {
  24.                    /* K1键按下 打印任务执行情况 */
  25.                    case KEY_DOWN_K1:         
  26.                        printf("=================================================\\r\\n");
  27.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  28.                        vTaskList((char *)&pcWriteBuffer);
  29.                        printf("%s\\r\\n", pcWriteBuffer);
  30.                   
  31.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  32.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  33.                        printf("%s\\r\\n", pcWriteBuffer);
  34.                        break;
  35.                   
  36.                    /* K3键按下 进入到停机模式 */
  37.                    case KEY_DOWN_K3:         
  38.                        printf("K3按键按下,系统进入待机模式,按K2按键将唤醒\\r\\n");
  39.                        /*
  40.                          1. 停止模式是在Cortex-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电
  41. 压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止, PLL、
  42. HSI和HSE的RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来。
  43.                          2. 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
  44.                          3. 一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
  45.                        */
  46.                        SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  /* 关闭滴答定时器 */
  47.                        PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);                 
  48.                        portENTER_CRITICAL();
  49.                      
  50.                        /*
  51.                          1、当一个中断或唤醒事件导致退出停止模式时, HSI RC振荡器被选为系统时钟。
  52.                          2、退出低功耗的停机模式后,需要重新配置使用HSE。     
  53.                        */
  54.                        RCC_HSEConfig(RCC_HSE_ON);
  55.                        while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET){}
  56.                        RCC_PLLCmd(ENABLE);
  57.                        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}
  58.                        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  59.                            
  60.                        while (RCC_GetSYSCLKSource() != 0x08){}
  61.                        SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 使能滴答定时器 */
  62.                        portEXIT_CRITICAL();
  63.                        break;
  64.                   
  65.                    /* 其他的键值不处理 */
  66.                    default:                    
  67.                        break;
  68.               }
  69.          }
  70.         
  71.          vTaskDelay(20);
  72.      }
  73. }
  74. /*
  75. *********************************************************************************************************
  76. *    函 数 名: vTaskLED
  77. *    功能说明: LED闪烁
  78. *    形    参: pvParameters 是在创建该任务时传递的形参
  79. *    返 回 值: 无
  80. *   优 先 级: 2
  81. *********************************************************************************************************
  82. */
  83. static void vTaskLED(void *pvParameters)
  84. {
  85.      TickType_t xLastWakeTime;
  86.      const TickType_t xFrequency = 500;
  87.      /* 获取当前的系统时间 */
  88.     xLastWakeTime = xTaskGetTickCount();
  89.    
  90.     while(1)
  91.     {
  92.          bsp_LedToggle(2);
  93.          bsp_LedToggle(3);
  94.         
  95.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  96.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  97.     }
  98. }
  99. /*
  100. *********************************************************************************************************
  101. *    函 数 名: vTaskMsgPro
  102. *    功能说明: 消息处理,这里用作LED闪烁
  103. *    形    参: pvParameters 是在创建该任务时传递的形参
  104. *    返 回 值: 无
  105. *   优 先 级: 3
  106. *********************************************************************************************************
  107. */
  108. static void vTaskMsgPro(void *pvParameters)
  109. {
  110.      TickType_t xLastWakeTime;
  111.      const TickType_t xFrequency = 1000;
  112.      /* 获取当前的系统时间 */
  113.     xLastWakeTime = xTaskGetTickCount();
  114.    
  115.     while(1)
  116.     {
  117.          bsp_LedToggle(1);
  118.          bsp_LedToggle(4);
  119.         
  120.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  121.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  122.     }
  123. }
  124. /*
  125. *********************************************************************************************************
  126. *    函 数 名: vTaskStart
  127. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  128. *    形    参: pvParameters 是在创建该任务时传递的形参
  129. *    返 回 值: 无
  130. *   优 先 级: 4
  131. *********************************************************************************************************
  132. */
  133. static void vTaskStart(void *pvParameters)
  134. {
  135.     while(1)
  136.     {
  137.          /* 按键扫描 */
  138.          bsp_KeyScan();
  139.         vTaskDelay(10);
  140.     }
  141. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-9-13 17:29:06 | 显示全部楼层
31.5 总结

        本章节主要为大家讲解了FreeRTOS低功耗之停机模式,这里仅是提供了一种停机模式在FreeRTOS上的实现思路,有兴趣的同学也可以想一些其它的实现思路。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-1 00:46 , Processed in 0.278888 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表