硬汉嵌入式论坛

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

[RL-RTX] 【RTX操作系统教程】第22章   RTX低功耗之停机模式

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2016-1-11 15:13:31 | 显示全部楼层 |阅读模式
第22章    RTX低功耗之停机模式


     低功耗是MCU的一项非常重要的指标,本章节为大家讲解STM32F103和STM32F407的低功耗方式之停机模式在RTX操作系统上面的实现方法(RTX本身支持的tickless低功耗模式在第24章节讲解
     本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。
22.1 STM32F103停机模式介绍
22.2 STM32F407停机模式介绍
22.3 如何有效降低停机模式下的功耗
22.4 实验例程说明
22.5      总结

22.1  STM32F103停机模式介绍

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

22.1.1 STM32F103如何进入停机模式

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

22.1.2 STM32F103如何退出停机模式

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

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

     使用停机模式注意以下两个问题:
u  进入停机模式前,一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
u  当一个中断或唤醒事件导致退出停机模式时,HSI RC振荡器被选为系统时钟。这个时候用户要根据需要重新配置时钟,如果使用的HSE时钟,那么要重新配置并使能HSE和PLL。

22.2 STM32F407停机模式介绍

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

22.2.1 STM32F407如何进入停机模式

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

22.2.2 STM32F407如何退出停机模式

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

22.2.3 STM32F407使用停机模式注意事项

    使用停机模式注意以下两个问题:
u  进入停机模式前,一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
u  当一个中断或唤醒事件导致退出停机模式时,HSI RC振荡器被选为系统时钟。这个时候用户要根据需要重新配置时钟,如果使用的HSE时钟,那么要重新配置并使能HSE和PLL。

22.3 如何有效降低停机模式下的功耗

    设计低功耗主要从以下几方面着手:
u  注意I/O的状态。因为在停机状态下,所有的I/O引脚都保持它们在运行模式时的状态。
    l  如果此I/O口带上拉,请设置为高电平输出或者高阻态输入。
    l  如果此I/O口带下拉,请设置为低电平输出或者高阻态输入。
u  注意I/O和外设IC的连接。
u  测试低功耗的时候,一定不要连接调试器,更不能边调试边测电流。

22.4 实验例程说明

22.4.1 STM32F103开发板实验

配套例子:
    V4-422_RTX实验_低功耗(停机模式)
实验目的:
    1.     学习RTX实验低功耗(停机模式)。
    2.     通过函数DBGMCU_Config(DBGMCU_STOP,ENABLE);保证停机模式下调试器正常连接使用。
实验内容:
    1.K1按键按下,串口打印。
    2.K2按键按下将系统从停机模式模式恢复。
    3.K3按键按下让系统进入停机模式。
     4.各个任务实现的功能如下:
       AppTaskUserIF任务 :按键消息处理。
       AppTaskLED任务    :LED闪烁。
       AppTaskMsgPro任务 :消息处理,这里实现LED闪烁。
       AppTaskStart任务  :启动任务,也是最高优先级任务,这里实现按键扫描。
    5.关于低功耗的停机模式说明:
        (1) 停止模式是在Cortex-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止,PLLHISHSERC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
        (2) 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
        (3) 一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
        (4) 当一个中断或唤醒事件导致退出停止模式时,HSI RC振荡器被选为系统时钟。
        (5) 退出低功耗的停机模式后,需要重新配置使用HSE。
    6.实际项目中推荐采用官方的tickless模式。
设计低功耗主要从以下几个方面着手:
    1.     用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式可以使用的低功耗方式有休眠模式,待机模式,停机模式。
    2.     选择了低功耗方式后就是关闭可以关闭的外设时钟。
    3.     降低系统主频。
    4.     注意I/O的状态。
         如果此I/O口带上拉,请设置为高电平输出或者高阻态输入;
        如果此I/O口带下拉,请设置为低电平输出或者高阻态输入;
       a.在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
       b.在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
       c.在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
        ● 复位引脚(始终有效)
        ● 当被设置为防侵入或校准输出时的TAMPER引脚
        ● 被使能的唤醒引脚
    5.注意I/O和外设IC的连接。
    6.测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
RTX配置:
    RTX配置向导详情如下:
22.1.png

u  Task Configuration
l Number of concurrent running tasks
    允许创建4个任务,实际创建了如下四个任务:
                     AppTaskUserIF任务   :按键消息处理。
                    AppTaskLED任务     :LED闪烁。
                    AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                    AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
l Number of tasks with user-provided stack
    创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
22.2.png

程序设计:
u  任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
      将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
u  系统栈大小分配:
22.3.png

u  外设初始化:
     注意新加的函数初始化函数DBGMCU_Config(DBGMCU_STOP, ENABLE);保证停机模式下调试器正常连接使用。
  1. /*
  2. /*
  3. *********************************************************************************************************
  4. *    函 数 名: bsp_Init
  5. *    功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
  6. *             全局变量。
  7. *    形    参: 无
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. void bsp_Init(void)
  12. {
  13.      /* 保证停机模式下调试器继续可以连接使用 */
  14.      DBGMCU_Config(DBGMCU_STOP, ENABLE);
  15.    
  16.      /* 优先级分组设置为4, 优先配置好NVIC */
  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  18.      bsp_InitUart();    /* 初始化串口 */
  19.      bsp_InitLed();         /* 初始LED指示灯端口 */
  20.      bsp_InitKey();         /* 初始化按键 */
  21. }
复制代码
u  RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码
u  RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码
u  K2按键用来将系统从停机模式唤醒,配置如下(在文件bsp_key.c文件):
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: TouchInterrupt_Configuration
  4. *    功能说明: 停机模式唤醒按键
  5. *    形    参:无
  6. *    返 回 值: 无              
  7. *********************************************************************************************************
  8. */
  9. static void bsp_InitKeyStopMODE(void)
  10. {
  11.      GPIO_InitTypeDef  GPIO_InitStructure;
  12.      EXTI_InitTypeDef  EXTI_InitStructure;
  13.      NVIC_InitTypeDef  NVIC_InitStructure;
  14.      RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
  15.      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
  16.      /* 配置引脚 */
  17.      GPIO_InitStructure.GPIO_Pin = GPIO_PIN_K2;
  18.      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  19.      GPIO_Init(GPIO_PORT_K2, &GPIO_InitStructure);
  20.      GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
  21.      /* 配置外部中断事件 */
  22.      EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  23.      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  24.      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  25.      EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  26.      EXTI_Init(&EXTI_InitStructure);
  27.      /* 16个抢占式优先级,0个响应式优先级 */
  28.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  29.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
  30.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  31.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  32.     NVIC_Init(&NVIC_InitStructure);
  33. }
  34. /* 中断服务程序,在文件stm32f10x_it.c里面实现*/
  35. /*
  36. *********************************************************************************************************
  37. *    函 数 名: EXTI0_IRQHandler
  38. *    功能说明: 外部中断服务程序
  39. *    形    参: 无
  40. *    返 回 值: 无
  41. *********************************************************************************************************
  42. */
  43. void EXTI0_IRQHandler (void)
  44. {
  45.      if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  46.      {   
  47.          EXTI_ClearITPendingBit(EXTI_Line0); /* 清除中断标志位 */
  48.      }         
  49. }
复制代码
u  四个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t ucKeyCode;
  13.     while(1)
  14.     {
  15.          ucKeyCode = bsp_GetKey();
  16.         
  17.          if (ucKeyCode != KEY_NONE)
  18.          {
  19.               switch (ucKeyCode)
  20.               {
  21.                    /* K1键按下,打印调试说明 */
  22.                    case KEY_DOWN_K1:
  23.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  24.                        break;  
  25.                    /* K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro */
  26.                    case KEY_DOWN_K2:
  27.                        printf("K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro\r\n");
  28.                        os_sem_send (&semaphore);
  29.                        break;
  30.                    /* 其他的键值不处理 */
  31.                    default:                    
  32.                        break;
  33.               }
  34.          }
  35.         
  36.          os_dly_wait(20);
  37.      }
  38. }
  39. /*
  40. *********************************************************************************************************
  41. *    函 数 名: AppTaskLED
  42. *    功能说明: LED闪烁。
  43. *    形    参: 无
  44. *    返 回 值: 无
  45. *   优 先 级: 2
  46. *********************************************************************************************************
  47. */
  48. __task void AppTaskLED(void)
  49. {
  50.      const uint16_t usFrequency = 200; /* 延迟周期 */
  51.    
  52.      /* 设置延迟周期 */
  53.      os_itv_set(usFrequency);
  54.    
  55.     while(1)
  56.     {
  57.          bsp_LedToggle(2);
  58.          bsp_LedToggle(3);
  59.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  60.          os_itv_wait();
  61.     }
  62. }
  63. /*
  64. *********************************************************************************************************
  65. *    函 数 名: AppTaskMsgPro
  66. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的信号量同步信号
  67. *    形    参: 无
  68. *    返 回 值: 无
  69. *   优 先 级: 3
  70. *********************************************************************************************************
  71. */
  72. __task void AppTaskMsgPro(void)
  73. {
  74.      OS_RESULT xResult;
  75.      const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
  76.    
  77.     while(1)
  78.     {
  79.          xResult = os_sem_wait (&semaphore, usMaxBlockTime);
  80.         
  81.          switch (xResult)
  82.          {
  83.               /* 无需等待接受到信号量同步信号 */
  84.               case OS_R_OK:
  85.                    printf("无需等待接受到信号量同步信号\r\n");
  86.                    break;  
  87.               /* 信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号 */
  88.               case OS_R_SEM:
  89.                    printf("信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号\r\n");
  90.                    break;
  91.               /* 超时 */
  92.               case OS_R_TMO:
  93.                    bsp_LedToggle(1);
  94.                    bsp_LedToggle(4);
  95.                    break;
  96.             
  97.               /* 其他值不处理 */
  98.               default:                    
  99.                    break;
  100.          }   
  101.     }
  102. }
  103. /*
  104. *********************************************************************************************************
  105. *    函 数 名: AppTaskStart
  106. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
  107. *    形    参: 无
  108. *    返 回 值: 无
  109. *   优 先 级: 4
  110. *********************************************************************************************************
  111. */
  112. __task void AppTaskStart(void)
  113. {
  114.      /* 创建任务 */
  115.      AppTaskCreate();
  116.    
  117.      /* 创建任务通信机制 */
  118.      AppObjCreate();
  119.    
  120.     while(1)
  121.     {
  122.          /* 按键扫描 */
  123.          bsp_KeyScan();
  124.         os_dly_wait(10);
  125.     }
  126. }
复制代码

22.4.2 STM32F407开发板实验

配套例子:
    V5-422_RTX实验_低功耗(停机模式)
实验目的:
    1.     学习RTX实验低功耗(停机模式)。
     2.     通过函数DBGMCU_Config(DBGMCU_STOP,ENABLE);保证停机模式下调试器正常连接使用。
实验内容:
    1.K1按键按下,串口打印。
    2.K2按键按下将系统从停机模式模式恢复。
     3.K3按键按下让系统进入停机模式。
     4.各个任务实现的功能如下:
      AppTaskUserIF任务 :按键消息处理。
      AppTaskLED任务    :LED闪烁。
      AppTaskMsgPro任务 :消息处理,这里实现LED闪烁。
      AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
       5.关于低功耗的停机模式说明:
       (1) 停止模式是在Cortex-M4F的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.2V供电区域的的所有时钟都被停止,PLLHSIHSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
       (2) 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
       (3) 一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
       (4) 当一个中断或唤醒事件导致退出停止模式时,HSIRC振荡器被选为系统时钟。
        (5) 退出低功耗的停机模式后,需要重新配置使用HSE。
     6.实际项目中推荐采用官方的tickless模式。
设计低功耗主要从以下几个方面着手:
    1.     用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式可以使用的低功耗方式有休眠模式,待机模式,停机模式。
    2.     选择了低功耗方式后就是关闭可以关闭的外设时钟。
    3.     降低系统主频。
    4.     注意I/O的状态。
       如果此I/O口带上拉,请设置为高电平输出或者高阻态输入;
      如果此I/O口带下拉,请设置为低电平输出或者高阻态输入;
        a.在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
        b.在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
        c.在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
       ● 复位引脚(仍可用)。
       ● RTC_AF1引脚 (PC13)(如果针对入侵、时间戳、RTC闹钟输出或RTC时钟校准输出进行了配置)。
       ● WKUP引脚 (PA0)(如果使能)。
    5.注意I/O和外设IC的连接。
    6.测低功耗的时候,一定不要连接调试器,更不能边调试边测电流。
RTX配置:
     RTX配置向导详情如下:
22.4.png

u  Task Configuration
l Number of concurrent running tasks
     允许创建4个任务,实际创建了如下四个任务:
                    AppTaskUserIF任务   :按键消息处理。
                    AppTaskLED任务     :LED闪烁。
                    AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                    AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
l  Number of tasks with user-provided stack
    创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
22.5.png

程序设计:
u  任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
     staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
     staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
      将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
u  系统栈大小分配:
22.6.png

u  外设初始化:
    注意新加的函数初始化函数DBGMCU_Config(DBGMCU_STOP, ENABLE);保证停机模式下调试器正常连接使用。
  1. /*
  2. /*
  3. *********************************************************************************************************
  4. *    函 数 名: bsp_Init
  5. *    功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
  6. *             全局变量。
  7. *    形    参: 无
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. void bsp_Init(void)
  12. {
  13.      /* 保证停机模式下调试器继续可以连接使用 */
  14.      DBGMCU_Config(DBGMCU_STOP, ENABLE);
  15.    
  16.      /* 优先级分组设置为4, 优先配置好NVIC */
  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  18.    
  19.      bsp_InitUart();    /* 初始化串口 */
  20.      bsp_InitKey();         /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
  21.      /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
  22.      bsp_InitLed();         /* 初始LED指示灯端口 */
  23. }
复制代码
u  RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码
u  RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码
u  K2按键用来将系统从停机模式唤醒,配置如下(在文件bsp_key.c文件):
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: TouchInterrupt_Configuration
  4. *    功能说明: 停机模式唤醒按键
  5. *    形    参:无
  6. *    返 回 值: 无              
  7. *********************************************************************************************************
  8. */
  9. static void bsp_InitKeyStopMODE(void)
  10. {
  11.      GPIO_InitTypeDef  GPIO_InitStructure;
  12.      EXTI_InitTypeDef   EXTI_InitStructure;
  13.      NVIC_InitTypeDef   NVIC_InitStructure;
  14.    
  15.      /* 使能SYSCFG时钟 */
  16.      RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  17.      RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
  18.      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  19.    
  20.      /* 配置按键K2的GPIO为浮动输入模式(实际上CPU复位后就是输入状态) */
  21.      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;       /* 设为输入口 */
  22.      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;     /* 设为推挽模式 */
  23.      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   /* 无需上下拉电阻 */
  24.      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  /* IO口最大速度 */
  25.      GPIO_InitStructure.GPIO_Pin = GPIO_PIN_K2;
  26.      GPIO_Init(GPIO_PORT_K2, &GPIO_InitStructure);
  27.    
  28.      /* 连接 EXTI Line13 到 PC13 引脚 */
  29.      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);
  30.    
  31.      /* 配置 EXTI LineXXX */
  32.      EXTI_InitStructure.EXTI_Line = EXTI_Line13;
  33.      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  34.      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  35.      EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  36.      EXTI_Init(&EXTI_InitStructure);
  37.      /* 16个抢占式优先级,0个响应式优先级 */
  38.      NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
  39.      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
  40.      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  41.      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  42.      NVIC_Init(&NVIC_InitStructure);
  43. }
  44. /* 中断服务程序,在文件stm32f4xx_it.c里面实现*/
  45. /*
  46. *********************************************************************************************************
  47. *    函 数 名: EXTI15_10_IRQHandler
  48. *    功能说明: 外部中断服务程序
  49. *    形    参: 无
  50. *    返 回 值: 无
  51. *********************************************************************************************************
  52. */
  53. void EXTI15_10_IRQHandler(void)
  54. {
  55.      if(EXTI_GetITStatus(EXTI_Line13) != RESET)
  56.      {   
  57.          EXTI_ClearITPendingBit(EXTI_Line13); /* 清除中断标志位 */
  58.      }         
  59. }
复制代码
u  四个RTX任务的实现:
  1. /*
  2. /*
  3. *********************************************************************************************************
  4. *    函 数 名: AppTaskUserIF
  5. *    功能说明: 按键消息处理     
  6. *    形    参: 无
  7. *    返 回 值: 无
  8. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  9. *********************************************************************************************************
  10. */
  11. __task void AppTaskUserIF(void)
  12. {
  13.      uint8_t ucKeyCode;
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                    /* K1键按下,打印调试说明 */
  23.                    case KEY_DOWN_K1:
  24.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  25.                        break;  
  26.                   
  27.                    /* K3键按下 进入到停机模式 */
  28.                    case KEY_DOWN_K3:         
  29.                        printf("K3按键按下,系统进入待机模式,按K2按键将唤醒\r\n");
  30.                    /*
  31.                    1. 停止模式是在Cortex-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压
  32.                     调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止, PLL、 HSI和
  33.                      HSE的RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来。
  34.                     2. 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
  35.                     3. 一定要关闭滴答定时器,实际测试发现滴答定时器中断也能唤醒停机模式。
  36.                    */
  37.                        tsk_lock ();  /* 调度锁是通过关闭滴答定时器中断实现 */
  38.                        PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);                 
  39.                      
  40.                        /*
  41.                          1、当一个中断或唤醒事件导致退出停止模式时, HSI RC振荡器被选为系统时钟。
  42.                          2、退出低功耗的停机模式后,需要重新配置使用HSE。
  43.                        */
  44.                        SystemInit();
  45.                        tsk_unlock ();
  46.                        break;
  47.                    /* 其他的键值不处理 */
  48.                    default:                    
  49.                        break;
  50.               }
  51.          }
  52.         
  53.          os_dly_wait(20);
  54.      }
  55. }
  56. /*
  57. *********************************************************************************************************
  58. *    函 数 名: AppTaskLED
  59. *    功能说明: LED闪烁。
  60. *    形    参: 无
  61. *    返 回 值: 无
  62. *   优 先 级: 2
  63. *********************************************************************************************************
  64. */
  65. __task void AppTaskLED(void)
  66. {
  67.      const uint16_t usFrequency = 200; /* 延迟周期 */
  68.    
  69.      /* 设置延迟周期 */
  70.      os_itv_set(usFrequency);
  71.    
  72.     while(1)
  73.     {
  74.          bsp_LedToggle(2);
  75.          bsp_LedToggle(3);
  76.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  77.          os_itv_wait();
  78.     }
  79. }
  80. /*
  81. *********************************************************************************************************
  82. *    函 数 名: AppTaskMsgPro
  83. *    功能说明: 消息处理,这里实现LED闪烁
  84. *    形    参: 无
  85. *    返 回 值: 无
  86. *   优 先 级: 3
  87. *********************************************************************************************************
  88. */
  89. __task void AppTaskMsgPro(void)
  90. {
  91.      const uint16_t usFrequency = 200; /* 延迟周期 */
  92.    
  93.      /* 设置延迟周期 */
  94.      os_itv_set(usFrequency);
  95.    
  96.     while(1)
  97.     {
  98.          bsp_LedToggle(1);
  99.          bsp_LedToggle(4);
  100.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  101.          os_itv_wait();
  102.     }
  103. }
  104. /*
  105. *********************************************************************************************************
  106. *    函 数 名: AppTaskStart
  107. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
  108. *    形    参: 无
  109. *    返 回 值: 无
  110. *   优 先 级: 4
  111. *********************************************************************************************************
  112. */
  113. __task void AppTaskStart(void)
  114. {
  115.      /* 创建任务 */
  116.      AppTaskCreate();
  117.    
  118.     while(1)
  119.     {
  120.          /* 按键扫描 */
  121.          bsp_KeyScan();
  122.         os_dly_wait(10);
  123.     }
  124. }
复制代码

22.5 总结
    本章节主要为大家讲解了RTX低功耗之停机模式,这里仅是提供了一种停机模式在RTX上的实现思路,有兴趣的同学也可以想一些其它的实现思路。

评分

参与人数 1金币 +1 收起 理由
joshuazchen + 1 赞一个!

查看全部评分

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-11 13:38 , Processed in 0.293210 second(s), 32 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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