1 引言
μC/OS-II是由美國(guó)人Jean Labrosse 編寫的一個(gè)源碼公開的嵌入式實(shí)時(shí)操作系統(tǒng)內(nèi)核。它從1992年開始為人所知。μC/OS-II是一種占先式的多任務(wù)操作系統(tǒng),可固化,可裁減,移植性好。μC/OS-II功能強(qiáng)大,支持56個(gè)用戶任務(wù),支持信號(hào)量、消息郵箱、消息隊(duì)列等多種常用的進(jìn)程間通信機(jī)制,現(xiàn)已成功應(yīng)用到眾多商業(yè)嵌入式系統(tǒng)中,其穩(wěn)定性與可靠性已經(jīng)得到檢驗(yàn)[1]。
各類電動(dòng)車的研究與開發(fā)目前在國(guó)內(nèi)已經(jīng)掀起了高潮,國(guó)家、地方以及越來(lái)越多的汽車公司都投入到這個(gè)前途光明的朝陽(yáng)產(chǎn)業(yè)的研究中。混合動(dòng)力電動(dòng)車、燃料電池純電動(dòng)車是當(dāng)前研發(fā)的主要方向。蓄電池不可避免地成為電動(dòng)車輔助能源。鎳氫電池、鋰離子電池等因?yàn)槠淙萘看蟆Ⅲw積小、動(dòng)力性較好而成為目前電動(dòng)車研發(fā)的首選動(dòng)力電池。對(duì)電池的過充電過放電很容易造成電池的損壞,并大大降低電池壽命。而如何能根據(jù)所用電池的特性,對(duì)其安全有效的使用即電池管理系統(tǒng)(Battery Management System,BMS)的設(shè)計(jì)成為關(guān)鍵。BMS負(fù)責(zé)實(shí)時(shí)地估測(cè)當(dāng)前的電池容量,即荷電狀態(tài)(State of Charge,SOC),以及對(duì)各電池組進(jìn)行電壓均衡,判斷是否出現(xiàn)不正常電池單元,并發(fā)送報(bào)警信號(hào)。SOC估測(cè)方法的準(zhǔn)確性已成為電動(dòng)車研發(fā)的瓶頸之一,在世界范圍內(nèi)都未取得重大突破。限于篇幅,本文對(duì)SOC估測(cè)方法不做詳細(xì)介紹,而主要描述電池管理系統(tǒng)的軟硬件實(shí)現(xiàn)。
2 BMS的構(gòu)成與硬件實(shí)現(xiàn)
2.1 基于光纖CAN總線的電動(dòng)車分布式控制系統(tǒng)
電池管理系統(tǒng)BMS是電動(dòng)車控制系統(tǒng)的組成部分之一??刂凭钟蚓W(wǎng)CAN總線因?yàn)槠浣Y(jié)構(gòu)簡(jiǎn)單,通信方式靈活,抗干擾能力強(qiáng),目前已經(jīng)在工業(yè)控制,汽車電子領(lǐng)域得到了廣泛的應(yīng)用。CAN總線最初即是德國(guó)的Bosch公司為汽車的監(jiān)測(cè)、控制系統(tǒng)而設(shè)計(jì)的。CAN網(wǎng)絡(luò)在電動(dòng)車上的應(yīng)用能使得各電控單元(ECU)之間的通信極為方便。如果通信介質(zhì)采用光纖,那么通信介質(zhì)上的干擾將被完全消除。本文所描述的對(duì)電池管理系統(tǒng)的研究是燃料電池電動(dòng)車研發(fā)的子課題。電池采用的是容量為12安時(shí)(AH)的鎳氫電池。
電動(dòng)車控制系統(tǒng)一般包括能量流管理系統(tǒng),電機(jī)控制器,燃料電池控制器,顯示系統(tǒng),電池管理系統(tǒng)等,若為混合動(dòng)力車,還應(yīng)包括發(fā)動(dòng)機(jī)控制器等其他控制器。本文所描述的鎳氫電池管理系統(tǒng)ECU(Electronic control unit)與這些控制系統(tǒng)采用光纖構(gòu)成上層CAN網(wǎng)。而電池管理系統(tǒng)ECU又與24組電池組信息檢測(cè)ECU構(gòu)成下層CAN網(wǎng)絡(luò)。我們所采用的鎳氫電池每個(gè)基本電池單元提供1.2V左右的電壓,10個(gè)單元串聯(lián)構(gòu)成一個(gè)電池組,24個(gè)電池組再串聯(lián)產(chǎn)生約280V的高電壓,作為車用輔助電源。設(shè)計(jì)的電池管理系統(tǒng)BMS及電動(dòng)車控制系統(tǒng)基本結(jié)構(gòu)如圖1所示。
2.2 電池管理ECU的硬件方案
電池管理ECU采用TI公司的TMS320LF2407 DSP作為其CPU。主要原因在于其體積小,處理速度快,片內(nèi)集成了A/D模數(shù)轉(zhuǎn)換器和CAN總線控制器[2]。如圖1所示,電池管理ECU需要兩個(gè)CAN控制器。DSP內(nèi)部集成的CAN控制器(CAN1)接上層光纖CAN網(wǎng)絡(luò);我們?yōu)橄到y(tǒng)另外擴(kuò)展的Philip公司的SJA1000獨(dú)立CAN控制器(CAN2)作為與下層電池組CAN網(wǎng)絡(luò)通信用。電池管理ECU的結(jié)構(gòu)框圖如圖2所示。
由于DSP的數(shù)據(jù)和地址線是分開的,而SJA1000的數(shù)據(jù)和地址線是分時(shí)復(fù)用的。其相互接口是本系統(tǒng)的難點(diǎn)之一。可通過將SJA1000映射為DSP的I/O地址,通過模擬SJA1000的讀寫時(shí)序?qū)ζ溥M(jìn)行讀寫訪問。
3 采用前后臺(tái)系統(tǒng)的軟件設(shè)計(jì)方法
在前后臺(tái)系統(tǒng)中,應(yīng)用程序被設(shè)計(jì)成一個(gè)無(wú)限的循環(huán),循環(huán)中調(diào)用相應(yīng)的函數(shù)完成相應(yīng)的操作,這部分可看作是后臺(tái)行為。中斷服務(wù)程序處理異步事件,這部分可看作是前臺(tái)行為。后臺(tái)行為也稱作任務(wù)級(jí),前臺(tái)也稱作中斷級(jí)。時(shí)間相關(guān)性很強(qiáng)的工作一般是靠中斷服務(wù)子程序來(lái)保證的。中斷服務(wù)所提供的信息(如標(biāo)志)一直要等到后臺(tái)程序(即循環(huán))運(yùn)行到處理該信息這一步時(shí)才能得到處理。這中間的時(shí)間間隔稱任務(wù)級(jí)響應(yīng)時(shí)間。這個(gè)時(shí)間具有不確定性,有時(shí)候會(huì)很長(zhǎng)。可見前后臺(tái)系統(tǒng)的實(shí)時(shí)性較差。
本系統(tǒng)的軟件須完成的主要功能包括:中斷方式接收24個(gè)電池組的ECU通過下層CAN總線傳出的電壓與溫度信息,并對(duì)數(shù)據(jù)進(jìn)行處理;定時(shí)采樣電池的總電壓與電流(采樣頻率越高則SOC估測(cè)效果越好);通過電壓、電流、溫度等信息通過一定的算法計(jì)算電池SOC值;每隔50ms通過上層光纖CAN總線向控制系統(tǒng)中其他CAN節(jié)點(diǎn)發(fā)送一次SOC值以及其他信息;每隔1s通過上層光纖CAN總線發(fā)送一次所接收的電池組的電壓溫度信息;對(duì)電壓偏高或偏低的電池組進(jìn)行電壓均衡;監(jiān)測(cè)不正常情況,隨時(shí)發(fā)送報(bào)警信號(hào)。
若采用前后臺(tái)的方法對(duì)本系統(tǒng)進(jìn)行軟件設(shè)計(jì),有兩種方案供選擇。其一,可以將所有的工作都在后臺(tái)的無(wú)限循環(huán)中處理,中斷服務(wù)服務(wù)程序只提供標(biāo)志信息。這樣也就會(huì)出現(xiàn)上文所述的任務(wù)級(jí)響應(yīng)時(shí)間的不確定性,實(shí)時(shí)性較差。其二,可以將大部分的工作,如A/D采樣,SOC算法,CAN數(shù)據(jù)發(fā)送等系統(tǒng)中大部分的工作都在中斷服務(wù)程序中處理。這種方法看起來(lái)實(shí)時(shí)性很好,但由于處理中斷服務(wù)程序的時(shí)間較長(zhǎng),關(guān)中斷的時(shí)間也就較長(zhǎng),所以不可避免的會(huì)引起中斷事件的頻繁丟失。
而若采用μC/OS-II操作系統(tǒng)進(jìn)行軟件設(shè)計(jì),則所有的函數(shù)與任務(wù)的處理與執(zhí)行時(shí)間具有可確定性,因而系統(tǒng)的可靠性將大大提高。下文筆者將詳細(xì)介紹嵌入式實(shí)時(shí)多任務(wù)操作系統(tǒng)μC/OS-II的移植與應(yīng)用。
4 移植 μC/OS-II
TMS320LF2407滿足μC/OS-II移植的條件[3]。TI公司提供的編譯軟件Code Composer V4.10.36也支持C語(yǔ)言與匯編語(yǔ)言混合編程[4]。筆者即在此編譯器中進(jìn)行μC/OS-II移植。
μC/OS-II操作系統(tǒng)的組成文件分為三類,一類是與處理器無(wú)關(guān)的代碼文件,另一類是處理器有關(guān)的代碼文件以及μC/OS-II與應(yīng)用相關(guān)的設(shè)置文件。當(dāng)然移植工作完成后編寫應(yīng)用程序,還應(yīng)包括應(yīng)用文件。移植所需要做的工作僅僅是修改部分與處理器有關(guān)的文件。這類文件包括:OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C等三個(gè)文件。限于篇幅,本文僅描述移植過程的重點(diǎn)與難點(diǎn)。
TMS320LF2407 芯片本身的堆棧只有8級(jí),從AR0到AR7。該C編譯器將內(nèi)部寄存器AR0、AR1保留,AR1作為堆棧指針SP,AR0被作為堆棧中的臨時(shí)變量指針FP。所以在匯編語(yǔ)言中不要使用這兩個(gè)寄存器,若一定要用,必須關(guān)中斷,并注意保存和恢復(fù)。TI公司的Code Composer 編譯軟件里,中斷要調(diào)用I
SAVE保存所有寄存器,各寄存器壓入堆棧的先后順序?yàn)椋嚎兆?、,ST1、ST0、ACCH、ACCL、PREGH、PREGL、TREG、AR0、AR2、AR3、AR4、AR5、AR6、AR7、TOS、6個(gè)硬件堆棧,共22個(gè)。返回時(shí)“跳轉(zhuǎn)”到ISAVE保存所有寄存器,各寄存器壓入堆棧的先后順序?yàn)椋嚎兆帧?,ST1、ST0、ACCH、ACCL、PREGH、PREGL、TREG、AR0、AR2、AR3、AR4、AR5、AR6、AR7、TOS、6個(gè)硬件堆棧,共22個(gè)。返回時(shí)“跳轉(zhuǎn)”到I
REST函數(shù),恢復(fù)這些寄存器的值,順序與I
SAVE相反。這里用“跳轉(zhuǎn)“而不是調(diào)用,是因?yàn)镮SAVE相反。這里用“跳轉(zhuǎn)“而不是調(diào)用,是因?yàn)镮
REST執(zhí)行完后不一定能返回到開始執(zhí)行時(shí)的地址。
改寫OSTaskStkInit():該函數(shù)任務(wù)堆棧初始化函數(shù),在創(chuàng)建任務(wù)的時(shí)候被調(diào)用。TMS320LF2407的堆棧是從低地址往高地址遞增的。該函數(shù)首先獲取該任務(wù)棧的棧頂?shù)刂贰H缓髮?duì)該地址進(jìn)行遞增并賦初值。從棧頂?shù)刂烽_始的前兩個(gè)地址分別裝載棧頂?shù)刂?,?shù)據(jù)區(qū)地址,第三個(gè)地址保留。后面依次為上述寄存器值,從ST1到TOS,TOS裝載的是中斷的返回地址或任務(wù)起始地址,后面再保留6個(gè)硬件堆棧地址。該函數(shù)返回堆棧指針值,即最尾的地址。
改寫OSStartHighRdy():該函數(shù)啟動(dòng)最高優(yōu)先級(jí)的任務(wù)。將當(dāng)前就緒的最高優(yōu)先級(jí)任務(wù)的堆棧指針賦于AR1,跳轉(zhuǎn)到I
REST函數(shù),即可轉(zhuǎn)到最高優(yōu)先級(jí)任務(wù)的起始地址。改寫OSCtxSw():該函數(shù)進(jìn)行任務(wù)間切換,為OSSched()函數(shù)所調(diào)用。任務(wù)切換用8號(hào)軟中斷來(lái)實(shí)現(xiàn)。第一步:調(diào)用IREST函數(shù),即可轉(zhuǎn)到最高優(yōu)先級(jí)任務(wù)的起始地址。改寫OSCtxSw():該函數(shù)進(jìn)行任務(wù)間切換,為OSSched()函數(shù)所調(diào)用。任務(wù)切換用8號(hào)軟中斷來(lái)實(shí)現(xiàn)。第一步:調(diào)用I
SAVE函數(shù)壓棧。第二步:為將當(dāng)前原任務(wù)的堆棧指針保存到當(dāng)前原任務(wù)的任務(wù)控制塊(TCB)中;將處于就緒態(tài)的最高優(yōu)先級(jí)新任務(wù)TCB地址賦給當(dāng)前TCB;新任務(wù)的優(yōu)先級(jí)賦給當(dāng)前優(yōu)先級(jí);將新任務(wù)TCB中的堆棧指針賦給AR1。第三步:跳轉(zhuǎn)到I$$REST。
改寫OSIntCtxSw():該函數(shù)只能在中斷子程序中被OSIntExit()函數(shù)調(diào)用。由于中斷可能會(huì)引起任務(wù)切換,所以在中斷服務(wù)程序的最后調(diào)用OSIntExit()來(lái)檢查是否需要進(jìn)行任務(wù)切換。若有比被中斷任務(wù)的優(yōu)先級(jí)更高的任務(wù)處于就緒態(tài),則調(diào)用此函數(shù)進(jìn)行任務(wù)切換。該函數(shù)首先通過執(zhí)行POP指令彈出調(diào)用OSIntCtxSw()時(shí)的返回地址,然后調(diào)整堆棧指針,然后轉(zhuǎn)到OSCtxSw()函數(shù)的第二步執(zhí)行。要調(diào)整堆棧指針的原因是在調(diào)用OSIntExit()時(shí)保存了返回地址和幀指針等相關(guān)的值,所以在進(jìn)行任務(wù)切換前必須將先前任務(wù)的指針值恢復(fù)到中斷前的位置。通過查看進(jìn)中斷后堆棧指針AR1的變化,我們發(fā)現(xiàn)程序運(yùn)行到任務(wù)切換時(shí),AR1增加了5個(gè)地址,故需要在此函數(shù)中將AR1減5,以恢復(fù)被中斷前任務(wù)堆棧的指針。
改寫OSTickISR():時(shí)鐘節(jié)拍中斷服務(wù)子程序,可采用定時(shí)器1周期中斷作為系統(tǒng)時(shí)鐘節(jié)拍,這部分編寫沒有什么難點(diǎn)。但要注意的是一定不要在調(diào)用中斷嵌套加1函數(shù)OSIntEnter()之前開中斷。因?yàn)檫@樣可能導(dǎo)致直接從非最后層的高優(yōu)先級(jí)中斷里切換到任務(wù),這將導(dǎo)致致命后果,程序再也不能進(jìn)某中斷。
改寫OS_CPU.H,關(guān)鍵語(yǔ)句如下:
#define OS_STK_GROWTH 0
#define OS_ENTER_CRITICAL() asm(“SETC INTM”);
#define OS_EXIT_CRITICAL() asm(“CLRC INTM”);
#define OS_TASK_SW() asm(“INTR 8”);
按需配置OS_CFG.H。至此,μC/OS-II在TMS320LF2407上的移植就基本完成了。最后的工作是對(duì)部分代碼進(jìn)行改寫和優(yōu)化,從而提高運(yùn)行速度,減少代碼空間。本文對(duì)此不進(jìn)行描述,讀者可自行嘗試處理。
5 應(yīng)用程序改寫
在本應(yīng)用中,筆者建立了四個(gè)應(yīng)用任務(wù),優(yōu)先級(jí)分別為4、5、6、7。同時(shí)為每個(gè)任務(wù)分配了一個(gè)消息郵箱,使用基于消息郵箱事件的通信機(jī)制進(jìn)行任務(wù)間通信與任務(wù)切換。整個(gè)軟件的基本結(jié)構(gòu)如圖2所示。
任務(wù)AdQTask():采樣總電壓、電流信號(hào),并對(duì)電池進(jìn)行容量(電量)累積。分配郵箱:pAdQMbox。
任務(wù)SocTask():進(jìn)行電池的SOC算法。分配郵箱:pSocMbox。
任務(wù)SendTask():通過DSP內(nèi)部CAN發(fā)送SOC值以及電池電壓溫度信息。分配郵箱:pSendMbox。
任務(wù)SjaRxTask():對(duì)從SJA1000接收過來(lái)的電池組信息進(jìn)行處理與故障診斷。分配郵箱:pSjaRxMbox。
由上節(jié)對(duì)堆棧的分析可看出,任務(wù)棧最少需要25個(gè)地址。筆者為每個(gè)任務(wù)分配了100個(gè)地址(200個(gè)字節(jié))的任務(wù)??臻g。使用函數(shù)OSTaskCreate()進(jìn)行創(chuàng)建各任務(wù),該函數(shù)的第三個(gè)參數(shù)為棧頂?shù)刂?,為OSTaskStkInit()所調(diào)用。要注意TMS320LF2407的堆棧是遞增的,故應(yīng)傳遞任務(wù)棧的最低地址。而又由于任務(wù)程序是采用C語(yǔ)言編寫,編譯器對(duì)AR1的偏移范圍可能會(huì)超過任務(wù)棧棧頂。雖然在這種情況下AR1是可恢復(fù)的,但仍可能會(huì)影響最低地址之前的地址內(nèi)容。所以筆者建議對(duì)其進(jìn)行適當(dāng)后移。
中斷1為SJA1000從CAN總線上接收到數(shù)據(jù)所引發(fā)。在中斷1中讀取SJA1000緩沖區(qū)的數(shù)據(jù),然后向郵箱pSjaRxMbox發(fā)送標(biāo)志信號(hào)。在中斷處理完后即可到任務(wù)SjaRxTask()執(zhí)行。
中斷2為定時(shí)器1周期中斷。周期設(shè)為1ms。每10ms做一次時(shí)鐘節(jié)拍。每個(gè)周期1ms向郵箱pAdQMbox發(fā)送數(shù)據(jù)1(標(biāo)志信號(hào)),以使AdQTask()任務(wù)列為就緒態(tài),中斷退出時(shí)若其為最高優(yōu)先級(jí)任務(wù)則轉(zhuǎn)到該任務(wù)執(zhí)行。每50ms發(fā)送數(shù)據(jù)2,以就緒AdQTask()任務(wù)和SocTask()任務(wù)。每1s發(fā)送標(biāo)志數(shù)據(jù)3,以就緒AdQTask()任務(wù),SocTask()任務(wù)和SendTask()任務(wù)。
各任務(wù)均等待相應(yīng)郵箱以及相應(yīng)標(biāo)志信號(hào)。任務(wù)恢復(fù)后判斷郵箱中的標(biāo)志信號(hào),從而轉(zhuǎn)到相應(yīng)的功能程序中。
下面列舉SjaRxTask()任務(wù)與中斷1的中斷服務(wù)程序的簡(jiǎn)化代碼來(lái)描述μC/OS-II的郵箱通信機(jī)制,供讀者參考。
void SjaRxTask(void data) /*接收任務(wù)*/
{ INT8U *FlagSjaRx=0;
INT8U error;
data=data;
while(1) {
FlagSjaRx=OSMboxPend(pSjaRxMbox,1,&error); /*等待郵箱中的消息*/
if(*FlagSjaRx) /*判斷標(biāo)志信號(hào)是否為1*/
SjaRxProcess(); /*接收數(shù)據(jù)處理函數(shù)*/
}
}
void c_int1() /*SJA1000的中斷服務(wù)程序*/
{ OSIntEnter(); /*中斷嵌套層加1*/
count=1; /*標(biāo)志信號(hào)置1*/
…… /*讀取SJA1000緩沖區(qū)的數(shù)據(jù),代碼省略*/
OSMboxPost(pAdQMbox,(void*)&count); /*發(fā)送標(biāo)志信號(hào)*/
…… /*清中斷標(biāo)志并釋放SJA1000緩沖區(qū),代碼省略*/
OSIntExit(); /*檢查是否需進(jìn)行任務(wù)切換,若需要,則進(jìn)行切換*/
asm(“ CLRC INTM ”); /*開總中斷*/
}
6 結(jié)語(yǔ)
如今,PC時(shí)代已經(jīng)到來(lái),嵌入式系統(tǒng)的應(yīng)用開始無(wú)處不在,采用嵌入式操作系統(tǒng)的手機(jī)、信息家電等眾多的嵌入式產(chǎn)品已經(jīng)出現(xiàn)。而在相關(guān)場(chǎng)合,嵌入式實(shí)時(shí)操作系統(tǒng)(RTOS)的應(yīng)用也愈加廣泛。采用RTOS的最大好處就是可以提高系統(tǒng)的可靠性與實(shí)時(shí)性,同時(shí)也提高了軟件開發(fā)的效率,縮短了開發(fā)周期。在本系統(tǒng)的軟件設(shè)計(jì)中引入μC/OS-II以后,相比以前的前后臺(tái)系統(tǒng),所增加的代碼空間為數(shù)據(jù)約1.5K字,程序約3.5K字,額外消耗的存儲(chǔ)器資源較小。而因?yàn)棣藽/OS-II本身的實(shí)時(shí)特性,使本應(yīng)用系統(tǒng)的實(shí)時(shí)性需要能得以滿足,從而系統(tǒng)的可靠性也隨之大大提高。因此,在一般的中小型實(shí)時(shí)嵌入式系統(tǒng)中,μC/OS-II是一種理想的選擇。
本文從應(yīng)用與實(shí)用的角度出發(fā),詳細(xì)介紹了μC/OS-II在基于TMS320LF2407內(nèi)核的電動(dòng)車電池管理系統(tǒng)中的應(yīng)用,希望對(duì)相關(guān)的研究開發(fā)人員有所幫助。實(shí)驗(yàn)結(jié)果表明,該電池管理系統(tǒng)具有設(shè)計(jì)合理、性能穩(wěn)定、實(shí)時(shí)性好、可靠性高等優(yōu)點(diǎn),取得了令人滿意的工作效果。
評(píng)論