本节需要掌握以下内容:
1,低功耗模式简介(了解)
2, Tickless模式详解(熟悉)
3, Tickless模式相关配置项(掌握)
4,Tickless低功耗模式实验(掌握)
5,课堂总结(掌握)
一、低功耗模式简介(了解)
很多应用场合对于功耗的要求很严格,比如可穿戴低功耗产品,物联网低功耗产品等
一般MCU都有相应的低功耗模式,裸机开发可以使用MCU的低功耗模式。
FreeRTOS也提供了一个叫Tickless的低功耗模式,方便带FreeRTOS操作系统的应用开发
1.1 STM32低功耗模式
- 睡眠模式
- 停止模式
- 待机模式
这里我们主要使用的时这个睡眠模式
1、进入睡眠模式
WFI指令:__WFI
WFE指令:__WFE
2、退出睡眠模式
任何中断或事件都可以唤醒睡眠模式
关于这三个低功耗模式的详解可以查看对应板子的开发指南
二、Tickless模式详解(熟悉)
如何降低功耗?
Tickless低功耗的本质是通过调用指令WFI实现睡眠模式!
Tickless模式的设计思想?
任务运行事件统计实验中可以看出,在整个系统的运行过程中,其实大部分事件都是在执行空闲任务的
空闲任务:实在系统中所有其它任务都阻塞或者被挂起时才运行的
为了可以降低功耗,又不影响系统运行,该如何做?
可以在本该空闲任务执行的期间,让MCU进入相应的低功耗模式;当其它任务准备运行的时候,唤醒MCU退出低功耗模式
难点:
1、进入低功耗模式之后,多久唤醒?也就是下一个要运行的任务如何被准确唤醒?
2、任何中断均可唤醒MCU,若滴答定时器频繁中断主任会影响低功耗的效果?
将滴答定时器的中断周期修改为低功耗运行事件
退出低功耗后,需补上系统时钟节拍数。
值得庆幸的是:FreeRTOS的低功耗Tickless模式机制已经处理好了这些难点。
三、Tickless模式相关配置项(掌握)
- configUSE_TICKLESS_IDLE
- configEXPECTED_IDLE_TIME_BEFORE_SLEEP
- configPRE_SLEEP_PROCESSING(x)
- configPOST_SLEEP_PROCESSING( x )
四、Tickless低功耗模式实验(掌握)
4.1、实验目的:
学习 FreeRTOS 中的低功耗Tickless模式,并观察该模式对功耗有明显降低
4.2、实验设计:
将设计三个任务:start_task、task1
将在原先二值信号量的源码中,加入低功耗模式,最后对比这两个实验的功耗结果,观察Tickless模式对于降低功耗是否有用
4.3 实验代码
/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );/* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );/******************************************************************************************************/
QueueHandle_t semphore_handle;
/* 进入低功耗前所需要执行的操作 */
void PRE_SLEEP_PROCESSING(void)
{__HAL_RCC_GPIOA_CLK_DISABLE();__HAL_RCC_GPIOB_CLK_DISABLE();__HAL_RCC_GPIOC_CLK_DISABLE();__HAL_RCC_GPIOD_CLK_DISABLE(); __HAL_RCC_GPIOE_CLK_DISABLE();__HAL_RCC_GPIOF_CLK_DISABLE();__HAL_RCC_GPIOG_CLK_DISABLE();
}
/* 退出低功耗后所需要执行的操作 */
void POST_SLEEP_PROCESSING(void)
{__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();__HAL_RCC_GPIOG_CLK_ENABLE();
}
/*** @brief FreeRTOS例程入口函数* @param 无* @retval 无*/
void freertos_demo(void)
{ semphore_handle = xSemaphoreCreateBinary();if(semphore_handle != NULL){printf("二值信号量创建成功!!!\r\n");}xTaskCreate((TaskFunction_t ) start_task,(char * ) "start_task",(configSTACK_DEPTH_TYPE ) START_TASK_STACK_SIZE,(void * ) NULL,(UBaseType_t ) START_TASK_PRIO,(TaskHandle_t * ) &start_task_handler );vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL(); /* 进入临界区 */xTaskCreate((TaskFunction_t ) task1,(char * ) "task1",(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,(void * ) NULL,(UBaseType_t ) TASK1_PRIO,(TaskHandle_t * ) &task1_handler );xTaskCreate((TaskFunction_t ) task2,(char * ) "task2",(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,(void * ) NULL,(UBaseType_t ) TASK2_PRIO,(TaskHandle_t * ) &task2_handler );vTaskDelete(NULL);taskEXIT_CRITICAL(); /* 退出临界区 */
}/* 任务一,释放二值信号量 */
void task1( void * pvParameters )
{uint8_t key = 0;BaseType_t err;while(1) {key = key_scan(0);if(key == KEY0_PRES){if(semphore_handle != NULL){err = xSemaphoreGive(semphore_handle);if(err == pdPASS){printf("信号量释放成功!!\r\n");}else printf("信号量释放失败!!\r\n");}}vTaskDelay(10);}
}/* 任务二,获取二值信号量 */
void task2( void * pvParameters )
{uint32_t i = 0;BaseType_t err;while(1){err = xSemaphoreTake(semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */if(err == pdTRUE){printf("获取信号量成功\r\n");}else printf("已超时%d\r\n",++i);}
}