吳 瑾,郭 華
(北京控制工程研究所,北京 100190)
本文研究了一種基于ARM公司Keil μVision模擬器[1]的單片機(jī)軟件調(diào)試測(cè)試環(huán)境的制作方法.用戶(hù)需開(kāi)發(fā)的部分為符合μVision編程接口約定的WIN32動(dòng)態(tài)鏈接庫(kù)(后文簡(jiǎn)稱(chēng)μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展).這是一種純軟件方式的仿真模擬環(huán)境,無(wú)需任何單片機(jī)硬件,具有可靠性強(qiáng)、靈活性強(qiáng)、可定制性強(qiáng)、制作周期短、成本低等優(yōu)點(diǎn).
文中首先介紹了μVision模擬器提供的編程接口,之后描述了如何應(yīng)用這些接口構(gòu)建一個(gè)完整的單片機(jī)軟件調(diào)試測(cè)試環(huán)境.
Keil μVision提供給動(dòng)態(tài)鏈接庫(kù)擴(kuò)展使用的接口函數(shù)十分全面,主要包括如下幾類(lèi):
1)系統(tǒng)配置定義類(lèi),主要用于定義用戶(hù)特定的特殊寄存器和虛擬寄存器、設(shè)置寄存器內(nèi)存監(jiān)視、創(chuàng)建定時(shí)時(shí)鐘等:AgsiDefineSFR、AgsiDefineVTR、AgsiDeclareInterrupt、AgsiSetWatchOnSFR、AgsiSetWatchOnVTR、AgsiSetWatchOnMemory、AgsiCreateTimer、AgsiDefineMenuItem.
2)存儲(chǔ)器讀寫(xiě)類(lèi),用于運(yùn)行過(guò)程中獲取和寫(xiě)入存儲(chǔ)器數(shù)據(jù):AgsiWriteSFR、AgsiReadSFR、Agsi-WriteVTR、 AgsiReadVTR、 AgsiWriteMemory、 AgsiReadMemory.
3)模擬器狀態(tài)獲取類(lèi),運(yùn)行過(guò)程中獲取模擬器狀態(tài),如當(dāng)前模擬器時(shí)間、中斷狀態(tài)等:AgsiGet-States、AgsiGetProgramCounter、AgsiIsInInterrupt、Agsi-IsSleeping、AgsiGetExternalClockRate、AgsiGetInternal-ClockRate、AgsiGetClockFactor、AgsiGetLastMemory-Address.
4)模擬器控制類(lèi),用于對(duì)模擬器進(jìn)行控制操作:AgsiSetTimer、AgsiSetSFRReadValue、AgsiStopSimulator、AgsiTriggerReset、AgsiUpdateWindows、Agsi-HandleFocus、AgsiMessage、AgsiExecuteCommand.
具體這些接口函數(shù)的參數(shù)、功能、返回值可參考ARM公司提供的接口編程開(kāi)發(fā)手冊(cè)[2].
Keil μVision對(duì)用戶(hù)開(kāi)發(fā)的μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展有如下要求:
1)引用 Agsi.h/Agsi.cpp 文件;
2)必須為WIN32動(dòng)態(tài)鏈接庫(kù)形式[3](推薦使用Microsoft Visual C++6.0(后文簡(jiǎn)稱(chēng)VC)開(kāi)發(fā));
3)必須具備μVision指定的入口函數(shù),其名稱(chēng)和形式必須為:
extern“C”DWORD AGSIEXPORT AgsiEntry(DWORD nCode,void*vp).
Keil μVision要求動(dòng)態(tài)鏈接庫(kù)擴(kuò)展必須具備AgsiEntry入口函數(shù),它是μVision模擬器與動(dòng)態(tài)鏈接庫(kù)擴(kuò)展實(shí)現(xiàn)數(shù)據(jù)交互的主要途徑,μVision模擬器在運(yùn)行的各個(gè)階段,主動(dòng)調(diào)用AgsiEntry函數(shù),傳遞消息和消息數(shù)據(jù),使動(dòng)態(tài)鏈接庫(kù)擴(kuò)展正確運(yùn)行.
(1)函數(shù)參數(shù)
nCode 消息標(biāo)志,所有可能的值參照表1;
vp 消息參數(shù)指針,依nCode不同而不同.
(2)函數(shù)返回值
函數(shù)調(diào)用成功則返回1,否則返回0.
(3)函數(shù)描述
AgsiEntry是Keil μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展的唯一輸入函數(shù).在μVision模擬器啟動(dòng)時(shí),將自動(dòng)調(diào)用此函數(shù).參數(shù)nCode的值如表1所示.
表1 AgsiEntry函數(shù)消息表Tab.1 AgsiEntry function message
一般來(lái)說(shuō),需要進(jìn)行處理和響應(yīng)的消息是AGSI_INIT、AGSI_RESET、AGSI_TERMINATE,在模擬器初始化、模擬器復(fù)位和模擬器結(jié)束運(yùn)行時(shí)動(dòng)態(tài)鏈接庫(kù)擴(kuò)展收到這些消息.
當(dāng)nCode為AGSI_INIT時(shí),動(dòng)態(tài)鏈接庫(kù)擴(kuò)展應(yīng)進(jìn)行以下工作:
1)當(dāng)需要使用自定義的寄存器時(shí),使用AgsiDefineSTR()定義寄存器;
2)當(dāng)需要使用虛擬寄存器時(shí),使用AgsiDefineVTR()定義虛擬寄存器(如內(nèi)部串口緩沖區(qū)輸入寄存器(SIN)、內(nèi)部串口緩沖區(qū)輸出寄存器(SOUT)等);
3)當(dāng)測(cè)試平臺(tái)需要使用操作界面(通常為對(duì)話(huà)框形式)時(shí),使用AgsiDefineMenuItem()定義彈出對(duì)話(huà)框菜單入口(定義的菜單入口將出現(xiàn)在μVision環(huán)境中調(diào)試狀態(tài)下的Peripherals菜單中);
4)當(dāng)需要監(jiān)視單片機(jī)寄存器或內(nèi)存(通常使用此手段采集單片機(jī)軟件運(yùn)行過(guò)程中的數(shù)據(jù))時(shí),使用AgsiSetWatchOnSFR()或AgsiSetWatchOnMemory()定義監(jiān)視點(diǎn);
5)當(dāng)需要使用模擬器同步定時(shí)時(shí)鐘時(shí),使用AgsiCreateTimer()創(chuàng)建時(shí)鐘.
當(dāng)nCode為AGSI_RESET時(shí),一般將動(dòng)態(tài)鏈接庫(kù)擴(kuò)展中定義的變量、數(shù)組等進(jìn)行復(fù)位,以保證每次復(fù)位后,調(diào)試測(cè)試環(huán)境初始狀態(tài)的一致性.在這個(gè)消息的處理中也可以啟動(dòng)模擬器定時(shí)時(shí)鐘,設(shè)置時(shí)鐘事件的處理.
當(dāng)nCode為AGSI_TERMINATE時(shí),說(shuō)明模擬器運(yùn)行已經(jīng)結(jié)束,需將動(dòng)態(tài)鏈接庫(kù)擴(kuò)展中使用的資源進(jìn)行釋放,包括申請(qǐng)的內(nèi)存、創(chuàng)建的顯示界面等.
在開(kāi)發(fā)μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展中,必須明確回調(diào)函數(shù)的概念.本文中回調(diào)函數(shù)即是指在某種特定事件發(fā)生時(shí),自動(dòng)被模擬器調(diào)用的函數(shù).它也是動(dòng)態(tài)鏈接庫(kù)擴(kuò)展的主要功能實(shí)現(xiàn)載體,分為3種類(lèi)型.
(1)寄存器監(jiān)視回調(diào)函數(shù)
它用于監(jiān)視單片機(jī)軟件的寄存器狀態(tài),一旦模擬器對(duì)所監(jiān)視寄存器進(jìn)行操作,相應(yīng)的回調(diào)函數(shù)就會(huì)被自動(dòng)調(diào)用.例如模擬外圍設(shè)備與單片機(jī)軟件通過(guò)內(nèi)部串口進(jìn)行通信,則需要監(jiān)視內(nèi)部串口緩沖區(qū)輸出寄存器(SOUT),并在回調(diào)函數(shù)中對(duì)SOUT進(jìn)行讀取操作,并使用內(nèi)部串口緩沖區(qū)輸入寄存器(SIN)將應(yīng)答的數(shù)據(jù)返回給單片機(jī)軟件.
(2)內(nèi)存監(jiān)視回調(diào)函數(shù)
它用于監(jiān)視單片機(jī)軟件對(duì)內(nèi)存及I/O的操作處理,一旦模擬器對(duì)所監(jiān)視的內(nèi)存地址進(jìn)行訪(fǎng)問(wèn),相應(yīng)的回調(diào)函數(shù)就會(huì)被自動(dòng)調(diào)用.常用于對(duì)單片機(jī)軟件的數(shù)據(jù)采集仿真控制,由于單片機(jī)系統(tǒng)尋址方式為內(nèi)存及I/O統(tǒng)一編址,故此種回調(diào)函數(shù)可模擬出內(nèi)存及I/O端口的輸入輸出數(shù)據(jù).例如通過(guò)監(jiān)視地址的讀寫(xiě),可以簡(jiǎn)單明確地獲知單片機(jī)軟件對(duì)外圍端口的操作時(shí)序,只要在回調(diào)函數(shù)中按實(shí)際外圍設(shè)備的情況將數(shù)據(jù)反饋給單片機(jī)軟件即構(gòu)成了對(duì)這些外圍設(shè)備的模擬.同時(shí)還可在回調(diào)函數(shù)中記錄兩者間的數(shù)據(jù)交換情況,供事后分析.
(3)定時(shí)時(shí)鐘觸發(fā)回調(diào)函數(shù)
它用于建立對(duì)模擬器系統(tǒng)的定時(shí)控制,一旦所設(shè)置好的定時(shí)器觸發(fā),相應(yīng)的定時(shí)回調(diào)函數(shù)就會(huì)被自動(dòng)調(diào)用.它常用于產(chǎn)生對(duì)單片機(jī)軟件的外部驅(qū)動(dòng)輸入,也可以說(shuō)是仿真調(diào)試環(huán)境實(shí)現(xiàn)對(duì)單片機(jī)軟件的自動(dòng)控制的一種方式.
另外,為了方便用戶(hù)使用,μVision模擬器對(duì)內(nèi)存和寄存器的監(jiān)視觸發(fā)時(shí)機(jī),是在讀之前、寫(xiě)之后觸發(fā)的.即讀取操作的讀取之前、寫(xiě)入操作的寫(xiě)入之后觸發(fā).如圖1所示,單片機(jī)軟件在讀取0x100內(nèi)存前,模擬器調(diào)用回調(diào)函數(shù)OnMem100Read,函數(shù)中對(duì)內(nèi)存0x100進(jìn)行賦值為0x90,單片機(jī)軟件實(shí)際讀取的值就是0x90了,進(jìn)行運(yùn)算后再次寫(xiě)入內(nèi)存0x100,這時(shí)是寫(xiě)入后模擬器調(diào)用OnMem100Write,此時(shí)讀取內(nèi)存0x100的值,即為運(yùn)算后的結(jié)果0x92.
圖1 μVision模擬器監(jiān)視的回調(diào)時(shí)機(jī)Fig.1 μVision simulator watch-callback timing
一般來(lái)說(shuō),μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展開(kāi)發(fā)過(guò)程大體可分為3個(gè)階段:
1)開(kāi)發(fā)者應(yīng)了解單片機(jī)軟件的工作原理,熟悉軟件的輸入、輸出數(shù)據(jù)端口及操作方式.
2)對(duì)μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展進(jìn)行設(shè)計(jì)、編碼.
3)結(jié)合單片機(jī)軟件和μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展,構(gòu)成調(diào)試運(yùn)行環(huán)境,對(duì)二者進(jìn)行聯(lián)合調(diào)試、測(cè)試.
對(duì)于第一個(gè)階段,它是動(dòng)態(tài)鏈接庫(kù)擴(kuò)展開(kāi)發(fā)的基礎(chǔ)工作,每個(gè)單片機(jī)軟件的實(shí)際情況各不相同,需要開(kāi)發(fā)人員在實(shí)際的應(yīng)用中依具體情況而定.第二個(gè)階段中包含幾個(gè)固定的步驟,是開(kāi)發(fā)μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展的主要工作階段.第三個(gè)階段的聯(lián)合調(diào)試,需要開(kāi)發(fā)人員的經(jīng)驗(yàn)和技巧,要對(duì)單片機(jī)軟件和動(dòng)態(tài)鏈接庫(kù)擴(kuò)展相互驗(yàn)證、不斷完善和修改.
μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展的設(shè)計(jì)步驟如圖2所示.
構(gòu)建μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展,推薦使用Microsoft Visual C++6.0(后文簡(jiǎn)稱(chēng) VC)按基于MFC[4]的標(biāo)準(zhǔn)庫(kù)制作.工程建立后,需要制作擴(kuò)展庫(kù)入口AgsiEntry函數(shù),函數(shù)中主要處理AGSI_INIT消息,要對(duì)用戶(hù)使用的寄存器(SFR)[5]、虛擬寄存器(VTR)和界面顯示菜單項(xiàng)入口進(jìn)行定義.同時(shí),還要根據(jù)單片機(jī)軟件端口操作情況,對(duì)寄存器、內(nèi)存地址進(jìn)行監(jiān)視點(diǎn)設(shè)置,對(duì)動(dòng)態(tài)鏈接庫(kù)擴(kuò)展中需要使用的定時(shí)時(shí)鐘進(jìn)行創(chuàng)建.
入口函數(shù)AgsiEntry制作后,接下來(lái)需要針對(duì)寄存器內(nèi)存監(jiān)視、定時(shí)時(shí)鐘開(kāi)發(fā)回調(diào)函數(shù).監(jiān)視回調(diào)函數(shù)中,如果是讀監(jiān)視,一般將準(zhǔn)備好的數(shù)據(jù)填入所監(jiān)視存儲(chǔ)器,供單片機(jī)軟件獲取;如果是寫(xiě)監(jiān)視,一般將單片機(jī)軟件輸出的數(shù)據(jù)讀出并進(jìn)行記錄,在一些情況下還需要給單片機(jī)軟件反饋數(shù)據(jù).定時(shí)時(shí)鐘回調(diào)函數(shù)中,一種情況是開(kāi)發(fā)人員要主動(dòng)給單片機(jī)軟件送入某種激勵(lì),例如可以實(shí)現(xiàn)定時(shí)向單片機(jī)軟件發(fā)送串口通信數(shù)據(jù),定時(shí)觸發(fā)外部中斷等;另外也可以是進(jìn)行某種延時(shí)操作,例如單片機(jī)軟件輸出通信數(shù)據(jù)后,延時(shí)100ms再給出通信應(yīng)答.
圖2 μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展設(shè)計(jì)步驟Fig.2 Design steps for μVision dymamic link library(DLL)extension
在大多數(shù)情況下,需要制作針對(duì)單片機(jī)軟件的數(shù)據(jù)顯示和操作控制界面,通常為非模式對(duì)話(huà)框形式.它并不是必須的,但有了它會(huì)使單片機(jī)軟件運(yùn)行狀態(tài)和數(shù)據(jù)更直觀的顯示,對(duì)軟件調(diào)試的操作控制也更加便捷,建議使用.
建立界面過(guò)程主要是制作對(duì)話(huà)框的建立、刷新和關(guān)閉函數(shù),它們是AGSI_INIT消息中定義界面顯示菜單項(xiàng)入口函數(shù)的參數(shù),如圖3所示.
圖3 對(duì)話(huà)框函數(shù)定義代碼范例Fig.3 The example of dialog function definition
在模擬器運(yùn)行過(guò)程中,點(diǎn)擊μVision界面菜單Peripherals中自定義的菜單項(xiàng)時(shí),對(duì)話(huà)框建立函數(shù)被調(diào)用.在模擬器運(yùn)行狀態(tài)改變,如開(kāi)始運(yùn)行、暫停運(yùn)行時(shí),對(duì)話(huà)框刷新函數(shù)被調(diào)用.退出模擬器運(yùn)行狀態(tài)時(shí),μVision會(huì)調(diào)用對(duì)話(huà)框關(guān)閉函數(shù),這個(gè)函數(shù)中應(yīng)該做好對(duì)話(huà)框資源的釋放處理.
上述μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展的開(kāi)發(fā)工作完成后,開(kāi)始對(duì)單片機(jī)軟件和μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展進(jìn)行聯(lián)合調(diào)試.把VC生成的動(dòng)態(tài)鏈接庫(kù)拷貝到Keil μVision安裝目錄的 C51Bin下(例如 Keil μVision安裝在C:Keil下,則將動(dòng)態(tài)鏈接庫(kù)拷貝到C:KeilC51Bin目錄下).
啟動(dòng)μVision,打開(kāi)單片機(jī)軟件工程,選擇工程屬性“Options For Target-Debug”,在彈出對(duì)話(huà)框中的Dialog Dll的參數(shù)項(xiàng)中,添加參數(shù)-dDLLNAME(DLLNAME為動(dòng)態(tài)鏈接庫(kù)擴(kuò)展的名稱(chēng),不含擴(kuò)展名).例如圖4,加載了ALTUDLL動(dòng)態(tài)鏈接庫(kù).
圖4 μVision工程屬性參數(shù)設(shè)置Fig.4 Setting μVision project property parameters
加載動(dòng)態(tài)鏈接庫(kù)之后,如果制作了平臺(tái)數(shù)據(jù)顯示和操作控制界面,選擇調(diào)試狀態(tài)下Peripherals菜單中自定義菜單入口顯示界面.
之后開(kāi)始運(yùn)行μVision模擬器,對(duì)單片機(jī)軟件和動(dòng)態(tài)鏈接庫(kù)擴(kuò)展進(jìn)行共同驗(yàn)證.由于單片機(jī)軟件的正確性未知,故當(dāng)出現(xiàn)仿真運(yùn)行結(jié)果與預(yù)期不符時(shí),應(yīng)從單片機(jī)軟件和動(dòng)態(tài)鏈接庫(kù)擴(kuò)展兩方面加以考慮,充分利用μVision和VC提供的調(diào)試手段,完善單片機(jī)軟件仿真調(diào)試運(yùn)行環(huán)境.
綜上所述,開(kāi)發(fā)一個(gè)使用μVision模擬器的單片機(jī)軟件調(diào)試測(cè)試環(huán)境并不復(fù)雜,可以極大提高單片機(jī)軟件的調(diào)試測(cè)試效率.目前,ARM公司Keil μVision的產(chǎn)品網(wǎng)站上還提供了不少μVision模擬器的擴(kuò)展芯片仿真,如AD、CAN等,實(shí)際上這些仿真芯片也是使用μVision動(dòng)態(tài)鏈接庫(kù)擴(kuò)展的方式開(kāi)發(fā)的,開(kāi)發(fā)人員熟悉μVision模擬器接口后,完全可以根據(jù)自己的需要開(kāi)發(fā)類(lèi)似的通用芯片仿真,以提高調(diào)試運(yùn)行環(huán)境的可重用性.
[1] ARM.Getting started with μVision2 and the C51 microcontroller development tools user’s guide[M].Cambridge:ARM,2001
[2] ARM.Implementing μVision DLL’s for advanced generic simulator interface[M].Cambridge:ARM,2010
[3] 王闊廳,孫俊忠.基于MFC的動(dòng)態(tài)鏈接庫(kù)的創(chuàng)建和調(diào)用方法研究[J].電腦學(xué)習(xí),2009(5):32-35 Wang K T,Sun J Z.Study on creation and calling method of DLL based on MFC[J].Computer Study,2009(5):32-35
[4] 侯俊杰.深入淺出MFC[M].第二版.武漢:華中科技大學(xué)出版社,2001 Hou J J.Dissecting MFC[M].2nd ed.Wuhan:Huazhong University of Science and Technology Press,2001
[5] Intel.MCS-51 microcontroller family user’s manual[M].Santa Clara:Intel,1994