| [編者按]為使廣大嵌入式系統(tǒng)應(yīng)用技術(shù)人員系統(tǒng)地了解和掌握一些先進應(yīng)用、開發(fā)技術(shù),本刊從創(chuàng)刊號起開辟《學習園地》欄目。上半年將集中介紹嵌入式C編程技術(shù)(一)~(六),內(nèi)容包括單片機C語言應(yīng)用程序設(shè)計中的變量定義和變量空間、C語言編程技巧、函數(shù)有效使用及混合編程技術(shù)。 嵌入式C是指在嵌入式應(yīng)用中使用的C語言。在嵌入式應(yīng)用中非常注重的是代碼的時空效率,即產(chǎn)生的代碼的運行時間要盡可能少,占用的存儲空間(包括程序存儲器和數(shù)據(jù)存儲器)要盡可能小。單片機在國內(nèi)的嵌入式應(yīng)用領(lǐng)域使用最多,8051是單片機教學的首選機型,F(xiàn)以8051為例講解產(chǎn)生代碼的時空效率,C編譯器使用Franklin C51。用C語言進行嵌入式應(yīng)用的軟件開發(fā)是必然趨勢,程序設(shè)計應(yīng)該以C語言為主,匯編語言為輔。對匯編語言掌握到只要可以讀懂程序,在時間要求比較嚴格的模塊中進行程序的優(yōu)化即可。盡管懂匯編語言不是目的,但懂得一些匯編語言可幫助了解影響C語言效率的8051特殊限定。例如,懂得匯編語言指令就可知道使用片內(nèi)RAM做變量存儲的優(yōu)勢,因為片外變量需要幾條指令才能設(shè)置累加器和數(shù)據(jù)指針來存取。最好的嵌入式應(yīng)用的編程者應(yīng)是由匯編語言轉(zhuǎn)用C語言,而不是原來用過微機標準C語言的人員。下面將從變量定義和變量空間、C語言技巧、函數(shù)的有效使用、混合編程幾部分講述嵌入式C編程技術(shù)。本文不涉及C語言基礎(chǔ),可作為北京航空航天大學出版社出版的《單片機的C語言應(yīng)用程序設(shè)計》(修訂版)的提高篇。 一、 變量定義和變量空間 C語言是一種類型化語言。它要求對程序中使用的變量,在使用之前必須加以定義,說明其存儲屬性、存儲類型和數(shù)據(jù)類型,以便編譯系統(tǒng)給它分配存儲位置。 采用C語言編程,編譯器可以自動完成變量的存儲空間的分配。寄存器分配、不同存儲器的尋址及數(shù)據(jù)類型等細節(jié)問題由C編譯器管理,因而變量的定義至關(guān)重要,它關(guān)系到數(shù)據(jù)存儲器單元的使用和分配,也關(guān)系到產(chǎn)生代碼的長度。對8位單片機來講,直接支持的變量類型只有無符號字符和位。編程時要注意兩個原則,其一,總是使用可能的最小數(shù)據(jù)類型。8051系列單片機是8位機,因此,顯然對具有“char”類型的對象的操作比“int”或“l(fā)ong”類型的對象要方便得多。C51編譯器直接支持所有的字節(jié)操作,因而如果不是運算符要求,就不做“int”類型的轉(zhuǎn)換。這可用一個乘積運算來清楚說明,兩個“char”類型對象的乘積與8051指令“MUL AB”剛好相符。如果用整型量完成同樣的運算,則需要調(diào)用庫函數(shù)。其二,只要有可能,使用“unsigned”數(shù)據(jù)類型。8051系列單片機并不直接支持有符號數(shù)的運算,因而C51編譯器必須產(chǎn)生與之相關(guān)的更多的代碼以解決這個問題。如果使用無符號數(shù)據(jù)類型,產(chǎn)生的代碼要少得多。 無論何時,應(yīng)盡可能地使用無符號字符變量,因為它能直接被8051所接受。如果使用有符號和無符號兩種數(shù)據(jù)類型,那么就得使用兩種格式類型的庫函數(shù),占用的存儲空間成倍增長。須要進行額外的代碼操作來測試符號位,這無疑會降低代碼效率。 使用縮寫形式定義數(shù)據(jù)類型: #define uchar unsigned char #define uint unsigned int 這樣,在以后的編程中就可以用uchar代替unsigned char,用uint代替unsigned int來定義變量。頭文件reg51.h中有所有8051的SFR及可位尋址位的定義,只要: #include 這樣,在以后的編程中就可以使用: P1=0x10; TMOD=0x01; TR0=1; EA=1; 可以養(yǎng)成習慣,在每個程序的開頭都加上以下三行: #include #define uchar unsigned char #define uint unsigned int 本文下面將直接使用uchar和 uint,不再進行說明。 這部分講述C語言編程中的變量定義和變量空間。首先介紹單片機數(shù)據(jù)處理及其存儲器結(jié)構(gòu)特點,然后討論變量的存儲類型和變量存儲區(qū)域的關(guān)系,變量存儲屬性和變量有效范圍的關(guān)系,接著是C語言有效編程的幾個相關(guān)主題。 ·只讀變量和變量空間 討論在程序執(zhí)行過程中只讀的常數(shù)限定變量?赏ㄟ^使用“#define”定義減少變量占用空間,提高對象的存取效率。 ·使用自動變量減少變量占用空間 討論如何使用“auto”類型變量減少變量空間的大小,這樣只有定義它們的函數(shù)執(zhí)行時,變量的存儲單元才保留。 ·使用位域減少變量占用空間 討論如何使用位域減少變量占用空間。 ·使用聯(lián)合減少變量占用空間 討論如何使用聯(lián)合減少變量占用空間。 1. 存儲空間中的對象定位 8051系列單片機的存儲器是哈佛結(jié)構(gòu)的,其特點是將程序存儲器(ROM)和數(shù)據(jù)存儲器(RAM)分開,并有各自的尋址機構(gòu)和尋址方式。8051系列單片機在物理上有四個存儲空間: ·片內(nèi)(內(nèi)部)程序存儲器; ·片外(外部)程序存儲器; ·片內(nèi)(內(nèi)部)數(shù)據(jù)存儲器; ·片外(外部)數(shù)據(jù)存儲器。 在定位變量時,經(jīng)常訪問的數(shù)據(jù)對象應(yīng)放在內(nèi)部數(shù)據(jù)RAM中。訪問內(nèi)部數(shù)據(jù)存儲器要比訪問外部數(shù)據(jù)存儲器快得多。內(nèi)部數(shù)據(jù)RAM由寄存器組、位尋址區(qū)域和其他由用戶定義的變量共享。由于片內(nèi)RAM容量的限制(128~256字節(jié),由使用的單片機決定),必須權(quán)衡利弊以解決訪問效率和這些對象數(shù)量之間的矛盾。 在討論Franklin C51定義變量的數(shù)據(jù)類型的時候,必須同時提及它的存儲類型與8051單片機存儲器結(jié)構(gòu)的關(guān)系。因為Franklin C51是面向8051系列單片機及其硬件控制系統(tǒng)的開發(fā)工具。它定義的任何數(shù)據(jù)類型必須以一定的存儲類型的方式定位在8051的某一存儲區(qū)中,否則便沒有任何的實際意義。 在8051系列單片機中,程序存儲器與數(shù)據(jù)存儲器嚴格分開,特殊功能寄存器與片內(nèi)數(shù)據(jù)存儲器統(tǒng)一編址,這是單片機與一般微機的存儲器結(jié)構(gòu)有所不同的兩個特點。C51編譯器完全支持8051單片機的硬件結(jié)構(gòu),可完全訪問8051硬件系統(tǒng)的所有部分,支持直接尋址和間接尋址方式。該編譯器通過將變量、常量定義成不同的存儲類型(data,bdata,idata,pdata,xdata,code)的方法,將它們定位在不同的存儲區(qū)中。 存儲類型與8051單片機實際存儲空間的對應(yīng)關(guān)系如表1所列。 表1 當使用code存儲類型定義常量數(shù)據(jù)時,C51編譯器會將其定位在程序代碼空間(ROM或EPROM)。訪問內(nèi)部數(shù)據(jù)存儲區(qū)(data,bdata,idata)比訪問外部數(shù)據(jù)存儲區(qū)(xdata,pdata)相對要快一些,因此,可將經(jīng)常使用的變量置于內(nèi)部數(shù)據(jù)存儲區(qū)。 例: bit flag; 布爾值 code uchar table[]={1,2,3,”help”,oxff}; idata uint temp; data char var; / char data var; 等價,盡量用后一種 static unsigned long xdata array[100]; 靜態(tài)變量 extern float idata x,y,z; 外部變量 uint pdata dimension; uchar xdata vector[10][4]; char bdata flags; sbit flag0=flags^0; sbit P11=P1^1; 如果省略存儲類型,存儲模式將自動決定變量的默認存儲類型。存儲模式作為編譯選項如表2所列。 表2
|