资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理)
目录
一、独立看门狗介绍
二、看门狗监测多任务执行思路
1、监测目标
2、监测方案
3、应用注意事项
三、看门狗监测多任务编程
1、STM32cubeMX配置
2、代码编写
四、低功耗Tickless模式
1、Tickless模式介绍
2、Tickless模式配置
3、Tickless模式编程
① 监测系统死机
② 监测任务执行
说明:
①、监测任务通过独立看门狗监测自身,如果长时间得不到执行,看门狗将复位系统;
②、监测任务通过事件标志监控其它任务,如果任一任务长时间得不到执行,看门狗将复位系统;
③、监测任务收到全部被监测任务发来的事件标志后,才进行喂狗。
①、监测任务优先级设置最高,以便及时喂狗
②、监测任务与被监测任务均不可以挂起或删除,否则,无法及时喂狗导致系统复位
③、喂狗时间由被监测任务的最大发送事件标志间隔时间确定,并且留有足够裕量
④、考虑事件标志只有低24位可用,被监测任务最多24个,足够使用
监控任务优先级需要设置最高。以便喂狗
①设置事件位
/* USER CODE BEGIN PD */
#define BIT_Task01_EVENT (EventBits_t)(0x0001 << 0)
#define BIT_Task02_EVENT (EventBits_t)(0x0001 << 1)
#define BIT_Task03_EVENT (EventBits_t)(0x0001 << 2)
#define BIT_Task04_EVENT (EventBits_t)(0x0001 << 3)
#define BIT_TaskAll_EVENT BIT_Task01_EVENT | BIT_Task02_EVENT | BIT_Task03_EVENT | BIT_Task04_EVENT
/* USER CODE END PD */
②创建事件
/* USER CODE BEGIN Init */
MyEvent01Handle = xEventGroupCreate();//创建事件
/* USER CODE END Init */
③监测任务
void IWDG_Monitor_Task(void const * argument)
{
/* USER CODE BEGIN IWDG_Monitor_Task */
EventBits_t xEvent;
const TickType_t xTicksToWait = 6000 / portTICK_PERIOD_MS;//设置等待时间
/* Infinite loop */
for(;;)
{
xEvent = xEventGroupWaitBits(
MyEvent01Handle,//事件句柄
BIT_TaskAll_EVENT,//事件
pdTRUE,//退出时清除事件位
pdTRUE,//逻辑与,满足所有事件
xTicksToWait//等待时间
);
if((xEvent&(BIT_TaskAll_EVENT)) == (BIT_TaskAll_EVENT))
{
sprintf(buff,"%s \r\n","喂狗,监测任务与被监测任务均正常执行");
HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);
HAL_IWDG_Refresh(&hiwdg);
}
else
{
}
}
/* USER CODE END IWDG_Monitor_Task */
}
④被监测任务
void StartTask01(void const * argument)
{
/* USER CODE BEGIN StartTask01 */
/* Infinite loop */
for(;;)
{
osDelay(1000);
xEventGroupSetBits(MyEvent01Handle,BIT_Task01_EVENT);
}
/* USER CODE END StartTask01 */
}
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
osDelay(2000);
xEventGroupSetBits(MyEvent01Handle,BIT_Task02_EVENT);
}
/* USER CODE END StartTask02 */
}
void StartTask03(void const * argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
for(;;)
{
osDelay(3000);
xEventGroupSetBits(MyEvent01Handle,BIT_Task03_EVENT);
}
/* USER CODE END StartTask03 */
}
void StartTask04(void const * argument)
{
/* USER CODE BEGIN StartTask04 */
/* Infinite loop */
for(;;)
{
osDelay(4000);
xEventGroupSetBits(MyEvent01Handle,BIT_Task04_EVENT);
}
/* USER CODE END StartTask04 */
}
①电池类产品,一般要求低功耗设计,比如农业物联网的节点采集设备
②低功耗设计,除了MCU,软件, 硬件设计同等重要
③Tickless模式主要针对睡眠模式,当然,也可以自行使用停机模式,待机模式
Tickless 低功耗机制是当前小型 RTOS 所采用的通用低功耗方法,比如FreeRTOS,RTX 和 uCOS-III等。仅从字母上看,Tick 是滴答时钟的意思,less 是 Tick 的后缀,表示较少的,整体看就是表示减少滴答时钟节拍运行。
在FreeRTOS系统中,当用户任务都被挂起或者阻塞时,最低优先级的空闲任务会得到执行。那么 STM32 支持的低功耗模式就可以放在空闲任务里面实现。为了实现低功耗最优设计,我们还不能直接把睡眠模式放在空闲任务就可以了。由于Tick中断停止,将导致无法及时运行阻塞超时的任务,进入空闲任务后,首先要计算可以执行低功耗的最大时间,也就是求出下一个要执行的高优先级任务还剩多少时间。然后就是把低功耗的唤醒时间设置为这个求出的时间(其实就是重载Systick),如果没有其它中断或事件唤醒STM32,到时间后Systick中断会将STM32唤醒,继续执行任务。
这个就是所谓的 Tickless 模式。从上面的讲解中可以看出,实现Tickless模式最麻烦的是计算低功耗可以执行的时间。这个难题,FreeRTOS 已为我们做好。
① 将宏定义configUSE_TICKLESS_IDLE设置为1即可
② 配置 configEXPECTED_IDLE_TIME_BEFORE_SLEEP,只有当系统可运行于低功耗模式的时钟节拍数大于等于这个参数时,系统才可以进入到低功耗模式。此参数已在 FreeRTOS.h文件中定义了,默认为2,用户可以自定义时,不能小于2
①STM32cubeMX配置
②configEXPECTED_IDLE_TIME_BEFORE_SLEEP设置
(进入低功耗的最小Tick,如果实际比设置Tick小,则不进入低功耗)一般默认2个Tick就够了,如果需要修改不要在源码里修改,在FreeRTOSConfig.h里重定义宏
/* USER CODE BEGIN 1 */
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 10
/* USER CODE END 1 */
③在进入与退出Tickless模式时增加代码,通常是关闭外设等
这样写只是为了验证有没有开启低功耗成功
/* USER CODE BEGIN PREPOSTSLEEP */
__weak void PreSleepProcessing(uint32_t *ulExpectedIdleTime)
{
//进入休眠前,关闭外设等
/* place for user code */
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
}
__weak void PostSleepProcessing(uint32_t *ulExpectedIdleTime)
{
//退出休眠,开启外设等
/* place for user code */
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
}
/* USER CODE END PREPOSTSLEEP */