你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。
chrome
firefox
safari
ie8及以上
ST
意法半导体官网
STM32
中文官网
ST
全球论坛
登录/注册
首页
技术问答
话题
资源
创客秀
视频
标签
积分商城
每日签到
【安富莱】【RTX操作系统教程】第24章 RTX低功耗之tickles...
[复制链接]
baiyongbin2009
发布时间:2016-2-17 15:53
文章
文章封面:
-
文章简介:
-
本帖最后由 baiyongbin2009 于 2016-2-18 15:25 编辑
完整PDF教程和例子下载:
https://pan.baidu.com/s/1c0V2Why
第24章
RTX
低功耗之tickless模式:
ãRTXæä½ç³»ç»æç¨ã第24ç« RTXä½åèä¹tickless模å¼.pdf
(776.74 KB, 下载次数: 9)
2016-2-17 15:43 上传
点击文件名下载附件
第24章
RTX
低功耗之tickless模式
本章节为大家讲解RTX本身支持的低功耗模式tickless实现方法,tickless低功耗机制是当前小型RTOS所采用的通用低功耗方法,比如embOS,FreeRTOS和uCOS-III(类似方法)都有这种机制。
本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。
24.1 tickless低功耗模式介绍
24.2 RTX实现tickless模式的框架
24.3 tickless模式的API函数
24.4 实验例程说明
24.5 总结
24.1 tickless低功耗模式介绍
tickless低功耗机制是当前小型RTOS所采用的通用低功耗方法,比如embOS,FreeRTOS和uCOS-III(类似方法)都有这种机制。
RTX的低功耗也是采用的这种方式,那么tickless又是怎样一种模式呢,仅从字母上看tick是滴答时钟的意思,less是tick的后缀,表示较少的,这里的含义可以表示为无滴答时钟。整体看这个字母就是表示滴答时钟节拍停止运行的情况。
反映在RTX上,tickless又是怎样一种情况呢?我们都知道,当用户任务都被挂起时,最低优先级的空闲任务会得到执行。那么STM32支持的睡眠模式,停机模式就可以放在空闲任务里面实现。为了实现低功耗最优设计,我们还不能直接把睡眠或者停机模式直接放在空闲任务就可以了。进入空闲任务后,首先要计算可以执行低功耗的最大时间,也就是求出下一个要执行的高优先级任务还剩多少时间。然后就是把低功耗的唤醒时间设置为这个求出的时间,时间到后系统会从低功耗模式被唤醒,继续执行多任务。这个就是所谓的tickless模式。从上面的讲解中可以看出,实现tickless模式最麻烦是低功耗可以执行的时间如何获取。关于这个问题,RTX已经为我们做好了,调用函数os_suspend即可。
24.2 RTX实现tickless模式的框架
RTX实现低功耗tickless模式的代码框架如下:
__task void os_idle_demon (void) {
uint32_t sleep;
...
/* 第1步:配置系统深度睡眠模式 */
...
/* 第2步:通过函数os_suspend获取系统可以处于低功耗模式的时钟节拍个数,此函数会关闭调度器 */
for (;;) {
sleep = os_suspend ();
if (sleep) {
...
/* 第3步:创建一个新的定时器,专门用于将系统从低功耗模式唤醒,并将唤醒时间设置为
函数os_suspend返回值sleep */
...
/* 第4步:调用低功耗指令进入低功耗模式 */
__WFE ();
/* 第5步:系统从低功耗模式唤醒,调整系统实际处于低功耗状态的时钟节拍个数*/
/* Adjust actual sleep time (in case of any event) */
sleep = ...
}
/* 第6步:重新使能调度器并调整系统时间,继续多任务的执行 */
os_resume (sleep); /* OS Resume */
}
}
复制代码
24.3 tickless模式的API函数
使用如下2个函数可以实现RTX的tickless模式:
os_suspend
os_resume
关于这两个函数的讲解及其使用方法可以看教程第3章3.3小节里面说的参考资料rlarm.chm文件
下面我们也对这2个函数依次进行讲解:
24.3.1 函数os_suspend
函数原型:
U32 os_suspend (void);
复制代码
函数描述:
函数os_suspend用于获取系统可以处于低功耗模式的时钟节拍个数。此函数必须配套函数os_resume一起使用。调用了函数os_suspend后,此函数会关闭调度器,即关闭任务切换,调用了函数os_resume会恢复任务调度。
函数返回系统可以处于低功耗模式的时钟节拍个数。
使用这个函数要注意以下问题:
1. 只能在空闲任务里面调用这个函数。
2. 当系统进入到低功耗模式后,系统滴答定时器停止运行,因为调用了函数os_suspend,此函数会关闭滴答定时器。
使用举例:
下面举的例子是RTX官方提供的基于STM32F2的低功耗设计代码,用于STM32F4也是可以,因为STM32F2和STM32F4的RTX时钟基本一样。下面的例子是通过RTC的低功耗唤醒功能实现。
#include <rtl.h>
__task void os_idle_demon (void) {
uint32_t sleep;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Configure Cortex-M3 for deep sleep */
PWR->CR &= ~PWR_CR_PDDS; /* Enter Stop mode when in deepsleep */
PWR->CR |= PWR_CR_LPDS; /* Voltage regulator in low-power */
/* Enable LSI clock and wait until ready */
RCC->CSR |= RCC_CSR_LSION;
while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
/* Enable power interface clock */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
/* Disable backup domain write protection */
PWR->CR |= PWR_CR_DBP;
/* Select LSI as clock source for RTC and enable RTC */
RCC->BDCR &= ~RCC_BDCR_RTCSEL;
RCC->BDCR |= RCC_BDCR_RTCSEL_1;
RCC->BDCR |= RCC_BDCR_RTCEN;
/* Disable the write protection for RTC registers */
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
/* Configure RTC auto-wakeup mode */
RTC->ISR &= ~RTC_ISR_WUTF; /* Clear wakeup timer flag */
RTC->CR &= ~RTC_CR_WUCKSEL; /* Set RTC clock to 2kHz */
RTC->CR |= RTC_CR_WUTIE; /* Enable RTC wakeup timer interrupt */
/* Configure EXTI line 22 for wakeup on rising edge */
EXTI->EMR |= (1 << 22); /* Event request is not masked */
EXTI->RTSR |= (1 << 22); /* Rising trigger enabled */
NVIC_EnableIRQ (RTC_WKUP_IRQn); /* Enable RTC WakeUp IRQ */
for (;;) {
/* HERE: include optional user code to be executed when no task runs. */
sleep = os_suspend (); /* OS Suspend */
if (sleep) {
RTC->ISR &= ~RTC_ISR_WUTF; /* Clear timer wakeup flag */
RTC->CR &= ~RTC_CR_WUTE; /* Disable wakeup timer */
while ((RTC->ISR & RTC_ISR_WUTWF) == 0);
/* RTC clock is @2kHz, set wakeup time for OS_TICK >= 1ms */
RTC->WUTR = (sleep * (OS_TICK / 1000) * 2);
RTC->CR |= RTC_CR_WUTE; /* Enable wakeup timer */
__WFE (); /* Enter STOP mode */
/* After Wake-up */
if ((RTC->ISR & RTC_ISR_WUTF) == 0) {
sleep = 0; /* We didn't enter Stop mode */
}
}
os_resume (sleep); /* OS Resume */
}
}
复制代码
24.3.2 函数os_resume
函数原型:
void os_resume (
U32 sleep_time ); /* 系统处于低功耗模式的时钟节拍个数 */
复制代码
函数描述:
函数os_resume用于恢复任务调度器的运行。此函数必须配套函数os_suspend一起使用。调用了函数os_suspend后,此函数会关闭调度器,即关闭任务切换,调用函数os_resume会恢复任务调度。
参数填写系统处于低功耗模式的时钟节拍个数。
使用这个函数要注意以下问题:
1. 只能在空闲任务里面调用这个函数。
2. 当系统进入到低功耗模式后,系统滴答定时器停止运行,因为调用了函数os_suspend,此函数会关闭滴答定时器。
使用举例:
参考上面函数os_suspend的举例。
赞
0
收藏
0
评论
3
分享
发布时间:2016-2-17 15:53
举报
请先
登录
后回复
3个回答
baiyongbin2009
回答时间:2016-2-17 16:29:57
a0a.1 32b0c
24.4 实验例程说明
24.4.1 STM32F103开发板实验
配套例子:
V4-424_RTX实验_低功耗(tickless模式)
实验目的:
1. 学习RTX的低功耗(tickless模式)。
2. tickless模式低功耗的实现采用了
停机模式,使用RTC的闹钟中断进行唤醒
。
3. tickless模式的实现在源文件RTX_Conf_CM.C文件中的空闲任务os_idle_demon函数里面。
实验内容:
1.K1按键按下,串口打印。
2.K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro。
任务AppTaskMsgPro接收到消息后进行消息处理。
3.各个任务实现的功能如下:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的信号量同步信号。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
设计低功耗主要从以下几个方面着手:
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类型数据运算会出问题。
系统栈大小分配:
外设初始化:
注意新加的函数初始化函数DBGMCU_Config(DBGMCU_STOP, ENABLE);保证停机模式下调试器正常连接使用。
/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
* 全局变量。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
/* 保证停机模式下调试器继续可以连接使用 */
DBGMCU_Config(DBGMCU_STOP, ENABLE);
/* 优先级分组设置为4, 优先配置好NVIC */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
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)); /* 任务栈大小,单位字节数 */
}
复制代码
tickless
模式在空闲任务实现,即配置向导文件RTX_Conf_CM.c文件中
/*--------------------------- os_idle_demon ---------------------------------*/
#include "stm32f10x.h"
__task void os_idle_demon (void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
uint32_t sleep;
/* 使能PWR和BKP时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* 允许写入RTC和后备寄存器 */
PWR_BackupAccessCmd(ENABLE);
/* 复位后备寄存器 */
BKP_DeInit();
/* 使能LSI */
RCC_LSICmd(ENABLE);
/* 等待直到LSI就绪 */
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
/* 选择LSI作为RTC的时钟 */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
/* 使能RTC时钟 */
RCC_RTCCLKCmd(ENABLE);
/*
在APB1总线复位或者停止后重新开启,RTC的任何读取前得等待RTC寄存器
(RTC_CNT, RTC_ALR and RTC_PRL)跟RTC APB时钟同步。
*/
RTC_WaitForSynchro();
/* 等待RTC寄存器写操作完成 */
RTC_WaitForLastTask();
/*
1. LSI的频率典型值是40KHz(30KHz到60KHz)
2. 这里按40KHz来计算
RTC 周期 = RTCCLK / RTC_PR = (40 KHz)/(19 + 1) = 2KHz
*/
RTC_SetPrescaler(19);
/* 等待RTC寄存器写操作完成 */
RTC_WaitForLastTask();
/* EXTI线17连接到RTC闹钟事件,使能中断 */
EXTI_ClearITPendingBit(EXTI_Line17);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* 设置闹钟中断的NVIC */
NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
for (;;)
{
/* 挂起OS, 并返回可以执行低功耗的时长 */
sleep = os_suspend ();
if (sleep)
{
/* RTC计数设置 */
RTC_SetCounter(0);
RTC_WaitForLastTask();
/* 设置闹钟时间 */
RTC_SetAlarm(sleep*(OS_TICK/1000)*2);
RTC_WaitForLastTask();
/* 使能闹钟中断 */
RTC_ITConfig(RTC_IT_ALR, ENABLE);
RTC_WaitForLastTask();
/* 进入停机模式 */
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);
/*
1、当一个中断或唤醒事件导致退出停止模式时,HSI RC振荡器被选为系统时钟。
2、退出低功耗的停机模式后,需要重新配置使用HSE和HSE
*/
SystemInit();
/*
在APB1总线复位或者停止后重新开启,RTC的任何读取前得等待RTC寄存器
(RTC_CNT, RTC_ALR and RTC_PRL)跟RTC APB时钟同步。
*/
RTC_WaitForSynchro();
/* 检查唤醒标志是否设置 */
if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)
{
/* 用户可以在这里加入相关串口打印等函数来检测是否进入停机模式 */
//printf("lowpower\r\n");
/* 清除唤醒标志 */
PWR_ClearFlag(PWR_FLAG_WU);
}
else
{
sleep = 0;
}
}
/* 恢复OS */
os_resume (sleep);
}
}
/*--------------------------- RTC闹钟中断 ----------------------------------*/
void RTCAlarm_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_ALR) != RESET)
{
/* 禁止RTC的闹钟中断 */
RTC_ITConfig(RTC_IT_ALR, DISABLE);
RTC_WaitForLastTask();
/* 清除中断标志 */
EXTI_ClearITPendingBit(EXTI_Line17);
/* 清除中断标志 */
RTC_ClearITPendingBit(RTC_IT_ALR);
RTC_WaitForLastTask();
}
}
复制代码
信号量的创建:
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);
}
}
复制代码
赞
评论
回复
支持
反对
baiyongbin2009
回答时间:2016-2-17 16:36:02
a0a.1 32b0c
24.4.2 STM32F407开发板实验
配套例子:
V5-424_RTX实验_低功耗(tickless模式)
实验目的:
1. 学习RTX的低功耗(tickless模式)。
2. tickless模式低功耗的实现采用了
停机模式,使用RTC的唤醒中断进行唤醒
。这个和前面STM32F1开发板采用的闹钟中断唤醒不同。
3. tickless模式的实现在源文件RTX_Conf_CM.C文件中的空闲任务os_idle_demon函数里面。
实验内容:
1.K1按键按下,串口打印。
2.K2键按下,直接发送信号量同步信号给任务AppTaskMsgPro。
任务AppTaskMsgPro接收到消息后进行消息处理。
3.各个任务实现的功能如下:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的信号量同步信号。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
设计低功耗主要从以下几个方面着手:
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类型数据运算会出问题。
系统栈大小分配:
外设初始化:
注意新加的函数初始化函数DBGMCU_Config(DBGMCU_STOP, ENABLE);保证停机模式下调试器正常连接使用。
/*
/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
* 全局变量。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
/* 保证停机模式下调试器继续可以连接使用 */
DBGMCU_Config(DBGMCU_STOP, ENABLE);
/* 优先级分组设置为4, 优先配置好NVIC */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
bsp_InitUart(); /* 初始化串口 */
bsp_InitKey(); /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
bsp_InitLed(); /* 初始LED指示灯端口 */
}
复制代码
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)); /* 任务栈大小,单位字节数 */
}
复制代码
tickless
模式在空闲任务实现,即配置向导文件RTX_Conf_CM.c文件中
/*----------------------------------------------------------------------------
* Global Functions
*---------------------------------------------------------------------------*/
#include "stm32f4xx.h"
extern void SetSysClock(void);
void RTC_WKUP_IRQHandler (void) {
EXTI->PR = (1 << 22); /* Clear pending EXTI interrupt */
RTC->CR &= ~RTC_CR_WUTE; /* Disable wakeup timer */
}
/*--------------------------- os_idle_demon ---------------------------------*/
__task void os_idle_demon (void) {
// /* The idle demon is a system task, running when no other task is ready */
// /* to run. The 'os_xxx' function calls are not allowed from this task. */
uint32_t sleep;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Configure Cortex-M3 for deep sleep */
PWR->CR &= ~PWR_CR_PDDS; /* Enter Stop mode when in deepsleep */
PWR->CR |= PWR_CR_LPDS; /* Voltage regulator in low-power */
/* Enable LSI clock and wait until ready */
RCC->CSR |= RCC_CSR_LSION;
while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
/* Enable power interface clock */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
/* Disable backup domain write protection */
PWR->CR |= PWR_CR_DBP;
/* Select LSI as clock source for RTC and enable RTC */
RCC->BDCR &= ~RCC_BDCR_RTCSEL;
RCC->BDCR |= RCC_BDCR_RTCSEL_1;
RCC->BDCR |= RCC_BDCR_RTCEN;
/* Disable the write protection for RTC registers */
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
/* Configure RTC auto-wakeup mode */
RTC->ISR &= ~RTC_ISR_WUTF; /* Clear wakeup timer flag */
RTC->CR &= ~RTC_CR_WUCKSEL; /* Set RTC clock to 2kHz */
RTC->CR |= RTC_CR_WUTIE; /* Enable RTC wakeup timer interrupt */
/* Configure EXTI line 22 for wakeup on rising edge */
EXTI->EMR |= (1 << 22); /* Event request is not masked */
EXTI->RTSR |= (1 << 22); /* Rising trigger enabled */
NVIC_EnableIRQ (RTC_WKUP_IRQn); /* Enable RTC WakeUp IRQ */
for (;;) {
/* HERE: include optional user code to be executed when no task runs. */
sleep = os_suspend (); /* OS Suspend */
if (sleep) {
RTC->ISR &= ~RTC_ISR_WUTF; /* Clear timer wakeup flag */
RTC->CR &= ~RTC_CR_WUTE; /* Disable wakeup timer */
while ((RTC->ISR & RTC_ISR_WUTWF) == 0);
/* RTC clock is @2kHz, set wakeup time for OS_TICK >= 1ms */
RTC->WUTR = (sleep * (OS_TICK / 1000) * 2);
RTC->CR |= RTC_CR_WUTE; /* Enable wakeup timer */
__WFE (); /* Enter STOP mode */
/* After Wake-up */
if ((RTC->ISR & RTC_ISR_WUTF) == 0) {
sleep = 0; /* We didn't enter Stop mode */
}
}
os_resume (sleep); /* OS Resume */
/*
下面的代码由用户添加。
1、当一个中断或唤醒事件导致退出停止模式时,HSI RC振荡器被选为系统时钟。
2、退出低功耗的停机模式后,需要重新配置使用HSE和HSE。
3、测试发现时钟配置函数SetSysClock不能放在os_suspend和os_resume,要不会有问题。
*/
/* Disable IRQs */
__disable_irq();
SetSysClock();
/* Enable IRQs */
__enable_irq();
}
}
复制代码
信号量的创建:
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);
}
}
复制代码
赞
评论
回复
支持
反对
baiyongbin2009
回答时间:2016-2-17 16:36:58
a0a.1 32b0c
24.5 总结
本章节主要为大家讲解了RTX本身支持的低功耗tickless模式,对于初学者来说,刚开始学习可能不是特别理解,随着后面自己有了一定的经验后就比较容易理解了,特别是tickless的实现方法。另外tickless模式不限制用户必须采用停机模式,采用睡眠模式也是可以的,官方只是为用户提供了一种参考方法。
赞
评论
回复
支持
反对
所属标签
关于
意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号
手机版
快速回复
返回顶部
返回列表
24.4.1 STM32F103开发板实验