微機實現多任務的方式一般是由加載的操作系統來實現的。通過操作系統提供的函數來創建多進程或者多線程來實現多任務方式。由于多進程耗費的資源多,而多線程的開銷相對小的多,因此我們采用單片機模仿多線程的方式來實現。
操作系統創建多個線程后,將管理各個線程占用CPU的時間。操作系統以輪換方式向線程提供CPU時間片,從而使多個線程看起來是同時運行的,而不是等待一個線程執行結束后再去執行下一個線程。
PC(Program Counter,程序計數器)是用于存放下一條指令地址的地方。某個線程正在占用CPU時間,其實是PC值指向該線程所占的內存,并正在逐條取到CPU寄存器中進行運算。該時間片結束后,PC值要指向下一個線程所占用的內存中,進行類似的運算。其他線程都輪流一遍后,將又回到原來那個線程暫停的位置繼續運算。所以,從一個線程轉換到另外一個線程去執行時,要保存此線程的“現場”,包括此線程下一條指令的位置(PC值)、此線程所使用的各個寄存器值等。當此線程又擁有CPU時間時,將保存的PC值賦給PC寄存器,保存的各個寄存器值再賦給各個寄存器。
除了保存“現場”與恢復“現場”外,另外關鍵的一點是,操作系統能夠改變PC值——強制把使用CPU的權限從一個任務切換到另一個任務,這就用到了中斷。微機是用操作系統來管理中斷的,用戶只能間接使用中斷。
二、單片機實現多任務的思路
由上面的介紹,我們知道微機中多線程輪流占用CPU時間,關鍵點在于:
1、保存“現場”與恢復“現場”,即保存和恢復下一條指令的位置和通用寄存器的值。
2、能夠改變PC值,從而可以在多個線程中進行切換,以便同時運行。
在51系列單片機中,如何實現上面的兩個關鍵點呢?
1、保存此“現場”,恢復另一“現場”
給每個任務開辟一個堆棧,各個任務的堆棧不能交叉。各個任務的對應堆棧用于實現以下功能:
1、保存“現場”,在PC離開此任務前保存該任務所用到的通用寄存器值(寄存器A、B、Rn和位寄存器C等)。
2、恢復“現場”,先獲得下一個任務的堆棧地址,然后取出堆棧中所保存的通用寄存器值;
3、在調用子函數時,用以保存下一條指令的地址。
三、 多任務切換的主循環
進入某個任務進行死循環后,程序的主循環流程如圖3所示。當程序進入到某個任務進行死循環時,如上面的任務i,定時器中斷周期發生,發生時意味著該任務的時間片結束,準備執行下一個任務。這些準備工作是在中斷里做的,如圖3所示。首先,應保存此時用到的各個寄存器值,以便下次輪到該任務時取出繼續執行,還要保存棧頂的位置,以便下次能取出所保存的值;然后通過全局變量TaskIndex取得下一個任務的序號,通過任務序號,得到下一個任務的堆棧棧頂的地址,賦給棧頂寄存器SP;然后通過SP取出保存的各個通用寄存器值;,重設定時器值,使中斷能夠再次進行任務切換。
這里重要的是整個思路,沒有比較難的代碼,故沒有貼出代碼。值得提醒的是,保存通用寄存器值時,并不需要保存所有的通用寄存器值,只需要保存任務中用到的就可以。這里解釋前面程序中提及的45H、55H、65H:各個任務堆棧的開始處存儲各個任務的地址,然后再把要保護的寄存器值入棧,棧頂抬高;而要恢復下一個任務時,需將上次保護寄存器后的棧頂值賦給SP寄存器,然后逐個出棧賦值給各個寄存器值,直到棧底處存儲的上次任務暫停處的地址。因為本文的驗證程序只保護了A、B、R0、R2 4個寄存器值,堆棧剛好到達45H、55H、65H。
總結
單片機實現多任務的另一種常用方式是把任務切成小片,然后放在主循環里。這樣,每個循環執行一次各個任務的一小片,從而看起來所有的任務都同時進行。切片的思想是把一個任務細分成多個步驟,而每次只執行其中一小步。如多段數碼管的顯示可以每次只顯示一段,這是更常用的方式,但并不是每個任務都可以切片的。
以上就是粵嵌科技的講師給大家講解的實現多任務執行的方法,如果有更多的關于單片機技術上的問題的話,那么粵嵌科技歡迎大家來我們公司和我們的講師進行面對面的溝通和交流,也可以點擊我們文章下面的獲取試聽資格按鈕來獲取我們的單片機培訓免費資格。