問題場景
在FreeRTOS中創建了線程A、線程B,其中線程A優先級大于線程B。線程A、B任務代碼如下:
void A(void *argument)
{
while (1)
{
printf("A\r\n");
HAL_Delay(1000);
}
}
void B(void *argument)
{
while (1)
{
printf("B\r\n");
HAL_Delay(1000);
}
}
燒錄程序后查看串口數據發現只打印了A而不打印B,說明只執行了A線程沒有執行B線程。
問題原因
HAL_Delay是由ST提供的STM32 Cube HAL庫中的一個函數,通常用于在STM32微控制器上實現簡單的延時。HAL_Delay函數使用系統時鐘來進行延時,并且在延時期間會阻塞整個處理器,也就是說,它會使處理器暫時停止執行其他任務和代碼。
在開始運行線程之前,線程A、B處于就緒態,由于線程A優先級比線程B高,FreeRTOS任務控制器優先選擇線程A運行,此時線程A進入運行態。隨后線程A打印A,然后被HAL_Delay函數"阻塞",注意此時的"阻塞"并不意味著程序進入了阻塞態,由于HAL_Delay阻塞的是整個處理器,因此FreeRTOS無法進行其他線程的調度,也就是說,HAL_Delay同時阻塞了線程B。當HAL_Delay函數運行結束后,線程A重回就緒態,由于線程A優先級比線程B高,FreeRTOS任務控制器優先選擇線程A運行,循環往復,線程B不被執行。
解決辦法
osDelay是FreeRTOS(Real-Time Operating System)中的一個函數,用于實現任務的延時。FreeRTOS是一個開源的實時操作系統,專門用于嵌入式系統。osDelay函數允許任務掛起一段時間,然后由操作系統調度器在指定的時間后重新運行該任務。在等待期間,任務會被放入掛起狀態,讓其他任務有機會運行。
也就是說,當調用osDelay時,線程A進入阻塞態,此時任務控制器選擇進入就緒態的線程B執行,循環往復,線程A、B同時被執行。我們可以將任務A和B進行如下改動,即可看到既打印A又打印B。
void A(void *argument)
{
while (1)
{
printf("A\r\n");
osDelay(1000);
}
}
void B(void *argument)
{
while (1)
{
printf("B\r\n");
osDelay(1000);
}
}
使用osDelay可能帶來的問題
觀察一下HAL_Delay和osDelay的函數原型:
/**
* @brief This function provides minimum delay (in milliseconds) based
*/
__weak void HAL_Delay(uint32_t Delay);
/*
Wait for Timeout (Time Delay).
*/
osStatus_t osDelay (uint32_t ticks);
可以看到HAL_Delay函數的目的是提供毫秒級別的延時,意味著當你輸入HAL_Delay(500),硬件會盡量延時精確到500ms的時間。
與之不同的是,osDelay函數的輸入是ticks。ticks是一個計時單位,表示任務將被掛起的時間長度。每個tick的時間取決于FreeRTOS配置的時鐘節拍(tick)周期。例如,如果tick周期為1毫秒,那么傳遞參數ticks為10就會使任務掛起10毫秒。由此可見,osDelay函數延時的時間和一個ticks記時時間長度有很大關系。
那么如何確定ticks具體代表多長時間呢?首先我們應該找到用于配置的頭文件,通常這個頭文件名字叫做FreeRTOSConfig.h。其中,configTICK_RATE_HZ配置選項的值表示每秒鐘系統時鐘節拍(tick)的數量。configTICK_RATE_HZ的值一般默認被設置為1000,表示系統時鐘每秒產生1000個tick,即每個tick的時間間隔為1毫秒,此時osDelay對單個任務延時的時間長度和HAL_Delay近似。
-
程序
+關注
關注
117文章
3787瀏覽量
81038 -
RTOS
+關注
關注
22文章
813瀏覽量
119631 -
FreeRTOS
+關注
關注
12文章
484瀏覽量
62172 -
線程
+關注
關注
0文章
504瀏覽量
19682
發布評論請先 登錄
相關推薦
評論