徐 斯
(湖南機電職業技術學院,湖南 長沙 410151)
80C51單片機是目前國內外工業測控領域中使用極為廣泛的一類8位MCU,C51是面向80C51單片機的C語言。C語言是一種結構化的程序設計高級語言,在單片機應用系統開發中采用C語言編程,易于開發復雜的單片機應用程序,易于進行單片機應用程序的移植,有利于產品中的單片機重新選型,可大大加快單片機應用程序的開發速度。用C51編寫的應用程序須經C51編譯器轉換生成單片機可執行的代碼程序。Keil C51編譯器生成的代碼緊湊、使用方便、全面支持8051單片機主流產品及其眾多的派生系列。
(1)變量的數據類型選擇。①盡可能使用最小的數據類型char、unsigned char或bit。這類數據只占用1B或者1位,由于80C51是8位機,顯然對它們的操作要比對int或long類型數據操作要方便得多。②盡可能使用unsigned數據類型,原因是80C51機器指令不支持符號運算。當在C源代碼中使用了有符號的變量,盡管從字面上看,其操作十分簡單,但C51編譯器將要增加相應的庫函數,產生更多的程序代碼去處理符號運算。所以除了根據變量長度來選擇變量類型以外,還要考慮該變量是否會用于負數的場合,如果程序中可以不需要負數,那么可把變量都定義成無符號類型的。
(2)變量的存儲器類型選擇。由于單片機系統的存儲器資源有限,為了提高執行效率,對存儲器類型的設定,應該根據以下原則:只要條件滿足,盡量先使用直接尋址片內數據存儲器(data),其次設定變量為間接尋址片內數據存儲器(idata),在內部存儲器數量不夠的情況下,才使用外部存儲器,而且在外部存儲器中,優先選擇分頁尋址的數據存儲器pdata,最后才是片外數據存儲器xdata,而且,在內部和外部存儲器共同使用的情況下,要合理分配存儲器,對經常使用和計算頻繁的數據,應該使用內部存儲器,其他的則使用外部存儲器。根據它們的數量進行分配,盡量減少訪問外部存儲器,從而提高程序運行效率。
在80C51單片機系統上使用32位浮點數是得不償失的,這樣做會浪費單片機大量的存儲器資源和程序執行時間。一定要在系統中使用浮點數的時候,可以通過提高數值數量級或使用整型運算代替浮點運算。在運算時,可以進行定點運算的盡量進行定點運算,避免進行浮點運算。盡量減少乘除法運算,如*2或/2,就可以使用移位操作代替乘除法運算,這樣不僅可以減少代碼量,同時還能大提高程序執行效率。處理ints和longs比處理doubles和floats要方便得多,代碼執行起來會更快,C51編譯器也不用連接處理浮點運算的模塊。
一個源文件可以包含一個或幾個函數。在一個函數內部定義的變量是局部,它只在本函數范圍內有效。在函數之外定義的變量是全局變量,它可以為本源文件中其它函數所共用,有效范圍為:從定義變量的位置開始到本源文件結束。
在編寫C51語言程序時,不是特別必要的地方一般不要使用全局變量,而盡可能地使用局部變量,因為:
(1)局部變量只是在使用它時,編譯器才為它在內部存儲區分配存儲單元,而全局變量在程序的全部執行過程中都要占用存儲單元。
(2)全局變量使函數的通用性降低了,因為函數在執行時要依賴于其所在的外部變量。如果將一個函數移到另一個文件中,還要將有關的外部變量及其值一起移過去。但若該外部變量與其它文件的變量同名時,就會出現問題,降低了程序的可靠性和通用性。在程序設計中,在劃分模塊時要求模塊的“內聚性”強、與其它模塊的“耦合性”弱。即模塊功能要單一(不要把許多互不相干的功能放到一個模塊中),與其它模塊的相互影響盡量少。而全局變量是不符合這個原則的。一般要求把C51程序中的函數做成一個封閉體,除了可以通過“實參——形參”的渠道與外界發生聯系外,沒有其它渠道。這樣的程序移植性好、可讀性強。
(3)使用全局變量過多,會降低程序的清晰性,人們往往難以清楚地判斷出每個瞬時各個外部變量的值。在各個函數執行時都可能改變外部變量的值,程序容易出錯。因此,要限制使用全局變量。
從用戶的角度來看,有兩種函數:庫函數和用戶自定義函數。庫函數是KeilC51編譯器提供的,不需要用戶進行定義,可以直接調用。用戶自定義函數是用戶根據自己需要編寫的能實現特定功能的函數,它必須先進行定義之后才能調用。正確而靈活地使用庫函數可使程序代碼簡單、結構清晰、易于調試和維護。
(1)重視本征庫函數的使用。本征庫函數是庫函數中的一類,它在編譯時直接將固定的代碼插入到當前行,而不是用匯編語言中的“ACALL”和“LCALL”指令來實現調用,從而大大提高了函數的訪問效率。
例如單字節循環位移指令RL A和RR A相對的調令是_crol_(循環左移)和_cror_(循環右移)。如果想對int或long類型的變量進行循環位移,匯編調令將更加復雜,而且執行的時間會更長。對于int類型C庫函數為_irol_、iror_,對于long類型函數為_lrol_、_lror_。再例如JBC指令相對的調令是_testbit_,如果參數位置位,它將返回1;否則將返回0。
(2)重視復制、比較、移動等子符串處理庫函數的使用。子符串處理庫函數位于string.h中,其中包括復制、比較、移動等函數:memccpy、memchr、memcmp、memcpy、memmove、memset。在這些函數中,字符串的長度由調用者明確規定,函數可以工作在任何模式下。使用這些函數可以很方便地對字符串進行處理。
例1:使用庫函數對字符串進行復制、比較、移動。
(1)使用宏替代無符號數據類型。在輸入源程序時,為了提高輸入效率,可使用宏替代無符號數據類型。其方法是在源程序開頭,使用#define語句定義。
例 2:#define uchar unsigned char
這樣,在輸入源程序時,可以 uchar、uint、ulong代替unsigned char、unsigned int、unsigned long。在后面的敘述中我們有可能不加說明地使用uchar、uint、ulong說明定義的變量。
(2)使用宏替代函數。對于小段代碼,像從鎖存器中讀取數據,可通過使用宏來替代函數,使得程序有更好的可讀性,可把代碼定義在宏中,這樣看上去更像函數編譯器在碰到宏時,按照事先定義的代碼去替代宏。宏的名字應能夠描述宏的操作,當需改變宏時,只要修改宏定義處即可。
例3:#define led_on(){
宏能夠使得訪問多層結構和數組更加容易,可以用宏替代程序中經常使用的復雜語句,以減少程序輸入時的工作量,且有更好的可讀性和可維護性,與函數調用相比較,執行效率更高,但程序的執行代碼較大,因編譯器將定義的宏內容直接嵌入到代碼中。
C51提供了三種存儲器模式存儲變量、過程參數和分配再入函數堆棧。應該盡量使用小存儲器模式,即SMALL模式。應用系統很少需要使用其他兩種模式,像有大的再入函數堆棧系統那樣。一般來說如果系統所需要的內存數小于內部RAM數時,都應以小存儲模式進行編譯,對其它存儲模式可以由PDATA和XDATA進行說明。
在SMALL模式下,DATA段是所有的內部變量和全局變量的默認存儲段,所有參數傳遞都發生在DATA段中。如果有函數被聲明為再入函數,編譯器會在內部RAM中為它們分配空間。這種模式的優勢就是數據的存取速度很快,但由于片內RAM空間有限,對于較大的程序還得采用LARGE存儲器模式。
在實際進行項目開發時,如果能遵守科學的工程開發規則,靈活地運用C語言的強大功能,熟悉硬件特點,就能夠在較短時間內編寫出高效率、高可靠、易維護的嵌入式系統的執行代碼。
在模塊化程序開發過程中,一般用匯編語言編寫與硬件有關的程序,用C51語言編寫主程序及數據處理程序。使用混合編程技術可以很方便地在一些較大的C51程序中加入已有的匯編驅動程序。在編寫較大的程序時利用已有的匯編程序一方面可以節約大量的程序開發時間,另一方面在編寫驅動程序時,使用匯編語言可以保證部分對時間和穩定性有嚴格要求的程序段。同時,混合編程中的C51和匯編語言的使用仍然和獨立開發時基本一樣,只是在使用不同的語言時,需要注意不同函數之間的調用格式和參數傳遞的規定。
在實際進行項目開發時,如果能遵守科學的工程開發規則,靈活地運用C語言的強大功能,熟悉硬件特點,就能夠在較短時間內編寫出高效率、高可靠、易維護的嵌入式系統的執行代碼。
[1]譚浩強.C程序設計(第三版)[M].北京:清華大學出版社,2005.
[2]李廣弟.單片機基礎[M].北京:北京航空航天大學出版社,2007.
[3]張齊,杜群貴.單片機應用系統設計技術-基于C語言編程[M].北京:電子工業出版社,2004.
[4]徐愛鈞.8051單片機實踐教程-asm51匯編語言與C51高級語言應用[M].北京:電子工業出版社,2005.
[5]楊恢先.單片機原理及應用[M].湘潭:湘潭大學出版社,2013.
[6]施大發.基于Keil C51編譯器的程序優化設計[J].電腦編程技巧與維護,2010,(2).