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