李燕,馬強(qiáng),鄧凱旋
(華北科技學(xué)院電子信息工程學(xué)院,北京,065201)
上世紀(jì)70年代開(kāi)始出現(xiàn)嵌入式系統(tǒng),距今已有近50年的歷史。傳統(tǒng)的嵌入式裸機(jī)開(kāi)發(fā)運(yùn)行的程序代碼一般由一個(gè)main函數(shù)中的while死循環(huán)和各種中斷服務(wù)程序組成,異常情況或者需要執(zhí)行其他任務(wù)時(shí),通過(guò)調(diào)用中斷服務(wù)程序進(jìn)行處理,沒(méi)有多任務(wù)、線程的概念。但是引入操作系統(tǒng)后,程序執(zhí)行時(shí)可以把一個(gè)應(yīng)用程序分割為多個(gè)任務(wù),且系統(tǒng)內(nèi)核支持搶占式、合作式和時(shí)間片輪轉(zhuǎn)調(diào)度,極大地提高了系統(tǒng)實(shí)時(shí)性,降低了軟件開(kāi)發(fā)難度。操作系統(tǒng)根據(jù)任務(wù)的優(yōu)先級(jí),通過(guò)任務(wù)調(diào)度器使CPU分時(shí)執(zhí)行各個(gè)任務(wù),保證每個(gè)任務(wù)都能夠高效執(zhí)行[1]。因此基于操作系統(tǒng)的嵌入式開(kāi)發(fā)受到越來(lái)越多的開(kāi)發(fā)者的青睞。
基于實(shí)時(shí)操作系統(tǒng)的軟件開(kāi)發(fā),由系統(tǒng)進(jìn)行多任務(wù)的管理與調(diào)度。如果任務(wù)設(shè)計(jì)不合理,將會(huì)出現(xiàn)任務(wù)運(yùn)行不穩(wěn)定、通信的實(shí)時(shí)性差等嚴(yán)重后果,所以軟件結(jié)構(gòu)與多任務(wù)的同步與通信機(jī)制是基于操作系統(tǒng)的嵌入式開(kāi)發(fā)的難點(diǎn)和關(guān)鍵點(diǎn)[2]。FreeRTOS是實(shí)時(shí)操作系統(tǒng)的一種,該系統(tǒng)免費(fèi)而且開(kāi)源,高可移植性,主要用C語(yǔ)言編寫(xiě);可以在資源有限的微控制器中運(yùn)行,并且提供了用于低功耗的Tickless模式。本文以FreeRTOS為對(duì)象,對(duì)其同步與通信機(jī)制做了介紹,并在煤礦井下一氧化碳濃度監(jiān)測(cè)報(bào)警裝置的設(shè)計(jì)中應(yīng)用。
多任務(wù)管理是FreeRTOS系統(tǒng)的核心,采用了“分而治之”的思想,把大問(wèn)題分解為許多個(gè)小問(wèn)題,對(duì)其逐個(gè)擊破,大問(wèn)題也就迎刃而解;各個(gè)任務(wù)均以并發(fā)的方式處理,由任務(wù)調(diào)度器決定任務(wù)執(zhí)行。FreeRTOS是基于搶占式內(nèi)核的系統(tǒng),高優(yōu)先級(jí)的任務(wù)可以打斷低優(yōu)先級(jí)的任務(wù)運(yùn)行,低優(yōu)先級(jí)任務(wù)必須等高優(yōu)先級(jí)任務(wù)運(yùn)行完成之后,才能獲得CPU的使用權(quán)。
FreeRTOS系統(tǒng)內(nèi)核擁有隊(duì)列、信號(hào)量和事件標(biāo)志組來(lái)完成不同任務(wù)之間,任務(wù)與中斷之間的消息傳遞。消息隊(duì)列通常采用先進(jìn)先出(FIFO)的存儲(chǔ)緩沖機(jī)制,完成任務(wù)與任務(wù)、任務(wù)與中斷間的消息傳遞;信號(hào)量分為二制信號(hào)量、計(jì)數(shù)型信號(hào)量、互斥信號(hào)量和遞歸互斥信號(hào)量;主要用來(lái)完成共享資源訪問(wèn)和任務(wù)同步的功能;事件標(biāo)志組通過(guò)事件編號(hào)訪問(wèn)事件,用于實(shí)現(xiàn)多個(gè)任務(wù)或事件的同步。
隊(duì)列擁有獨(dú)立權(quán)限的內(nèi)核對(duì)象,本身并不屬于或賦予任何任務(wù)。任何任務(wù)均可向同一隊(duì)列寫(xiě)入或者讀出。隊(duì)列是為了任務(wù)與任務(wù)、任務(wù)與中斷之間的通信而準(zhǔn)備的,可以在任務(wù)與任務(wù)、任務(wù)與中斷之間傳遞消息,隊(duì)列中可以存儲(chǔ)有限的、大小固定的數(shù)據(jù)項(xiàng)目,也可以發(fā)送不定長(zhǎng)消息的場(chǎng)合。任務(wù)與任務(wù)、任務(wù)與中斷之間要交流的數(shù)據(jù)保存在隊(duì)列中,叫做隊(duì)列項(xiàng)目。隊(duì)列所能保存的最大數(shù)據(jù)項(xiàng)目數(shù)量叫做隊(duì)列的長(zhǎng)度,創(chuàng)建隊(duì)列的時(shí)候會(huì)指定數(shù)據(jù)項(xiàng)目的大小和隊(duì)列的長(zhǎng)度。通過(guò)字節(jié)拷貝將數(shù)據(jù)復(fù)制存儲(chǔ)到隊(duì)列中完成往隊(duì)列中寫(xiě)入數(shù)據(jù)的任務(wù);通過(guò)將隊(duì)列中的數(shù)據(jù)拷貝刪除完成從隊(duì)列中讀出數(shù)據(jù)的任務(wù)。讀寫(xiě)隊(duì)列均會(huì)指定一個(gè)阻塞超時(shí)時(shí)間,在這段時(shí)間里,任務(wù)將保持阻塞態(tài)等待隊(duì)列數(shù)據(jù)有效;當(dāng)?shù)却臅r(shí)間超過(guò)了阻塞超時(shí)時(shí)間,任務(wù)也會(huì)由阻塞態(tài)轉(zhuǎn)為就緒態(tài)。
FreeRTOS總共含有14個(gè)對(duì)消息隊(duì)列進(jìn)行處理的函數(shù),但是一般在使用時(shí)只需配置主要幾個(gè)函數(shù)即可,主要有動(dòng)態(tài)或靜態(tài)創(chuàng)建隊(duì)列、向隊(duì)列發(fā)送消息、隊(duì)列上鎖和解鎖,從隊(duì)列讀取消息。在使用隊(duì)列之前,必須創(chuàng)建隊(duì)列,隊(duì)列創(chuàng)建有兩種方法,一種靜態(tài)創(chuàng)建,使用函數(shù)xQueueCreate Static();另一種是動(dòng)態(tài)創(chuàng)建,使用函數(shù)xQueueCreate();兩者的區(qū)別在于:使用靜態(tài)創(chuàng)建隊(duì)列時(shí),需要用戶自行分配內(nèi)存,動(dòng)態(tài)創(chuàng)建則不需要。隊(duì)列是用來(lái)存儲(chǔ)消息的,因此必須要給消息分配存儲(chǔ)區(qū)。FreeRTOS使用參數(shù)uxQueuelength(隊(duì)列長(zhǎng)度)和uxItemsize(消息長(zhǎng)度)來(lái)指定存儲(chǔ)區(qū)域的大小。創(chuàng)建成功返回隊(duì)列句柄,創(chuàng)建失敗返回NULL。
信號(hào)量可以用于兩種場(chǎng)合,一是控制控制共享資源的訪問(wèn),二是任務(wù)同步。信號(hào)量在控制共享資源訪問(wèn)的過(guò)程中相當(dāng)于上鎖機(jī)制,任務(wù)只有獲得開(kāi)鎖的鑰匙才能獲得對(duì)共享資源的訪問(wèn)權(quán)。在任務(wù)同步場(chǎng)合中,信號(hào)量用來(lái)執(zhí)行任務(wù)與任務(wù),任務(wù)與中斷之間的同步。信號(hào)量可以分為二值信號(hào)量和計(jì)數(shù)型信號(hào)量。
2.2.1 二值信號(hào)量
二值信號(hào)量其實(shí)就是一個(gè)只有一個(gè)隊(duì)列項(xiàng)的隊(duì)列,這個(gè)特殊的隊(duì)列要么是滿的,要么是空的,所以在處理中斷與任務(wù)同步中,經(jīng)常使用隊(duì)列來(lái)代替二值信號(hào)量。下面三個(gè)步驟演示了二值信號(hào)量的工作過(guò)程:
(1)二值信號(hào)量無(wú)效
圖1中任務(wù)Task通過(guò)函數(shù)xSemaphoreTake()獲得該信號(hào)量,因?yàn)榇藭r(shí)二值信號(hào)量處于無(wú)效狀態(tài),所以任務(wù)Task進(jìn)入阻塞態(tài)。
圖1 請(qǐng)求二值信號(hào)量
(2)中斷釋放信號(hào)量
當(dāng)中斷發(fā)生時(shí),在中斷服務(wù)函數(shù)中通過(guò)圖2函數(shù)xSem aphoreGiveFromISR()釋放信號(hào)量,所以此時(shí)信號(hào)量變?yōu)橛行顟B(tài)。
圖2 釋放信號(hào)量
(3)任務(wù)成功獲取信號(hào)量
此時(shí)信號(hào)量已經(jīng)有效,任務(wù)Task獲取信號(hào)量成功,阻塞態(tài)解除,可以執(zhí)行任務(wù)。
圖3 任務(wù)請(qǐng)求信號(hào)量成功
2.2.2 計(jì)數(shù)型信號(hào)量
計(jì)數(shù)型信號(hào)量從本質(zhì)上講就是長(zhǎng)度大于1的隊(duì)列,用戶并不需要知道隊(duì)列中存儲(chǔ)了什么數(shù)據(jù),只需要知道隊(duì)列是否為空即可。計(jì)數(shù)型信號(hào)量常用于兩種場(chǎng)合,一是事件計(jì)數(shù),二是資源管理。在事件計(jì)數(shù)場(chǎng)合中,每當(dāng)有事件發(fā)生就在事件處理函數(shù)中增加信號(hào)量的計(jì)數(shù)值,其他任務(wù)信號(hào)量計(jì)數(shù)值減1。不同場(chǎng)合中,信號(hào)量值所代表的意思也不進(jìn)行同。在計(jì)數(shù)場(chǎng)合中,信號(hào)量值就是隊(duì)列結(jié)構(gòu)體成員變量uxMessagesWaiting,所創(chuàng)建的計(jì)數(shù)型信號(hào)量初始計(jì)數(shù)值為0。在資源管理場(chǎng)合中,信號(hào)量值代表當(dāng)前資源的可用數(shù)量。任何任務(wù)想要獲得資源的使用權(quán),必須首先獲取信號(hào)量,獲取成功之后信號(hào)量值就會(huì)減1。信號(hào)量值為0時(shí)說(shuō)明此時(shí)已經(jīng)沒(méi)有資源了。每個(gè)任務(wù)使用完資源之后一定要將信號(hào)量釋放,這樣信號(hào)量值才會(huì)加1。在該場(chǎng)合中創(chuàng)建的信號(hào)量值的初始值應(yīng)該是資源的數(shù)量。
2.2.3 互斥信號(hào)量
優(yōu)先級(jí)翻轉(zhuǎn)問(wèn)題經(jīng)常在可剝奪內(nèi)核系統(tǒng)中出現(xiàn),在這種情況下,高優(yōu)先級(jí)任務(wù)要一直等待低優(yōu)先級(jí)任務(wù)釋放占用的共享資源,而實(shí)際情況是中優(yōu)先級(jí)的任務(wù)剝奪了低優(yōu)先級(jí)任務(wù)對(duì)CPU的使用權(quán),使得高優(yōu)先級(jí)任務(wù)無(wú)法先于中優(yōu)先級(jí)任務(wù)使用共享資源,導(dǎo)致優(yōu)先級(jí)翻轉(zhuǎn)。FreeRTOS中的互斥信號(hào)量實(shí)質(zhì)上是一種擁有優(yōu)先級(jí)繼承的二值信號(hào)量,非常適合應(yīng)用在需要互斥訪問(wèn)的任務(wù)與任務(wù)或中斷與任務(wù)之間的同步?;コ庑盘?hào)量具有優(yōu)先級(jí)繼承的特性。當(dāng)一個(gè)互斥信號(hào)量正在被一個(gè)低優(yōu)先級(jí)的任務(wù)使用時(shí),此時(shí)有個(gè)高優(yōu)先級(jí)的任務(wù)需要獲得該信號(hào)量時(shí)就會(huì)被阻塞。但是在互斥信號(hào)量中高優(yōu)先級(jí)的任務(wù)會(huì)將低優(yōu)先級(jí)的任務(wù)提升到與自己相同的優(yōu)先級(jí),即優(yōu)先級(jí)繼承特性。該特性是通過(guò)降低高優(yōu)先級(jí)任務(wù)處于阻塞態(tài)的時(shí)間,將“優(yōu)先級(jí)翻轉(zhuǎn)”的影響降到最低。但是優(yōu)先級(jí)繼承不能完全解決優(yōu)先級(jí)翻轉(zhuǎn)的問(wèn)題,它只是盡可能降低優(yōu)先級(jí)翻轉(zhuǎn)帶來(lái)的影響。在使用互斥信號(hào)量時(shí)必須注意的是它只能在任務(wù)中使用,不能用于中斷服務(wù)函數(shù)中。
前述使用信號(hào)量進(jìn)行同步中,任務(wù)只能與一個(gè)任務(wù)或者事件進(jìn)行同步。在需要多個(gè)任務(wù)或者事件同步的應(yīng)用場(chǎng)景中,信號(hào)量就束手無(wú)策了。FreeRTOS采用事件標(biāo)志組解決該問(wèn)題。一個(gè)事件組就是一組的事件位,通過(guò)編號(hào)訪問(wèn)事件位。事件位用來(lái)標(biāo)明某個(gè)事件是否發(fā)生,可以當(dāng)作事件標(biāo)志。收到一條消息并且已經(jīng)將這條消息進(jìn)行了處理就可以將該消息的標(biāo)志位置1,當(dāng)隊(duì)列中沒(méi)有需要處理的消息時(shí)將該位置0;事件標(biāo)志組的第零位表示隊(duì)列中的消息是否進(jìn)行處理;事件標(biāo)志組的第一位表示是否有消息需要從網(wǎng)絡(luò)中發(fā)送出去;事件標(biāo)志組的第二位表示是否需要向網(wǎng)絡(luò)發(fā)送心跳信息。
事件標(biāo)志組為EventGroupHandle_t結(jié)構(gòu)體類型,其可以存儲(chǔ)8、24或者32個(gè)事件位,但對(duì)于STM32內(nèi)核而言,一個(gè)事件標(biāo)志組最多可以存儲(chǔ)24個(gè)事件位。
設(shè)計(jì)了一套基于FreeRTOS實(shí)時(shí)操作系統(tǒng)、以STM32 F407ZGT6為核心的一氧化碳濃度檢測(cè)和報(bào)警裝置,如圖4所示。該裝置可以實(shí)時(shí)檢測(cè)煤礦井下環(huán)境中一氧化碳濃度,采用紅外遙控裝置可以實(shí)現(xiàn)遠(yuǎn)程修改一氧化碳濃度報(bào)警值,方便工作人員操作。該檢測(cè)報(bào)警裝置基于實(shí)時(shí)多任務(wù)系統(tǒng),顯示任務(wù)、報(bào)警任務(wù)、RS485接收與發(fā)送任務(wù)的協(xié)調(diào)與配合的同步通信機(jī)制就是上述機(jī)制。
根據(jù)煤礦井下的特殊環(huán)境要求,本設(shè)計(jì)采用了NE-COBL這款工業(yè)級(jí)一氧化碳傳感器,其具有良好的應(yīng)答性和較高的輸出電流,可達(dá)到80Na/ppm至110Na/ppm;能夠輕松應(yīng)對(duì)復(fù)雜氣體;線性度較高,在清潔大氣中的輸出值小于10ppm;使用壽命長(zhǎng),達(dá)2年以上,穩(wěn)定性強(qiáng);性價(jià)比較高。
該系統(tǒng)基于實(shí)時(shí)多任務(wù)系統(tǒng),其顯示任務(wù)、運(yùn)行狀態(tài)更新任務(wù)、紅外遙控任務(wù)、RS485接收與發(fā)送任務(wù)等的同步通信由前文所述的通信機(jī)制協(xié)調(diào)配合來(lái)實(shí)現(xiàn)。程序中使用了模擬量采集消息對(duì)列、RS485接收與發(fā)送消息二值信號(hào)量,設(shè)計(jì)創(chuàng)建了二值信號(hào)量RS485接收消息隊(duì)列和RS485發(fā)送消息隊(duì)列。軟件設(shè)計(jì)總體結(jié)構(gòu)框圖設(shè)計(jì)如圖4所示。
圖4 軟件設(shè)計(jì)總體框圖
(1)任務(wù)開(kāi)始函數(shù)START_TASK():任務(wù)開(kāi)始函數(shù)主要用來(lái)創(chuàng)建其他任務(wù),執(zhí)行完任務(wù)開(kāi)始函數(shù),該任務(wù)將會(huì)被vTaskDelete(StartTask_Handler)刪除并退出臨界區(qū)。開(kāi)始任務(wù)函數(shù)的優(yōu)先級(jí)設(shè)置為1,任務(wù)堆棧大小為128個(gè)字節(jié)。通過(guò)調(diào)用vTaskStartScheduler()函數(shù)開(kāi)始任務(wù)調(diào)度。
(2)二值信號(hào)量RS485_BinarySemaphore=xSemaph oreCreateBinary():敏感元件采集到的信號(hào)經(jīng)調(diào)理電路處理后連接到STM32處理器的PC0引腳,即AD轉(zhuǎn)換的通道10,將PC0配置為模擬量輸入模式,對(duì)模擬信號(hào)連續(xù)轉(zhuǎn)換十次并取其平均值,以減小轉(zhuǎn)換誤差,經(jīng)數(shù)據(jù)換算后將結(jié)果通過(guò)消息隊(duì)列傳輸至模式處理任務(wù)以實(shí)現(xiàn)濃度顯示,然后判斷濃度是否超過(guò)設(shè)定的報(bào)警值以決定是否觸發(fā)聲光報(bào)警。任務(wù)最后判斷是否獲取到RS485處理任務(wù)發(fā)送的請(qǐng)求數(shù)據(jù)信號(hào)量,若信號(hào)量獲取成功,則將當(dāng)前濃度發(fā)送至RS485處理任務(wù)。
(3)消息隊(duì)列 Message_RS485RXD_Queue():該 消息隊(duì)列用于讀取RS485總線上的消息。QueueHandle_t Key_value_Queue():按鍵掃描消息隊(duì)列QueueHandle_tAnalog_model_Queue():模擬模式消息隊(duì)列;隊(duì)列不是屬于某個(gè)特別指定的任務(wù)的,任何任務(wù)都可以向隊(duì)列中發(fā)送消息,或者從隊(duì)列中讀取消息。
基于FreeRTOS同步與通信機(jī)制的CO濃度檢測(cè)設(shè)計(jì)中,系統(tǒng)功能由各種實(shí)時(shí)任務(wù)協(xié)調(diào)配合完成,根據(jù)實(shí)際需求設(shè)置任務(wù)執(zhí)行順序的先后,由FreeRTOS操作系統(tǒng)內(nèi)核解決任務(wù)間同步與通信問(wèn)題。該系統(tǒng)實(shí)現(xiàn)了界面顯示、監(jiān)控報(bào)警以及RS485通信等功能,實(shí)際使用中證明了該系統(tǒng)具有較強(qiáng)的穩(wěn)定性和良好的實(shí)時(shí)性?;贔reeRTOS系統(tǒng)不僅完成了任務(wù)間的協(xié)調(diào)配合,也使得程序開(kāi)發(fā)相對(duì)容易,對(duì)嵌入式裝置的研究與開(kāi)發(fā)具有重要意義。