本節需要掌握以下內容:
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);}
}