以vTaskDelay()為例子
toggle LED1後以vTaskDelay()阻塞task 100ms,醒來後task A執行了30ms的迴圈
static void task_A (void * pvParameter)
{
while (true)
{
LED1_TOGGLE();// (mark1)
vTaskDelay( pdMS_TO_TICKS(100) );
LED3_TOGGLE();// (mark2)
nrf_delay_ms(30);
LED3_TOGGLE();// (mark3)
}
}
從波形可以看到task A每執行一整個任週期要花費 100+30=130ms
(mark2)到(mark3)的30ms可當成是task在執行程式內容時所花費的時間,只要task程序時間小於週期長度
故依task程式內容而定,task的執行週期將不是固定時間長度
接下來以xTaskDelayUntil()為例子
toggle vTaskDelayUntil()阻塞task 100ms,醒來後task B執行了30ms的迴圈
static void task_B (void * pvParameter)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = pdMS_TO_TICKS(100);
xLastWakeTime = xTaskGetTickCount();
while (true)
{
LED2_TOGGLE();// mark1
vTaskDelayUntil ( &xLastWakeTime, xFrequency );
LED4_TOGGLE();// mark2
nrf_delay_ms(30);
LED4_TOGGLE();// mark3
}
}
可以明顯看出task的程式執行所花費時間並未去影響到下一個task B進入阻塞再喚醒
結論
vTaskDelay()就像是碼錶,每次執行後就重新計數
vTaskDelayUntil()則是像行事曆,依靠著系統時間訂定絕對的排程
這個例子是把上面的task A和B放在一起運行的結果
nrf_Delay_B ⬇falling edge表示task B結束100ms的阻塞,回到Running mode並取後系統使用權
⬆rasing edge即task B完成程序並進入下一個100ms阻塞
因為 優先權 A > B ,會遇到幾個狀況,
1. task A正在使用系統,task B的程序被延後
2. task B執行到一半的程序被逼中斷,系統使用權回到task A身上
task B僅管遇到優先權的亂流,仍不影響整體的週期性表現