在單片機上利用一個定時器和二行代碼輕輕鬆鬆實現多任務的運行(基於時間片)

因爲我常用的是stm32F4系列單片機,所以採用其滴答定時器作爲時基定時器(如果你使用的單片機是別款,只要單片機上有個定時器都可以,另外也得有中斷處理函數)(另外如果用的是stm32等單片機,片上具有滴答定時器,可以省掉1、2步驟,在HAL庫下直接用HAL_GetTick()代替GetCount()即可,其他類似)

1.首先初始化定時器,本人一般設置定時時間爲1ms,這個可以是具體情況而定。

2.定義一個全局變量,假設命名爲Count,並初始化爲0;然後再定時器相關的中斷處理函數中進行Count++。

static long long Count = 0;
//定時器初始化,並設定定時時間和中斷使能
void TimInit(){
    ...
}
//其相關的中斷處理函數
void InterHandle(void){
    ....
    Count ++;
}
//防止外界修改Count
long long GetCount(void){
    return Count;
}

3.在相關的頭文件裏定義倆個宏,第一行代碼中的(num)表示任務上一次的運行時刻,然後通過全局的時鐘數減去上一次的運行時刻,再與設定好的時間(ms)進行比較,如果大於等於則表示時間已到可以進行此任務,否則不能進行。當可以進行該任務時,會有num=GetCount()的動作,表示得到當前時間,方便下次判斷下次進此任務。舉個例子:現在12點整,定個明天12點整的鬧鐘,每天循環,然後它會顯示還有24個小時,然後等它到每天12點就響,也就是進鬧鐘任務。類比就是num表示當前時間12點整,getCount()就是系統時鐘,自定義ms就是那個最大間隔24個小時,然後以此循環。

#define _BEGIN(ms)    static long long num = 0; if(GetCount() - num >= ms)do{ num = GetCount()

#define _END()    }while(0)

4.使用方式,先定義一個任務函數,千萬要避免任務函數使用延時函數,不然可能會沒效果的。一般一個任務的運行時間最好把控在所設置的最小時鐘片內,比如我這定時爲1ms,則處理每個任務所花的時間應該比1ms小。如果是在stm32上基本不用過多擔心這個問題,只要不是跑什麼耗時通信協議就好。那如果是在51上的話,那個最小時鐘片還是定大一點比較穩,畢竟51的性能相對32而言是比較低的。

void Task1(void){
    _BEGIN(100);
    
    //doSomeing
    LED1 = ~LED1;//比如讓小燈1每隔100ms閃一下
    _END();
}

void Task2(void){
    _BEGIN(150);
    
    //doSomeing
    LED2 = ~LED2;//比如讓小燈2每隔150ms閃一下
    _END();
}

5.在主函數的while(1){}裏調用任務函數便可簡單的實現多任務了

6.總結,由於整體比較簡單,自然就會有很多缺點了,比如在一個任務函數裏面不能夠再次延時和如果在某個任務太佔時間會影響其它任務等,還得改進,不過這個已經適用很多情景了。如果處理的任務太過複雜,就可以考慮上os了。學習,共勉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章