生活随笔
收集整理的這篇文章主要介紹了
双任务延时原理与空闲任务
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- 1 雙任務延時原理與空閑任務
- 1.1 設計目標
- 1.2 任務延時原理
- 1.3 設計實現(xiàn)
1 雙任務延時原理與空閑任務
1.1 設計目標
目標:提供一個任務延時接口,使得延時過程中可放棄CPU而轉而運行其它任務,提高CPU利用率。
1.2 任務延時原理
在整個延時過程中,任務暫停運行,釋放CPU的控制權給其它任務:
- 開始時,啟動定時器,暫停任務運行:
- 計時結束,關閉計時器,恢復任務運行。
任務數(shù)量不限,而硬件計時器資源數(shù)量非常有限,不得不采用“軟計時器”,如下:
對于硬件定時器: - 使用SysTick,RTOS啟動后立即啟動。
- 周期性的中斷修改計時器計數(shù)值。
- 中斷處理需要時間,所以不能太過頻繁,如10ms。
對于軟計時器:
延時精度問題:
- 由于使用“軟計時器”,加之延時處理需要時間,所以延時精度有限,使用時需要注意場合。
空閑任務的引入:
- 如果所有任務都進入延時狀態(tài),那么RTOS應該運行什么呢?我們可以設計一個空閑任務,可以簡化RTOS的代碼結構,可以在空閑任務中方便的添加自定義代碼。
1.3 設計實現(xiàn)
為任務添加計時器:
添加空閑任務:
在時鐘節(jié)拍中斷中遞減計時器,并調(diào)用tTaskSched()切換任務:
最后修改tTaskSched(),僅切換到delayTicks數(shù)為0的任務運行。
添加延時接口taskDelay():
核心代碼如下:
#include "tinyOS.h"
#include "ARMCM3.h"
tTask
* currentTask
;
tTask
* nextTask
;
tTask
* idleTask
;
tTask
* taskTable
[2];
void tTaskInit
(tTask
* task
, void (*entry
)(void *), void *param
, uint32_t
* stack
)
{*(--stack
) = (unsigned long)(1<<24); *(--stack
) = (unsigned long)entry
; *(--stack
) = (unsigned long)0x14; *(--stack
) = (unsigned long)0x12; *(--stack
) = (unsigned long)0x3; *(--stack
) = (unsigned long)0x2; *(--stack
) = (unsigned long)0x1; *(--stack
) = (unsigned long)param
; *(--stack
) = (unsigned long)0x11; *(--stack
) = (unsigned long)0x10; *(--stack
) = (unsigned long)0x9; *(--stack
) = (unsigned long)0x8; *(--stack
) = (unsigned long)0x7; *(--stack
) = (unsigned long)0x6; *(--stack
) = (unsigned long)0x5; *(--stack
) = (unsigned long)0x4; task
->stack
= stack
; task
->delayTicks
= 0;
}
void tTaskSched
()
{ if (currentTask
== idleTask
) {if (taskTable
[0]->delayTicks
== 0) {nextTask
= taskTable
[0];} else if (taskTable
[1]->delayTicks
== 0) {nextTask
= taskTable
[1];} else {return;}} else {if (currentTask
== taskTable
[0]) {if (taskTable
[1]->delayTicks
== 0) {nextTask
= taskTable
[1];}else if (currentTask
->delayTicks
!= 0) {nextTask
= idleTask
;} else {return;}}else if (currentTask
== taskTable
[1]) {if (taskTable
[0]->delayTicks
== 0) {nextTask
= taskTable
[0];}else if (currentTask
->delayTicks
!= 0) {nextTask
= idleTask
;}else {return;}}}tTaskSwitch();
}
void tTaskSystemTickHandler
()
{int i
;for (i
= 0; i
< 2; i
++) {if (taskTable
[i
]->delayTicks
> 0){taskTable
[i
]->delayTicks
--;}}tTaskSched();
}
void tTaskDelay
(uint32_t delay
) {currentTask
->delayTicks
= delay
;tTaskSched();
}
void tSetSysTickPeriod(uint32_t ms
)
{SysTick
->LOAD
= ms
* SystemCoreClock
/ 1000 - 1; NVIC_SetPriority
(SysTick_IRQn
, (1<<__NVIC_PRIO_BITS
) - 1);SysTick
->VAL
= 0; SysTick
->CTRL
= SysTick_CTRL_CLKSOURCE_Msk
|SysTick_CTRL_TICKINT_Msk
|SysTick_CTRL_ENABLE_Msk
;
}
void SysTick_Handler
()
{tTaskSystemTickHandler();
}
int task1Flag
;
void task1Entry
(void * param
)
{tSetSysTickPeriod(10);for (;;) {task1Flag
= 1;tTaskDelay(1);task1Flag
= 0;tTaskDelay(1);}
}int task2Flag
;
void task2Entry
(void * param
)
{for (;;) {task2Flag
= 1;tTaskDelay(1);task2Flag
= 0;tTaskDelay(1);}
}
tTask tTask1
;
tTask tTask2
;
tTaskStack task1Env
[1024];
tTaskStack task2Env
[1024];
tTask tTaskIdle
;
tTaskStack idleTaskEnv
[1024];void idleTaskEntry
(void * param
) {for (;;){}
}int main
()
{tTaskInit(&tTask1
, task1Entry
, (void *)0x11111111, &task1Env
[1024]);tTaskInit(&tTask2
, task2Entry
, (void *)0x22222222, &task2Env
[1024]);taskTable
[0] = &tTask1
;taskTable
[1] = &tTask2
;tTaskInit(&tTaskIdle
, idleTaskEntry
, (void *)0, &idleTaskEnv
[1024]);idleTask
= &tTaskIdle
;nextTask
= taskTable
[0];tTaskRunFirst();return 0;
}
參考資料:
【李述銅】從0到1自己動手寫嵌入式操作系統(tǒng)
總結
以上是生活随笔為你收集整理的双任务延时原理与空闲任务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。