貴陽學院計科系 杜隆胤
瀘州醫學院生物醫學工程系 曹高飛
當前,嵌入式應用已經深入人們生活,嵌入式開發正如火如荼。相應地,也激起了高校計算機及相關專業學生的嵌入式學習熱潮。但是在內地一些嵌入式學習環境較差的地方,由于硬件資源短缺給學習帶來了不少困難。本文擬通過一種簡單可行的辦法以規避嵌入式開發對硬件環境的依賴,使學習者能將精力集中到嵌入式軟件開發上來,從而降低學習門檻,提升學習速度。
嵌入式開發語言非常多,包括具有對硬件操作獨具優勢的低級語言——匯編語言、同時具備低級語言和高級語言特性的C語言以及面向對象編程的C++語言等等。其中、匯編語言因為接近于機器語言,在硬件底層操作方面獨具優勢,如果編程得當可獲得很好的時間和空間效率,但它掌握起來相對困難且編程效率較低,而且程序可讀性差,后期調試和維護困難大,所以一般在資源相對較少的應用場合和與硬件聯系緊密的程序段使用;面向對象的高級語言編程接近人的思維方式,更貼近人類生活,能有效地提高編程效率為程序的可維護性,但編制的程序時間效率和空間效率都不高,且對底層硬件操作較一般需要通過低級語言程序來實現,因此一般只適合于各種資源都很豐富的大型的嵌入式系統;C同時具備低級語言和高級語言的優勢、在講求時間和空間效率基礎上兼備易學、編程效率高等特點,在中小型嵌入式開發中以及大型系統的驅動程序開發中得到了廣泛的應用。
Keil是目前最流行的開發80C51系列單片機的嵌入式的集成開發環境,它提供了C編譯器、宏匯編、連接器、庫管理和一個功能強大的仿真調試器等在內的完整開發方案,并通過一個集成開發環境(μVision)將這些功能組合起來。[1]特別地,Keil支持的軟件仿真為缺少硬件環境開發調試提供了方便,很多嵌入式愛好者又在Internet網上提供了不少自制的軟仿真DLL插件,為嵌入式開發學習者提供了很多便利。
但是,當前的仿真大都停留在觀察寄存器值的層次上,很難如實反映外接部件的最終實現效果,即使能找到個別能仿真外圍設備的插件又和開發者需要的存在一些差距,開發者自己開發適合自己的仿真環境又難度太大且耗時耗力。這矛盾促使了筆者尋找一種開發者自己能搭建仿真環境方法的動機。
現有的軟件仿真方式很難達到即契合開發實際、如實反應設備最終運行效果的要求,那么、有沒有一種不費事又能達到以上要求的軟件仿真方式呢?本文就Keil環境下的C程序如何在TC下編譯并仿真進行討論。至于其他環境,如VC或BorlandC,GCC等。讀者可以參照本文實現通過宏定義的軟仿真。
首先,變量長度問題。
在嵌入式開發中,變量長度是非常敏感的,因此在處理變量長度是一定要小心。為使得編寫的程序具有較好的編譯環境適應性,一般都不會直接使用int、long、short和byte等變量類型進行定義,而是使用型如int8、int16等能直接表示變量類型及長度的定義方式,這要求在使用這些定義語句前先進行相應的定義。如在TC下就可以作如下的宏定義:

在Keil環境下卻要把以上定義卻為如下形式:

因此一般嵌入式開發都會將此部分內容針對不同的環境編織成不同的頭文件,然后include到源文件中。同事可以在一個總的配置頭文件中用如下方式為調試和最后編譯配置不同的頭文件。

這樣就只需要在不同環境下編譯時改變宏定義DEBUG的值即可。
其次,關鍵字問題。
Keil中有部分關鍵字不是ANSI C標準,因此對這些關鍵字需要進行特別的處理。主要有sfr、sbit和interrupt。
1.sfr與sbit
sfr是Keil為能直接訪問80C51中的(特殊功能寄存器(SFR)而提供了一個專用的關鍵詞,其用法是:
sfrt變量名=寄存器地址值。[2]
但是TC中卻沒有此用法,因此該定義此部分內容的配置文件作一定的修改。可以將sfr定義的特殊功能寄存器名字定義為對應長度的無符號整型變量。如:
sfr p0=0x80;
響應的替換語句為:
unsigned char p0;
這樣只能是簡單地解決了sfr的問題,而sbit就非常難模擬了。sbit是Keil為訪問C51中特殊寄存器的位變量而設置的,但在TC下沒為位變量,無法直接替換該關鍵字。
一般地,在嵌入式開發中,為了提高程序的可移植性,不會直接在程序里對特殊寄存器賦值,而以響應功能函數的方式出現。[3]比如在電路中用p1_1以共陽極方式控制指示燈L1,則可以在配置文件中設置如下宏定義:
#define SetL1(a) p1_1=!a;
那么在程序中需要點亮或熄滅指示燈L1時就可以執行語句:
SetL1(1); //點亮指示燈L1
SetL1(0); //熄滅指示燈L1
這樣,在芯片更改或電路變動后只修改宏定義文件就能使程序適應新的硬件環境,從而增強了程序的可移植性。如此,為實現基于宏的軟仿真,可以在對應TC仿真環境下的配置文件中按功能進行相應的宏定義,即編寫相應的函數實現指示燈控制的模擬。筆者稱此仿真為功能級仿真,而相對的只反映變量值變化的仿真方法可稱為變量級仿真。
2.interrupt
關鍵字interrupt是Keil環境中定義中斷函數用的,使用該擴展屬性的函數定義語法如下:
返回值 函數名 interrupt n
其中n對應中斷源的編號,其值從0開始,在80C51單片機中,編號從0到4,個編號對應外中斷、定時器中斷和串行口中斷等。由于中斷與芯片聯系非常緊密,很難仿真。當然、TC下也可以利用PC鍵盤產生的中斷來模擬,但工作量較大。所以,遇到像“void timer0() interrupt 1”之類的語句,只能先把“()”后面部分注釋掉了,不不予仿真。
第三,功能仿真。
常用的嵌入式外接部件主要包括:液晶顯示,flash存儲器,指示燈,按鍵,揚聲器等,如果以查詢方式控制,就比較容易仿真。
1.液晶顯示的仿真
液晶顯示器可以利用TC的圖形化函數進行。因為一般點陣液晶都是以描點為基礎的,可以用TC下圖形化描點函數(void far putpixel(int x,int y,int color);)代替。在TC下進行圖形編程必須進行一系列的初始化,而嵌入式編程一開始也需要對硬件環境進行初始化,因此可以編寫一個代替嵌入式環境初始化的函數以實現圖形模式的啟動。這同樣可以在宏定義部分實現。一般嵌入式系統啟動后就會進入一個無限循環,而在TC下仿真時不可以能讓程序無限運行下去,因此需要設置一個出口,同時調用closegraph()以關閉圖形模式。
2.flash存儲仿真
對應外存儲器的仿真,可以在硬盤上開辟一個文件進行模擬。但是在編寫相應的仿真存取函數時,需要考慮flash的頁面大小以及頁內地址反轉問題,即在某頁內從起始地址以猝發方式連續存儲數據時,一旦存儲的數據超過一頁容量,頁內地址將反轉到頁面起始處,導致覆蓋先前寫入數據的現象。
為實現該功能的仿真,也需要在初始化函數中加入打開硬盤文件的語句,系統出口處加入文件關閉函數。在編寫存取功能的仿真函數時配合seek()函數進行存取位置的定位,存數據時注意猝發方式的地址及頁面大小即可實現基于宏定義的軟仿真。
3.指示燈仿真
如果配置文件中關于指示燈的配置為如下形式:
#define SetLx(a) p1_x=!a //x=0,1,2,…,7
那么在仿真配置文件中就可以相應作如下宏定義:
#define SetL0(a) setl1(a)
setl1(a)是為實現軟仿真編寫的控制指示燈的函數,以其實現TC環境下640*480的圖形環境中劃分一部分區域專門顯示指示燈的明滅狀態。
4.按鍵仿真
一般按鍵應該在配置頭文件中作如下配置:
#define IsKey0Down() (p3_5==1)
或者就直接有一個int IsKey0Down()函數。仿真中可以用鍵盤上某些鍵對應按鍵,此時可以使用boiskey()函數來檢測鍵盤是否有按鍵以及何鍵被按下。假如用鍵盤上的鍵“A”模擬“K0”鍵,則可編寫如下函數:


在配置頭文件中作如下定義即可:
#define IsKey0Down() iskey0down()
以上方式只能模擬系統中只有一個按鍵的情形,在系統有多個按鍵的情況需要考慮一次判斷多個按鍵。則將以上函數需稍作修改,以適應讀一次鍵值作多個判斷的需要。
5.揚聲器仿真
揚聲器的仿真類似于指示燈,只是注意揚聲器一般打開一會就會立即關閉,在此不再贅述。
本文討論的基于宏的軟仿真方法實質為利用C的空定義,在配置頭文件中實現基本功能的宏定義替換以實現嵌入式程序的仿真。
本文所討論的仿真方法一般只適應于沒有中斷的嵌入式系統,而嵌入式系統又不可能沒有中斷,因此,此方法只實用于嵌入式前期學習,不適于系統開發。但是,在完全以循環查詢方式編寫的嵌入式系統中,幾乎全部功能都能以宏定義方式實現TC下的軟仿真。
嵌入式開發中因為軟件與硬件聯系非常緊密,因此初學時難度較大,利用仿真方式進行學習能降低初學者入門難度。目前相對較好的Keil+DLL仿真方式依賴他人提供,很難適合開發者(學習者)的需要。
本文立足于程序初學者相對容易掌握的TC下的宏定義的方式搭建用戶自制的軟仿真環境,如此也使得開發者(學習者)比較容易根據需要對仿真環境進行增刪修改,使仿真更能貼近任務。但因為該方法要求具有一定的TC下的C編程基礎,而且本身很難實現中斷和數據收發的仿真,所以還有待進一步改善甚至尋找更便捷且更貼近任務的仿真方法。
[1]郭天祥.新概念51單片機C語言教程——入門、提高、開發、拓展[M].電子工業出版社,2009,01.
[2]Keil Elektronik GmbH.and Keil Software,Inc.Keil User’s Guide[J].1988.
[3]凌明.嵌入式系統高級C語言編程[M].北京航空航天大學出版社,2011-1-1.
[4]丁明亮,唐前輝.51單片機應用設計與仿真-基于Keil C與Proteus.北京航空航天大學出版社,2009-2-1.