本节需要掌握以下内容:
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 实验代码
demo.c
/******************************************************************************************************/
/*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);
}
}