黃志輝,羅峰
(同濟(jì)大學(xué) 汽車學(xué)院,上海201804)
黃志輝(碩士研究生),研究方向?yàn)檐囕v電子技術(shù)。
自動(dòng)代碼生成技術(shù)在航空航天、汽車、工業(yè)控制及自動(dòng)化等領(lǐng)域有著廣泛的應(yīng)用。20世紀(jì)90年代,隨著計(jì)算機(jī)技術(shù)和軟件技術(shù)的發(fā)展,許多工業(yè)領(lǐng)域廣泛采用基于模型的設(shè)計(jì)方法,極大地提高了系統(tǒng)的開發(fā)效率?;谀P偷拈_發(fā)方法中一項(xiàng)核心的技術(shù)就是自動(dòng)代碼生成技術(shù),在快速原型及系統(tǒng)實(shí)現(xiàn)等方面做出了巨大貢獻(xiàn)[1]。
Real-Time Workshop Embedded Coder(RTWEC)能夠?qū)imulink中圖形化設(shè)計(jì)的模塊生成用戶目標(biāo)所需的C語(yǔ)言代碼,該代碼可以應(yīng)用于許多實(shí)時(shí)或者非實(shí)時(shí)的場(chǎng)合,比如快速原型和硬件在環(huán)測(cè)試[2]。用戶可以修改生成的代碼,在獨(dú)立于Matlab之外的環(huán)境下執(zhí)行。代碼轉(zhuǎn)換是RTWEC的應(yīng)用基礎(chǔ),它能生成與ANSI/ISO標(biāo)準(zhǔn)相兼容的C語(yǔ)言代碼,這樣的代碼可運(yùn)行于目標(biāo)微控制器和實(shí)時(shí)操作系統(tǒng)(RTOS)。
本文以基于飛思卡爾公司的8位微控制器MC9S08QE128的電動(dòng)智能車轉(zhuǎn)向控制系統(tǒng)系統(tǒng)為例,闡述利用RTWEC生成高質(zhì)量、高效率的C代碼,并移植到該芯片內(nèi)的過(guò)程。由于 RTWEC對(duì)本課題所使用的MC9S08QE128并沒(méi)有專門的支持,因此用戶需要自己定制所需要的模塊。
RTWEC自動(dòng)程序創(chuàng)建過(guò)程,能在不同主機(jī)環(huán)境下生成用于實(shí)時(shí)應(yīng)用的程序。程序創(chuàng)建過(guò)程使用高級(jí)語(yǔ)言編譯器中的聯(lián)編實(shí)用程序,來(lái)控制所生成源代碼的編譯和鏈接過(guò)程。如圖1所示,代碼生成的整個(gè)流程可以分為3個(gè)步驟[3]。
圖1 RTWEC代碼生成流程
①通過(guò)RTWEC將建立起來(lái)的模型文件model.mdl文件編譯成一個(gè)中間描述文件,即model.rtw。它包括模塊參數(shù)、信號(hào)寬度、采樣時(shí)間以及各模塊的執(zhí)行次序。該文件可以被用戶修改,用來(lái)傳遞重要的參數(shù)信息。
②讀取中間描述文件mode1.rtw,然后進(jìn)行編譯和執(zhí)行目標(biāo)文件中的命令,包括系統(tǒng)目標(biāo)文件和每一個(gè)模塊目標(biāo)文件。在這一階段中,目標(biāo)語(yǔ)言編譯器TLC將中間描述文件model.rtw和相關(guān)的模塊、S函數(shù)等轉(zhuǎn)換為目標(biāo)源代碼。
③RTWEC根據(jù)系統(tǒng)模板聯(lián)編文件生成自定義聯(lián)編文件model.mk,然后調(diào)用make實(shí)用程序,它根據(jù)生成的聯(lián)編文件model.mk的規(guī)則,把生成的源代碼編譯、鏈接,從而生成可執(zhí)行代碼。比較特殊的一點(diǎn)是,CodeWarrior IDE使用的是project.mcp工程文件來(lái)進(jìn)行編譯、鏈接,而不是make實(shí)用程序,因此需要另外設(shè)計(jì)接口。
目標(biāo)驅(qū)動(dòng)模塊主要是用來(lái)生成微處理器所需的底層驅(qū)動(dòng)代碼,即對(duì)微處理器的寄存器進(jìn)行設(shè)置。在CodeWarrior IDE的指令集中,大量寄存器的設(shè)置因所選單片機(jī)型號(hào)各異,對(duì)不熟悉其復(fù)雜指令的設(shè)計(jì)人員來(lái)說(shuō),調(diào)試過(guò)程是很漫長(zhǎng)的。而目標(biāo)驅(qū)動(dòng)模塊如同CodeWarrior IDE的Processor Expert模塊,更為方便地提供給用戶進(jìn)行設(shè)計(jì)。如圖2所示,用戶只需要在PORT下拉列表框中選擇相應(yīng)的端口,而不需要了解繁瑣的寄存器設(shè)置。
圖2 數(shù)字I/O輸入模塊
根據(jù)上述RTWEC代碼生成的流程,可以得到目標(biāo)驅(qū)動(dòng)模塊的設(shè)計(jì)過(guò)程。目標(biāo)驅(qū)動(dòng)模塊主要是由S函數(shù)和TLC文件定制的。S函數(shù)(需要被封裝)用于定制自定義simulink模塊,該模塊可以傳遞用戶設(shè)置的參數(shù)信息,并保存在model.rtw文件中。TLC文件可以取出model.rtw文件中保存的參數(shù)信息,通過(guò)內(nèi)聯(lián)和一定的代碼生成規(guī)則,用于控制代碼生成過(guò)程與格式。
下面以數(shù)字I/O輸入模塊為例來(lái)說(shuō)明目標(biāo)驅(qū)動(dòng)模塊的設(shè)計(jì)。
(1)編寫C MEX S函數(shù)
S函數(shù)有很多種設(shè)計(jì)方式,比如m文件和C語(yǔ)言等。其中,只有用可被編譯C語(yǔ)言文件(C MEX文件)或者S函數(shù)生成器建立起來(lái)的S函數(shù),才能夠內(nèi)聯(lián)TLC文件,從而生成所需代碼。在編寫S函數(shù)中,最重要的是參數(shù)傳遞,即將用戶所選擇的參數(shù)傳遞到TLC文件中去。這里RTWEC提供了一個(gè)model.rtw文件,該文件可以用作S函數(shù)和TLC文件的橋梁。其實(shí)現(xiàn)方法是,通過(guò)mdlRTW函數(shù)將用戶參數(shù)傳遞到rtw中的SFcnParamSettings對(duì)象中去。代碼如下:
這樣,在 TLC文件中通過(guò)SFcnParamSettings.port_name便可以調(diào)用該參數(shù)。完成后用命令mex進(jìn)行編譯,即可生成所需的C MEX文件。
(2)封裝S函數(shù)
該步驟主要為方便用戶進(jìn)行參數(shù)設(shè)置,注意參數(shù)名與S函數(shù)對(duì)話框中的參數(shù)名要一致,而且必須是DOUBLE類型的。封裝好的模塊便可以放到自定義的Simulink模型庫(kù)中去。
(3)編寫TLC文件
這一文件的編寫非常重要,它直接決定了生成代碼的形式,即代碼內(nèi)容和它安放在生成的C語(yǔ)言文件中的位置。其參數(shù)的獲得正是通過(guò)rtw中的SfcnParamSettings對(duì)象所得到的。注意,TLC文件名與S函數(shù)一致才能夠被內(nèi)聯(lián)。下列TLC語(yǔ)句段顯示了如何根據(jù)用戶的選擇將寄存器的設(shè)置嵌入到生成的代碼中去:
為了在RTWEC生成代碼的同時(shí)建立起CodeWarrior IDE的工程文件,并自動(dòng)對(duì)其進(jìn)行操作。RTWEC提供了兩種截然不同的方法[4]。
(1)XML工程導(dǎo)入
CodeWarrior IDE的大多數(shù)版本都支持可擴(kuò)展標(biāo)記語(yǔ)言(XML)形式的工程導(dǎo)入或者導(dǎo)出。通過(guò)修改TLC文件,RTWEC可自動(dòng)生成XML文件,作為CodeWarrior IDE的工程導(dǎo)入。但該方法有個(gè)缺陷,每當(dāng)用戶在CodeWarrior IDE中修改工程時(shí),必須重新修改TLC文件,給使用帶來(lái)了很大不便。其設(shè)計(jì)過(guò)程如圖3所示。
圖3 以XML工程導(dǎo)入為接口
(2)COM組件控制工程建立
在CodeWarrior IDE有許多的接口函數(shù),而這些函數(shù)是可以通過(guò)用戶建立COM組件來(lái)進(jìn)行調(diào)用的。COM組件技術(shù)可以自動(dòng)執(zhí)行一些重復(fù)性的任務(wù),從而進(jìn)行外部操作。比如通過(guò)命令 actxserver('CodeWarrior.CodeWarriorApp')來(lái)打開CodeWarrior IDE,從而對(duì)其進(jìn)行控制。
本文嘗試了一種手工建立工程的方法,即在CodeWarrior IDE中建立工程,修改源文件 main.c,然后將生成的代碼文件和函數(shù)分別添加到工程和main.c中去,從而形成一種文件路徑的映射關(guān)系。這樣,每次在RTWEC中生成代碼后,直接用CodeWarrior IDE編譯即可。該方法使用簡(jiǎn)單,但缺點(diǎn)是自動(dòng)化程度差,用戶需要自行建立mcp工程,添加和修改文件。
下面以一個(gè)實(shí)例來(lái)說(shuō)明RTWEC代碼的生成及其測(cè)試。本文所設(shè)計(jì)的系統(tǒng)將前瞻傳感器安裝在智能車的伺服電機(jī)(隨動(dòng)舵機(jī))上,前置并懸伸出車體前端,將前瞻距離延長(zhǎng)到前排傳感器所能達(dá)到的最大距離。然后,控制隨動(dòng)舵機(jī)使其跟蹤黑線,并始終將黑線置于隨動(dòng)光電組的中間位置。在控制算法中通過(guò)隨動(dòng)比調(diào)節(jié)轉(zhuǎn)向舵機(jī)的轉(zhuǎn)角,使其配合隨動(dòng)舵機(jī)進(jìn)行轉(zhuǎn)向,如此便能達(dá)到智能車系統(tǒng)的超前調(diào)節(jié)和路徑優(yōu)化等目的[5]。
圖4為利用Matlab/StateFlow搭建起來(lái)的控制器模型。該模型比較復(fù)雜,手寫C代碼易出錯(cuò),調(diào)試周期長(zhǎng);而使用RTWEC自動(dòng)代碼生成技術(shù),調(diào)試過(guò)程中很容易檢查出邏輯沖突、數(shù)據(jù)溢出等錯(cuò)誤,大大縮短了開發(fā)周期。
圖4 隨動(dòng)控制算法的有限狀態(tài)機(jī)模型
在生成的代碼中,最重要的是初始化函數(shù)model_initialize()和運(yùn)行主函數(shù)model_step()。設(shè)計(jì)人員只要將這兩個(gè)函數(shù)包含在主函數(shù)里,就可以運(yùn)行了。
為了測(cè)試RTWEC生成代碼的正確性和運(yùn)行效率,將同樣的控制算法的生成代碼和手寫C代碼放在VC++中運(yùn)行。運(yùn)行前將一傳感器返回值設(shè)為1,設(shè)置不同的運(yùn)行時(shí)間(運(yùn)行次數(shù)),比較計(jì)算結(jié)果和 CPU消耗周期(cpucounter)。其中計(jì)算結(jié)果和隨動(dòng)轉(zhuǎn)角(angle)成正比,CPU消耗周期用庫(kù)函數(shù)QueryPerformanceCounter()計(jì)算得到。
圖5是手寫代碼與生成代碼消耗CPU周期對(duì)比,圖6為手寫代碼與生成代碼計(jì)算結(jié)果對(duì)比。可見兩者極為接近,自動(dòng)生成的代碼運(yùn)行正確,且效率沒(méi)有明顯降低。
圖5 手寫代碼與生成代碼消耗CPU周期對(duì)比
圖6 手寫代碼與生成代碼計(jì)算結(jié)果對(duì)比
生成代碼在CodeWarrior編譯后效率會(huì)降低,但隨著程序長(zhǎng)度的增加,代碼運(yùn)行的主要執(zhí)行時(shí)間將更多地消耗在邏輯判斷上,RTWEC生成代碼的執(zhí)行速度會(huì)相對(duì)得到提高。編程人員除了要提高代碼的執(zhí)行效率之外,還需要考慮設(shè)計(jì)的快速性、調(diào)試的方便性,以及可讀性等多方面因素。
[1]楊向忠,安錦文,崔文革.嵌入式自動(dòng)代碼生成技術(shù)應(yīng)用研究[J].彈箭與制導(dǎo)學(xué)報(bào),2008,28(3).
[2]戴海峰,魏學(xué)哲,孫澤昌.V-模式及其在現(xiàn)代汽車電子系統(tǒng)開發(fā)中的應(yīng)用[J].機(jī)電一體化,2006(6).
[3]任傳俊,蔣志文.Real-Time Workshop實(shí)時(shí)仿真研究與應(yīng)用[J].計(jì)算機(jī)仿真,2007(8).
[4]Mathworks,Inc.Matlab R2008b Help Document,2008.
[5]卓晴,黃開勝,邵貝貝.學(xué)做智能車[M].北京:北京航空航天大學(xué)出版社,2007.