打印
[应用相关]

RTX操作系统-RTX低功耗之待机模式

[复制链接]
1201|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ccw1986|  楼主 | 2016-2-16 20:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
RTX低功耗之待机模式
    低功耗是MCU的一项非常重要的指标,本章节为大家讲解STM32F103和STM32F407的低功耗方式之待机模式在RTX操作系统上面的实现方法(RTX本身支持的tickless低功耗模式在第24章节讲解
    本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。
23.1 STM32F103待机模式介绍
23.2 STM32F407待机模式介绍
23.3 实验例程说明
23.4      总结
23.1  STM32F103待机模式介绍
    说明:在RTX系统上面实现待机方式仅需了解这里讲解的知识基本就够用了,更多休眠方式的知识请看STM32F103参考手册和Cortex-M3权威指南。
    在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
    STM32F103有三种低功耗模式:
    (1)睡眠模式(Cortex™-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统滴答定时器Systick等仍在运行)。
    (2)停止模式(所有的时钟都已停止)。
    (3)待机模式(1.8V电源关闭)。
    本章节我们主要讲解待机模式,待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失,只有备份的寄存器和待机电路维持供电。
    在实际的待机模式编程时需要清楚那些问题呢? 请继续往下看。

23.1.1  STM32F103如何进入待机模式
    在RTX系统中,让STM32进入待机模式比较容易,调用固件库函数PWR_EnterSTANDBYMode即可。

23.1.2  STM32F103如何退出待机模式
    让STM32从待机模式唤醒可以通过外部复位(NRST引脚)、IWDG复位、WKUP引脚上的上升沿或RTC闹钟事件的上升沿。从待机唤醒后,除了电源控制/状寄存器,所有寄存器被复位。
    从待机模式唤醒后的代码执行等同于复位后的执行。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。
    在开发板上面是通过K2按键来唤醒,K2按键使用的引脚就是WKUP引脚。

23.1.3 STM32F103使用待机模式注意事项
     待机模式要注意以下问题:
    (1)在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
    A.  复位引脚(始终有效)。
    B.  当被设置为防侵入或校准输出时的TAMPER引脚。
    C.  被使能的唤醒引脚。

沙发
ccw1986|  楼主 | 2016-2-16 20:47 | 只看该作者
23.2  STM32F407待机模式介绍
    说明:在RTX系统上面实现待机方式仅需了解这里讲解的知识基本就够用了,更多休眠方式的知识请看STM32F407参考手册和Cortex-M4权威指南。
    在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
    STM32F407有三种低功耗模式:
    (1)睡眠模式(Cortex™-M4F内核停止,所有外设包括Cortex-M4核心的外设,如NVIC、系统滴答定时器Systick等仍在运行)。
    (2)停止模式(所有的时钟都已停止)。
    (3)待机模式(1.2V电源关闭)。
    本章节我们主要讲解待机模式,待机模式下可达到最低功耗。待机模式基于Cortex™-M4F深度睡眠模式,其中调压器被禁止。因此1.2 V域断电。PLL、HSI振荡器和HSE 振荡器也将关闭。除备份域RTC寄存器、RTC备份寄存器和备份SRAM)和待机电路中的寄存器外,SRAM 和寄存器内容都将丢失。
    在实际的待机模式编程时需要清楚那些问题呢? 请继续往下看。

23.2.1 STM32F407如何进入待机模式
    在RTX系统中,让STM32进入待机模式比较容易,调用固件库函数PWR_EnterSTANDBYMode即可。

23.2.2 STM32F407如何退出待机模式
    让STM32从待机模式唤醒可以通过外WKUP 引脚上升沿、RTC闹钟(闹钟A和闹钟B)、RTC唤醒事件、RTC入侵事件、RTC 时间戳事件、NRST引脚外部复位和IWDG 复位,唤醒后除了电源控制/状寄存器,所有寄存器被复位。
    从待机模式唤醒后,程序将按照复位(启动引脚采样、复位向量已获取等)后的方式重新执行。PWR 电源控制/ 状态寄存器(PWR_CSR)中的SBF状态标志指示MCU已处于待机模式。
    在开发板上面是通过K2按键来唤醒,K2按键使用的引脚就是RTC入侵事件检测引脚PC13。

23.2.3 STM32F407使用待机模式注意事项
    待机模式要注意以下问题:
(1)将选择的待机模式唤醒源(RTC闹钟A、RTC闹钟B、RTC唤醒、RTC入侵或RTC时间戳标志)对应的RTC标志清零,防止无**常进入待机模式。
(2)待机模式下的 I/O 状态
    A. 复位引脚(仍可用)。
    B. RTC_AF1 引脚 (PC13)(如果针对入侵、时间戳、RTC闹钟输出或RTC时钟校准输出进行了配置)。
    C.  WKUP引脚 (PA0)(如果使能)。

使用特权

评论回复
板凳
ccw1986|  楼主 | 2016-2-16 20:48 | 只看该作者
23.3  实验例程说明
23.3.1 STM32F103开发板实验
配套例子:
    V4-423_RTX实验_低功耗(待机模式)
实验目的:
    1.     学习RTX实验低功耗(待机模式)。
实验内容:
    1.     K1按键按下,串口打印。
    2.     K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro,任务AppTaskMsgPro接收到消息后进行消息处理。K2按键还有一个功能就是将系统从待机模式唤醒。
    3.     K3按键按下,系统进入到待机模式。
    4.     各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的信号量同步信号。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    5.     关于低功耗的说明:
    (1)   待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。
     (2) 从待机模式唤醒后的代码执行等同于复位后的执行。
    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配置向导详情如下:
                              
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
程序设计:
任务栈大小分配:
    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类型数据运算会出问题。
系统栈大小分配:
外设初始化:
    使能WKUP引脚PA0,用于将系统从待机模式唤醒。在bsp.c文件里面调用。

使用特权

评论回复
地板
ccw1986|  楼主 | 2016-2-16 20:49 | 只看该作者
/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
*             全局变量。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{   
     /* 优先级分组设置为4, 优先配置好NVIC */
     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
   
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
   
     /* 使能WKUP 引脚PA0,用于将系统从待机模式唤醒 */
     PWR_WakeUpPinCmd(ENABLE);

     bsp_InitUart();    /* 初始化串口 */
     bsp_InitLed();         /* 初始LED指示灯端口 */
     bsp_InitKey();         /* 初始化按键 */
   
}

RTX初始化:
/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: 标准c程序入口。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
int main (void)
{   
     /* 初始化外设 */
     bsp_Init();
   
     /* 创建启动任务 */
     os_sys_init_user (AppTaskStart,             /* 任务函数 */
                       4,                        /* 任务优先级 */
                       &AppTaskStartStk,         /* 任务栈 */
                       sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
     while(1);
}

RTX任务创建:
/*
*********************************************************************************************************
*    函 数 名: AppTaskCreate
*    功能说明: 创建应用任务
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
     HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
                                           1,                         /* 任务优先级 */
                                           &AppTaskUserIFStk,         /* 任务栈 */
                                           sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
   
     HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
                                        2,                       /* 任务优先级 */
                                        &AppTaskLEDStk,          /* 任务栈 */
                                        sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
   
     HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
                                           3,                         /* 任务优先级 */
                                           &AppTaskMsgProStk,         /* 任务栈 */
                                           sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
}


使用特权

评论回复
5
ccw1986|  楼主 | 2016-2-16 20:50 | 只看该作者
信号量创建:
static OS_SEM semaphore;

/*
*********************************************************************************************************
*    函 数 名: AppObjCreate
*    功能说明: 创建任务通信机制
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
     /* 创建信号量计数值是0, 用于任务同步 */
     os_sem_init (&semaphore, 0);
}
四个RTX任务的实现:
/*
*********************************************************************************************************
*    函 数 名: AppTaskUserIF
*    功能说明: 按键消息处理     
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
*********************************************************************************************************
*/
__task void AppTaskUserIF(void)
{
     uint8_t ucKeyCode;

    while(1)
    {
         ucKeyCode = bsp_GetKey();
        
         if (ucKeyCode != KEY_NONE)
         {
              switch (ucKeyCode)
              {
                   /* K1键按下,打印调试说明 */
                   case KEY_DOWN_K1:
                       printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
                       break;  

                   /* K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro */
                   case KEY_DOWN_K2:
                       printf("K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro\r\n");
                       os_sem_send (&semaphore);
                       break;

                   /* 其他的键值不处理 */
                  default:                    
                       break;
              }
         }
        
         os_dly_wait(20);
     }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskLED
*    功能说明: LED闪烁。
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 2
*********************************************************************************************************
*/
__task void AppTaskLED(void)
{
     const uint16_t usFrequency = 200; /* 延迟周期 */
   
     /* 设置延迟周期 */
     os_itv_set(usFrequency);
   
    while(1)
    {
         bsp_LedToggle(2);
         bsp_LedToggle(3);

         /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
         os_itv_wait();
    }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskMsgPro
*    功能说明: 消息处理,等待任务AppTaskUserIF发来的信号量同步信号
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 3
*********************************************************************************************************
*/
__task void AppTaskMsgPro(void)
{
     OS_RESULT xResult;
     const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
   
    while(1)
    {
         xResult = os_sem_wait (&semaphore, usMaxBlockTime);
        
         switch (xResult)
         {
              /* 无需等待接受到信号量同步信号 */
              case OS_R_OK:
                   printf("无需等待接受到信号量同步信号\r\n");
                   break;  

              /* 信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号 */
              case OS_R_SEM:
                   printf("信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号\r\n");
                   break;

              /* 超时 */
              case OS_R_TMO:
                   bsp_LedToggle(1);
                   bsp_LedToggle(4);
                   break;
            
              /* 其他值不处理 */
              default:                     
                   break;
         }   
    }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskStart
*    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 4
*********************************************************************************************************
*/
__task void AppTaskStart(void)
{
     /* 创建任务 */
     AppTaskCreate();
   
     /* 创建任务通信机制 */
     AppObjCreate();
   
    while(1)
    {
         /* 按键扫描 */
         bsp_KeyScan();
        os_dly_wait(10);
    }
}


使用特权

评论回复
6
ccw1986|  楼主 | 2016-2-16 20:51 | 只看该作者
23.3.2   STM32F407开发板实验
配套例子:
    V5-423_RTX实验_低功耗(待机模式)
实验目的:
    1.     学习RTX实验低功耗(待机模式)。
实验内容:
    1.     K1按键按下,串口打印。
    2.     K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro,任务AppTaskMsgPro接收到消息后进行消息处理。
    3.     K2按键还有一个功能是将系统从待机模式唤醒,唤醒方式是用过K2按键对应的引脚PC13检测RTC的入侵事件。
    4.     K3按键按下,系统进入到待机模式。
    5.     各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的信号量同步信号。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    6.     关于低功耗的说明:
     (1)  待机模式可实现系统的最低功耗。该模式是在Cortex-M4F深睡眠模式时关闭电压调节器整个1.2V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。
     (2) 从待机模式唤醒后的代码执行等同于复位后的执行。
    7.     实际项目中推荐采用官方的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配置向导详情如下:
                              
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
程序设计:
任务栈大小分配:
    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类型数据运算会出问题。
系统栈大小分配:

使用特权

评论回复
7
ccw1986|  楼主 | 2016-2-16 20:52 | 只看该作者
RTX初始化:
/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: 标准c程序入口。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
int main (void)
{   
     /* 初始化外设 */
     bsp_Init();
   
     /* 创建启动任务 */
     os_sys_init_user (AppTaskStart,             /* 任务函数 */
                       4,                        /* 任务优先级 */
                       &AppTaskStartStk,         /* 任务栈 */
                       sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
     while(1);
}

RTX任务创建:
/*
*********************************************************************************************************
*    函 数 名: AppTaskCreate
*    功能说明: 创建应用任务
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
     HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
                                           1,                         /* 任务优先级 */
                                           &AppTaskUserIFStk,         /* 任务栈 */
                                           sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
   
     HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
                                        2,                       /* 任务优先级 */
                                        &AppTaskLEDStk,          /* 任务栈 */
                                        sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
   
     HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
                                           3,                         /* 任务优先级 */
                                           &AppTaskMsgProStk,         /* 任务栈 */
                                           sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
}
信号量创建:
static OS_SEM semaphore;

/*
*********************************************************************************************************
*    函 数 名: AppObjCreate
*    功能说明: 创建任务通信机制
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
     /* 创建信号量计数值是0, 用于任务同步 */
     os_sem_init (&semaphore, 0);
}


使用特权

评论回复
8
ccw1986|  楼主 | 2016-2-16 20:53 | 只看该作者
K2按键(PC13引脚)RTC入侵事件检测的实现,在bsp.c文件中:
/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
     /* 优先级分组设置为4, 优先配置好NVIC */
     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

     bsp_InitUart();    /* 初始化串口 */
     bsp_InitKey();         /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */

     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
     bsp_InitLed();         /* 初始LED指示灯端口 */
   
     bsp_rtctamper();
}

/*
*********************************************************************************************************
*    函 数 名: bsp_rtctamper
*    功能说明: 配置RTC的入侵事件来唤醒待机模式,另外用户不需要写入侵中断函数。
*             因为系统进入到待机模式后,检测到入侵事件后系统的执行过程等同于进行复位。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void bsp_rtctamper(void)
{
     NVIC_InitTypeDef NVIC_InitStructure;
     EXTI_InitTypeDef  EXTI_InitStructure;

     /* 使能PWR时钟 */
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

     /* 允许访问RTC */
     PWR_BackupAccessCmd(ENABLE);
   
    /* 选择RTC时钟源 LSI */   
     RCC_LSICmd(ENABLE);
     while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != RESET);
     RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

     /* 使能外部中断 */
     EXTI_ClearITPendingBit(EXTI_Line21);
     EXTI_InitStructure.EXTI_Line = EXTI_Line21;
     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;
     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
     EXTI_InitStructure.EXTI_LineCmd = ENABLE;
     EXTI_Init(&EXTI_InitStructure);

     /* 使能中断通道 TAMPER */
     NVIC_InitStructure.NVIC_IRQChannel = TAMP_STAMP_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
     NVIC_Init(&NVIC_InitStructure);

     /* 禁止Tamper 1检测 */
     RTC_TamperCmd(RTC_Tamper_1, DISABLE);
   
     RTC_ClearFlag(RTC_FLAG_TAMP1F);
     RTC_TamperTriggerConfig(RTC_Tamper_1, RTC_TamperTrigger_FallingEdge);
     RTC_ITConfig(RTC_IT_TAMP, ENABLE);
     RTC_ClearITPendingBit(RTC_IT_TAMP1);

     /* 使能 Tamper 1 detection */
     RTC_TamperCmd(RTC_Tamper_1, ENABLE);
}
四个RTX任务的实现:
/*
*********************************************************************************************************
*    函 数 名: AppTaskUserIF
*    功能说明: 按键消息处理     
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
*********************************************************************************************************
*/
__task void AppTaskUserIF(void)
{
     uint8_t ucKeyCode;

    while(1)
    {
         ucKeyCode = bsp_GetKey();
        
         if (ucKeyCode != KEY_NONE)
         {
              switch (ucKeyCode)
              {
                   /* K1键按下,打印调试说明 */
                   case KEY_DOWN_K1:
                       printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
                       break;  

                   /* K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro,K2按键还有一个功能就是将系统从
待机模式唤醒*/
                   case KEY_DOWN_K2:
                       printf("K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro\r\n");
                       os_sem_send (&semaphore);
                       break;
                  
                   /* K3键按下 进入到待机模式 */
                   case KEY_DOWN_K3:            
                       printf("K3按键按下,系统进入待机模式,按K2按键将唤醒\r\n");
                       PWR_EnterSTANDBYMode();   
                       break;

                   /* 其他的键值不处理 */
                   default:                    
                       break;
              }
         }
        
         os_dly_wait(20);
     }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskLED
*    功能说明: LED闪烁。
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 2
*********************************************************************************************************
*/
__task void AppTaskLED(void)
{
     const uint16_t usFrequency = 200; /* 延迟周期 */
   
     /* 设置延迟周期 */
     os_itv_set(usFrequency);
   
    while(1)
    {
         bsp_LedToggle(2);
         bsp_LedToggle(3);

         /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
         os_itv_wait();
    }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskMsgPro
*    功能说明: 消息处理,等待任务AppTaskUserIF发来的信号量同步信号
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 3
*********************************************************************************************************
*/
__task void AppTaskMsgPro(void)
{
     OS_RESULT xResult;
     const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
   
    while(1)
    {
         xResult = os_sem_wait (&semaphore, usMaxBlockTime);
        
         switch (xResult)
         {
              /* 无需等待接受到信号量同步信号 */
              case OS_R_OK:
                   printf("无需等待接受到信号量同步信号\r\n");
                   break;  

              /* 信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号 */
              case OS_R_SEM:
                   printf("信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号\r\n");
                   break;

              /* 超时 */
              case OS_R_TMO:
                   bsp_LedToggle(1);
                   bsp_LedToggle(4);
                   break;
            
              /* 其他值不处理 */
              default:                    
                   break;
         }   
    }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskStart
*    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 4
*********************************************************************************************************
*/
__task void AppTaskStart(void)
{
     /* 创建任务 */
     AppTaskCreate();
   
     /* 创建任务通信机制 */
     AppObjCreate();
   
    while(1)
    {
         /* 按键扫描 */
         bsp_KeyScan();
        os_dly_wait(10);
    }
}
23.4 总结
    本章节主要为大家讲解了RTX低功耗之待机模式,这里仅是提供了一种停机模式在RTX上的实现思路,有兴趣的同学也可以想一些其它的实现思路。

使用特权

评论回复
9
huangcunxiake| | 2016-2-17 09:07 | 只看该作者
待机模式下可达到最低功耗。待机模式基于Cortex™-M4F深度睡眠模式,其中调压器被禁止

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

925

帖子

6

粉丝