張中前
(貴州航天電器股份有限公司,貴州貴陽(yáng),550009)
操作系統(tǒng)是裸機(jī)的第一層軟件,操作系統(tǒng)直接運(yùn)行在硬件上,上層軟件通過(guò)提供應(yīng)用程序接口(API函數(shù)),實(shí)現(xiàn)對(duì)底層硬件的訪問(wèn),同時(shí),通過(guò)操作系統(tǒng)實(shí)現(xiàn)對(duì)多個(gè)上層應(yīng)用軟件(任務(wù))管理,實(shí)現(xiàn)對(duì)硬件CPU管理、存儲(chǔ)管理、I/O接口管理及文件管理,如圖1所示。
圖1 操作系統(tǒng)功能組成示意圖
STM32系列單片機(jī)以其優(yōu)良的價(jià)格,大容量的FLASH及RAM存儲(chǔ)空間,極易用于較為復(fù)雜的控制系統(tǒng);在STM32單片機(jī)上進(jìn)行uC/OS-II實(shí)時(shí)操作系統(tǒng)的移植,提高了產(chǎn)品的設(shè)計(jì)靈活性,實(shí)現(xiàn)較為復(fù)雜的系統(tǒng)功能;通過(guò)將開源的uC/OS-II移植在STM32單片機(jī)上,以其較為低廉的硬件成本獲得較高的使用性能,具有良好的應(yīng)用前景。
uC/OS-II是一個(gè)完整的、可移植、可固化、可剪裁的基于優(yōu)先級(jí)調(diào)度的搶占式實(shí)時(shí)多任務(wù)操作系統(tǒng);它能夠在外界事件或數(shù)據(jù)產(chǎn)生時(shí),能夠接收并以足夠快的速度響應(yīng),其處理的結(jié)果又能夠在規(guī)定的時(shí)間內(nèi)輸出,并控制所有實(shí)時(shí)任務(wù)協(xié)調(diào)、一致運(yùn)行。它包含了基本的任務(wù)調(diào)度、時(shí)間管理、內(nèi)存管理以及任務(wù)之間的通信和同步等功能。
圖2 uC/OS-II文件結(jié)構(gòu)示意圖
uC/OS-II從結(jié)構(gòu)上分為:應(yīng)用軟件、與軟件處理器無(wú)關(guān)的代碼、配置文件、與處理器有關(guān)的移植文件及實(shí)際硬件,uC/OS-II的文件結(jié)構(gòu)如圖2所示。
任務(wù)是uC/OS-II操作系統(tǒng)的基本執(zhí)行單位,是操作系統(tǒng)中的一次執(zhí)行過(guò)程,如產(chǎn)品設(shè)計(jì)中的程序是靜止的,存儲(chǔ)在ROM、硬盤等設(shè)備中;任務(wù)主要由任務(wù)控制塊、任務(wù)堆棧、任務(wù)程序代碼等組成,如圖3所示。
圖3 uC/OS-II任務(wù)組成示意圖
任務(wù)是動(dòng)態(tài)的,存在于產(chǎn)品的RAM或閃存中,其運(yùn)行狀態(tài)可分為睡眠、運(yùn)行、等待、中斷等多個(gè)狀態(tài);每個(gè)任務(wù)可多次重復(fù)執(zhí)行。在產(chǎn)品設(shè)計(jì)時(shí),將產(chǎn)品的應(yīng)用程序設(shè)計(jì)過(guò)程分解,得到多個(gè)任務(wù),并依據(jù)實(shí)際的運(yùn)行過(guò)程,賦予每個(gè)任務(wù)優(yōu)先級(jí),操作系統(tǒng)通過(guò)任務(wù)調(diào)度,實(shí)現(xiàn)產(chǎn)品的功能。在uC/OS-II操作系統(tǒng)中,多個(gè)任務(wù)通過(guò)任務(wù)控制塊組成任務(wù)鏈表, CPU通過(guò)uC/OS-II操作系對(duì)多任務(wù)鏈表任務(wù)進(jìn)行調(diào)度,通過(guò)讀取任務(wù)控制塊中的優(yōu)先級(jí),使高優(yōu)先級(jí)的任務(wù)處于就緒狀態(tài),就緒狀態(tài)的任務(wù)得到執(zhí)行。任務(wù)狀態(tài)切換如圖4所示。
圖4 uC/OS-II任務(wù)狀態(tài)切換示意圖
uC/OS-II每個(gè)時(shí)間段執(zhí)行的任務(wù)只有一個(gè)。通過(guò)調(diào)度,使高優(yōu)先級(jí)任務(wù)得到執(zhí)行,故任務(wù)優(yōu)先級(jí)是CPU執(zhí)行任務(wù)時(shí)選擇的依據(jù)。uC/OS-II對(duì)任務(wù)的執(zhí)行方式是優(yōu)先級(jí)搶占式,在創(chuàng)建任務(wù)時(shí),每個(gè)任務(wù)被分配一個(gè)唯一的優(yōu)先級(jí)。uC/OS-II可以創(chuàng)建多達(dá)64個(gè)任務(wù),采用優(yōu)先級(jí)0~63表示,0為最高優(yōu)先級(jí)。
中斷是嵌入式實(shí)時(shí)操作系統(tǒng)中的重要機(jī)制,當(dāng)CPU正在運(yùn)行任務(wù)時(shí),若有中斷事件發(fā)射管,則CPU暫停當(dāng)前的任務(wù),轉(zhuǎn)向執(zhí)行中斷事件,CPU執(zhí)行完中斷事件后,進(jìn)行一次任務(wù)調(diào)度計(jì)算,若有比中斷更高優(yōu)先級(jí)的任務(wù),則CPU轉(zhuǎn)向執(zhí)行高優(yōu)先級(jí)任務(wù),否則,繼續(xù)執(zhí)行被中斷執(zhí)行的任務(wù)。
是操作系統(tǒng)實(shí)現(xiàn)并發(fā)運(yùn)行的關(guān)鍵,為了使操作系統(tǒng)在一定的時(shí)間內(nèi)執(zhí)行多個(gè)任務(wù),通過(guò)硬件定時(shí)器產(chǎn)生一個(gè)周期性的中斷,作為操作系統(tǒng)處理的系統(tǒng)時(shí)鐘,兩個(gè)時(shí)鐘之間的中斷一般稱為時(shí)鐘節(jié)拍。操作系統(tǒng)中,任務(wù)通過(guò)調(diào)用時(shí)鐘節(jié)拍函數(shù)OSTimeTick();從而進(jìn)入定時(shí)中斷,通過(guò)操作系統(tǒng)中斷管理,實(shí)現(xiàn)對(duì)多任務(wù)的調(diào)度執(zhí)行。
在uC/OS-II操作系統(tǒng)在執(zhí)行多任務(wù)時(shí),需要多個(gè)任務(wù)按照一定的時(shí)間順序配合,完成產(chǎn)品的給定功能,為此,任務(wù)間需要進(jìn)行時(shí)間的同步與信息的交換。uC/OS-II操作系統(tǒng)中,通過(guò)信號(hào)量、郵箱(消息郵箱)和消息隊(duì)列這些被稱作事件的中間環(huán)節(jié)來(lái)實(shí)現(xiàn)任務(wù)間的同步與通信,如圖5所示。
為了把描述事件的數(shù)據(jù)結(jié)構(gòu)統(tǒng)一起來(lái),uC/OS-II使用事件控制塊ECB數(shù)據(jù)結(jié)構(gòu)來(lái)描述諸如信號(hào)量、郵箱(消息郵箱)和消息隊(duì)列這些事件。事件控制塊中包含包括等待任務(wù)表在內(nèi)的所有有關(guān)事件的數(shù)據(jù)。
圖5 任務(wù)通過(guò)事件通信示意圖
uC/OS-II通過(guò)對(duì)內(nèi)存建立分區(qū)、申請(qǐng)及釋放內(nèi)存塊、查詢存儲(chǔ)分區(qū)狀態(tài)信息等方式,實(shí)現(xiàn)對(duì)內(nèi)存的管理,μC/OS-II對(duì)內(nèi)存進(jìn)行兩級(jí)管理,即把一個(gè)大片連續(xù)的內(nèi)存空間分成了若干個(gè)分區(qū),每個(gè)分區(qū)又分成了若干個(gè)大小相等的內(nèi)存塊來(lái)進(jìn)行管理。操作系統(tǒng)以分區(qū)為單位來(lái)管理動(dòng)態(tài)內(nèi)存,而任務(wù)以內(nèi)存塊為單位來(lái)獲得和釋放動(dòng)態(tài)內(nèi)存。內(nèi)存分區(qū)使用一個(gè)二維數(shù)組實(shí)現(xiàn),然后將數(shù)組與內(nèi)存控制塊關(guān)聯(lián),通過(guò)內(nèi)存控制塊組成鏈表,實(shí)現(xiàn)對(duì)內(nèi)存的動(dòng)態(tài)管理,如圖6、圖7所示。
圖6 內(nèi)存的分區(qū)管理示意圖
圖7 內(nèi)存控制塊鏈表示意圖
所謂移植,就是使一個(gè)實(shí)時(shí)操作系統(tǒng)能夠在某個(gè)微處理器平臺(tái)上或微控制器平臺(tái)上運(yùn)行。在2.1節(jié)中介紹了uC/OS-II的文件結(jié)構(gòu),從圖2可見,移植uC/OS-II操作系統(tǒng)時(shí),需要將與CPU有關(guān)的文件進(jìn)行修改,以適應(yīng)在STM32單片機(jī)上的使用。與CPU有關(guān)的三個(gè)文件分別為OS_CPU.H、OS_CPU_C.C、OS_CPU_A.ASM。
OS_CPU.H文件主要定義了與CPU相關(guān)的數(shù)控類型,主要為CPU的類型不同,所對(duì)應(yīng)的操作系統(tǒng)中的數(shù)據(jù)類型占用的存儲(chǔ)空間也不一樣。為了保證可移植性,程序中沒有直接使用C語(yǔ)言中的short、int和long等數(shù)據(jù)類型的定義,因?yàn)樗鼈兣c處理器類型有關(guān),隱含著不可移植性。程序中自己定義了一套數(shù)據(jù)類型,如INT16U表示16位無(wú)符號(hào)整型。對(duì)于ARM這樣的32位內(nèi)核,INT16U是unsigned short型;如果是16位處理器,則是unsingedint型。根據(jù)STM32中數(shù)據(jù)類型及uC/OS-II所需數(shù)據(jù)類型,同時(shí)對(duì)STM32進(jìn)入臨界區(qū)及堆棧方向進(jìn)行定義,對(duì)OS_CPU.H文件修改如下圖8所示。
圖8 OS_CPU.H文件修改
OS_CPU_C.C文件中包含了OSTaskStkInit()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStartHook()及OSTimeHook()共計(jì)6個(gè)函數(shù)。這些函數(shù)中,基于STM32單片機(jī)必須移植的是任務(wù)堆棧初始化函數(shù)OSTaskStkInit()。這個(gè)函數(shù)在任務(wù)創(chuàng)建時(shí)被調(diào)用,負(fù)責(zé)初始化任務(wù)的堆棧結(jié)構(gòu)并返回新堆棧的指針stk。主要對(duì)任務(wù)中需要用到的PC指針以及各個(gè)寄存器進(jìn)行處理,堆棧初始化工作結(jié)束后,返回新的堆棧棧頂指針。該函數(shù)移植修改如圖9所示。
圖9 OS_CPU.H文件修改示意
OS_CPU_A.ASM文件采用匯編語(yǔ)言編制,在移植時(shí),主要對(duì)與CPU有關(guān)的函數(shù)進(jìn)行修改,這些函數(shù)為:高優(yōu)先級(jí)任務(wù)就緒函數(shù)OSStartHighRdy()、任務(wù)切換函數(shù)OSCtxSw()、中斷任務(wù)切換函數(shù)OSIntCtxSw()及時(shí)鐘節(jié)拍中斷服務(wù)函數(shù)OSTickISR()函數(shù)。
OSStartHighRdy()高優(yōu)先級(jí)任務(wù)就緒函數(shù)是在OSStart()多任務(wù)啟動(dòng)之后,負(fù)責(zé)從最高優(yōu)先級(jí)任務(wù)的TCB控制塊中獲得該任務(wù)的堆棧指針SP,并通過(guò)SP依次將CPU現(xiàn)場(chǎng)恢復(fù)。這時(shí)系統(tǒng)就將控制權(quán)交給用戶創(chuàng)建的任務(wù)進(jìn)程,直到該任務(wù)被阻塞或都被其他更高優(yōu)先級(jí)的任務(wù)搶占CPU。該函數(shù)僅僅在多任務(wù)啟動(dòng)時(shí)被執(zhí)行一次,用來(lái)啟動(dòng)最高優(yōu)先級(jí)的任務(wù)執(zhí)行。移植該函數(shù)的原因是,它涉及將處理器寄存器保存到堆棧的操作。
OS_TASK_SW()任務(wù)切換函數(shù)由OSSched()函數(shù)調(diào)用,OSSched()函數(shù)負(fù)責(zé)任務(wù)之間的調(diào)度。OSCtxSw()函數(shù)的工作是,先將當(dāng)前任務(wù)的CPU現(xiàn)場(chǎng)保存到該任務(wù)的堆棧中,然后獲得最高優(yōu)先級(jí)任務(wù)的堆棧指針,并從該堆棧中恢復(fù)此任務(wù)的CPU現(xiàn)場(chǎng),使之繼續(xù)執(zhí)行,該函數(shù)就完了一次任切換。
OSIntCtxSw()中斷任務(wù)切換函數(shù)由OSIntExit()調(diào)用。由于中斷可能會(huì)使更高優(yōu)先級(jí)的任務(wù)進(jìn)入就緒態(tài),因此,為了讓更高優(yōu)先級(jí)的任務(wù)能立即運(yùn)行,在中斷服務(wù)子程序的最后,OSInitExit()函數(shù)會(huì)調(diào)用OSInitCtxSw()做任務(wù)切換。這樣做的目的主要是能夠盡快地讓高優(yōu)先級(jí)的任務(wù)得到響應(yīng),保證系統(tǒng)的實(shí)時(shí)性能。 OSInitCtxSw()與OSCtxSw()都是用于任務(wù)切換函數(shù),其區(qū)別在于,在OSIntCtxSw()中無(wú)需再保存CPU寄存器,因?yàn)樵谡{(diào)用OSIntCtxSw()之前已發(fā)生了中斷,OSIntCtxSw()已將默認(rèn)的CPU寄存器保存到被中斷的任務(wù)堆棧中。
OSTickISR()時(shí)鐘節(jié)拍中斷服務(wù)函數(shù),是特定的周期性中斷,是由硬件定時(shí)器產(chǎn)生的。時(shí)鐘節(jié)拍式中斷使得內(nèi)核可將任務(wù)延時(shí)若干個(gè)整數(shù)時(shí)鐘節(jié)拍,以及當(dāng)任務(wù)等待事件發(fā)生時(shí),提供等待超時(shí)的依據(jù)。時(shí)鐘節(jié)拍頻率越高,系統(tǒng)的額外開銷越大。中斷間的時(shí)間間隔取決于不同的應(yīng)用。OSTickISR()首先將CPU寄存器的值保存在被中斷任務(wù)的堆棧中,之后調(diào)用OSIntEnter()。隨后,OSTickISR()調(diào)用OSTimeTick,檢查所有處于延時(shí)等待狀態(tài)的任務(wù),判斷是否有延時(shí)結(jié)束就緒的任務(wù)。OSTickISR()最后調(diào)用OSIntExit()。如果在中斷中(或其他嵌套的中斷)有更高優(yōu)先級(jí)的任務(wù)就緒,并且當(dāng)前中斷為中斷嵌套的最后一層,那么OSIntExit()將進(jìn)行任務(wù)調(diào)度。
為驗(yàn)證uC/OS-II操作系統(tǒng)移植的成功與否,在STM32開發(fā)板上對(duì)uC/OS-II移植進(jìn)行驗(yàn)證,創(chuàng)建任務(wù)為:
任務(wù)1:LED0燈閃爍點(diǎn)亮;
任務(wù)2:按鍵掃描;
任務(wù)3:任務(wù)2按鍵掃描值通過(guò)信號(hào)量的形式,傳遞給任務(wù)3,按下一次按鍵,實(shí)現(xiàn)LED1燈的一次閃爍點(diǎn)亮;
任務(wù)4:觸摸屏任務(wù),借用開發(fā)板已有程序,采用郵箱形式進(jìn)行任務(wù)間信號(hào)傳遞;
任務(wù)5:主任務(wù),實(shí)現(xiàn)對(duì)觸摸屏的顯示,清除等功能。
創(chuàng)建任務(wù)如圖10所示,任務(wù)執(zhí)行結(jié)果如圖11所示。
圖10 任務(wù)創(chuàng)建示意圖
圖11 uC/OS-II系統(tǒng)移植后程序執(zhí)行結(jié)果示圖
本文介紹了uC/OS-II實(shí)時(shí)操作系統(tǒng)的基本原理,針對(duì)uC/OS-II操作系統(tǒng)在STM32單片機(jī)上的移植進(jìn)行了詳細(xì)說(shuō)明,并對(duì)移植實(shí)例進(jìn)行了分析,取得了良好的效果。本文對(duì)小型系統(tǒng)級(jí)別電子控制組件提供了一種可行的解決方案,對(duì)電子控制組件產(chǎn)品的設(shè)計(jì)具有一定的參考及指導(dǎo)作用。