Keil C51程序设计
轉(zhuǎn)自:http://www.dwenzhao.cn/profession/mcu/mcu51keilc.html
Keil C51程序設(shè)計(jì)
KeilC51是一種專為8051系列單片機(jī)設(shè)計(jì)的C編譯器,支持符合ANSI標(biāo)準(zhǔn)的C語言進(jìn)行程序設(shè)計(jì),同時(shí)針對8051系列單片機(jī)自身特點(diǎn)做了一些特殊擴(kuò)展。
1. KeilC51程序設(shè)計(jì)基本語法:
1)KeilC51程序的一般結(jié)構(gòu):
C51程序由一個(gè)或多個(gè)函數(shù)構(gòu)成,其中至少應(yīng)包含一個(gè)主函數(shù)main()。程序執(zhí)行時(shí),一定是從main()函數(shù)開始,調(diào)用其他函數(shù)后又返回main()函數(shù),被調(diào)用函數(shù)如果位于主調(diào)函數(shù)前面則可直接調(diào)用,否則要先說明后調(diào)用,函數(shù)之間可以互相調(diào)用。C51程序的一般結(jié)構(gòu)如下:
預(yù)處理命令 //用于包含頭文件等
全局變量說明; //全局變量可被本程序的所有函數(shù)引用
函數(shù)1說明;
......
函數(shù)n說明;
/*主函數(shù)*/
main(){
局部變量說明; //局部變量只能在所定義的函數(shù)內(nèi)部引用
執(zhí)行語句;
函數(shù)調(diào)用(形式參數(shù)表);
}
/*其他函數(shù)定義*/
函數(shù)1(形式參數(shù)定義){
局部變量說明; //局部變量只能在所定義的函數(shù)內(nèi)部引用
執(zhí)行語句;
函數(shù)調(diào)用(形式參數(shù)表);
}
......
函數(shù)n(形式參數(shù)定義){
局部變量說明; //局部變量只能在所定義的函數(shù)內(nèi)部引用
執(zhí)行語句;
函數(shù)調(diào)用(形式參數(shù)表);
}
由此可見,C51是由函數(shù)組成的,函數(shù)之間可以相互調(diào)用,但main()函數(shù)只能調(diào)用其他功能函數(shù),不能被其他函數(shù)調(diào)用。其他功能函數(shù),可以是C51編譯器提供的庫函數(shù),也可以是用戶按需要自行編寫的。不管main()函數(shù)處于程序中什么位置,程序總是從main()開始執(zhí)行。
編寫C51程序的注意點(diǎn):
①函數(shù)以“{”開始,以“}”結(jié)束,二者必須成對出現(xiàn),它們之間的部分為函數(shù)體。
②C51程序沒有行號(hào),一行內(nèi)可以書寫多條語句,一條語句也可以分寫在多行上。
③每條語句最后必須以一個(gè)分號(hào)“;”結(jié)尾,分號(hào)是C51程序的必要組成部分。
④每個(gè)變量必須先定義后引用。函數(shù)內(nèi)部定義的變量為局部變量,又稱內(nèi)部變量,只有在定義它的那個(gè)函數(shù)之內(nèi)才能夠使用。在函數(shù)外部定義的變量為全局變量,又稱外部變量,在定義它的那個(gè)程序文件中的函數(shù)都可以使用它。
⑤對程序語句的注釋必須放在雙斜杠“//”之后,或者放在“/*......*/”之內(nèi)。
2)數(shù)據(jù)類型:
C51數(shù)據(jù)類型可分為基本數(shù)據(jù)類型和復(fù)雜數(shù)據(jù)類型,復(fù)雜數(shù)據(jù)類型由基本數(shù)據(jù)類型構(gòu)造而成?;緮?shù)據(jù)類型有char(字符型)、int(整型)、long(長整型)、float(浮點(diǎn)型)和*(指針型)。下表列出了KeilC51編譯器能夠識(shí)別的數(shù)據(jù)類型:
|
數(shù)據(jù)類型 |
長度 |
值域 |
|
unsignedchar |
單字節(jié) |
0~255 |
|
signedchar |
單字節(jié) |
-128~+127 |
|
unsignedint |
雙字節(jié) |
0~65536 |
|
signedint |
雙字節(jié) |
-32768~+32767 |
|
unsignedlong |
四字節(jié) |
0~4294967295 |
|
signedlong |
四字節(jié) |
-2147483648~+2147483647 |
|
float |
四字節(jié) |
±1.175494E-38~±3.402823E+38 |
|
* |
1~3字節(jié) |
對象的地址 |
|
bit |
位 |
0或1 |
|
sfr |
單字節(jié) |
0~255 |
|
sfr16 |
雙字節(jié) |
0~65536 |
|
sbit |
位 |
0或1 |
KeilC51編譯器除了支持基本數(shù)據(jù)類型之外,還支持?jǐn)U充數(shù)據(jù)類型:
①bit:位類型,可以定義一個(gè)位變量,但不能定義位指針,也不能定義位數(shù)組。
②sfr:特殊功能寄存器,可以定義8051單片機(jī)的所有內(nèi)部8位特殊功能寄存器。sfr型數(shù)據(jù)占用一個(gè)內(nèi)存單元,其取值范圍是0~255。
③sfr16:16位特殊功能寄存器,它占用兩個(gè)內(nèi)存單元,取值范圍0~65535,可以定義8051單片機(jī)內(nèi)部的16位特殊功能寄存器。
④sbit:可尋址位,可以定義8051單片機(jī)內(nèi)部RAM中的可尋址位或特殊功能寄存器中的可尋址位。
示例:采用如下語句可以將8051單片機(jī)P0口地址定義為80H,將P0.1位定義為FLAG1。
sfrP0=80H;
sbitFLAG1=P0^1;
3)常量、變量及其存儲(chǔ)模式:
常量包括整型變量、浮點(diǎn)型變量、字符型常量及字符串常量等。
變量,是一種在程序執(zhí)行過程中其值能不斷變化的量。在使用一個(gè)變量之前,必須先進(jìn)行定義,用一個(gè)標(biāo)識(shí)符作為變量名并指出它的數(shù)據(jù)類型和存儲(chǔ)類型,以便編譯系統(tǒng)為它分配相應(yīng)的存儲(chǔ)單元。在C51中對變量進(jìn)行定義的格式如下:
[存儲(chǔ)種類]數(shù)據(jù)類型[存儲(chǔ)器類型]變量名表;
其中,“存儲(chǔ)種類”和“存儲(chǔ)器類型”是可選項(xiàng)。變量的存儲(chǔ)種類有4種:auto自動(dòng)、extern外部、static靜態(tài)和register寄存器。定義變量時(shí)如果省略存儲(chǔ)種類選項(xiàng),則該變量將為自動(dòng)變量。
KeilC51編譯器還允許說明變量的存儲(chǔ)器類型,使之能夠在8051單片機(jī)系統(tǒng)內(nèi)準(zhǔn)確地定位。下表列出了KeilC51編譯器所能識(shí)別的存儲(chǔ)器類型:
|
存儲(chǔ)器類型 |
說明 |
|
DATA |
直接尋址的片內(nèi)數(shù)據(jù)存儲(chǔ)器(128B),訪問速度最快 |
|
BDATA |
可位尋址的片內(nèi)數(shù)據(jù)存儲(chǔ)器(16B),允許位與字節(jié)混合訪問 |
|
IDATA |
間接訪問的片內(nèi)數(shù)據(jù)存儲(chǔ)器(256B),允許訪問全部片內(nèi)地址 |
|
PDATA |
分頁尋址的片外數(shù)據(jù)存儲(chǔ)器(256B),用MOVX@Ri指令訪問 |
|
XDATA |
片外數(shù)據(jù)存儲(chǔ)器(64KB),用MOVX@DPTR指令訪問 |
|
CODE |
程序存儲(chǔ)器(64KB),用MOVC@A+DPTR指令訪問 |
下面是一些變量定義的示例:
chardatavar1; //在DATA區(qū)定義字符型變量var1
intidatavar2; //在IDATA區(qū)定義整型變量var2
charcodetext[]=”ENTERPARAMETER”; //在CODE區(qū)定義字符串?dāng)?shù)組text[]
longxdataarray[100]; //在XDATA區(qū)定義長整數(shù)數(shù)組變量array[100]
externfloatidatax,y,z; //在IDATA區(qū)定義外部浮點(diǎn)型變量x,y,z
charbdataflags; //在BDATA區(qū)定義字符型變量flags
sbitflag0=flags^0; //在BDATA區(qū)定義可位尋址變量flag0
sfrP0=ox80; //定義特殊功能寄存器P0
定義變量時(shí)如果省略“存儲(chǔ)器類型”選項(xiàng),則按編譯時(shí)使用的存儲(chǔ)器模式SMALL、COMPACT或LARGE來規(guī)定默認(rèn)存儲(chǔ)器類型,確定變量的存儲(chǔ)器空間。函數(shù)中不能采用寄存器傳遞的參數(shù)變量的過程變量也保存在默認(rèn)的存儲(chǔ)器空間中。KeilC51編譯器的3種存儲(chǔ)器模式對變量的影響如下:
①SMALL:變量被定義在8051單片機(jī)片內(nèi)數(shù)據(jù)存儲(chǔ)器中,對這種變量的訪問速度最快。另外,所有的對象,包括堆棧,都位于片內(nèi)數(shù)據(jù)存儲(chǔ)器中,實(shí)際的堆棧長度取決于不同函數(shù)的嵌套深度。
②COMPACT:變量被定義在分頁尋址的片外數(shù)據(jù)存儲(chǔ)器中,每一頁片外數(shù)據(jù)存儲(chǔ)器的長度為256B。這時(shí)對變量的訪問是通過寄存器間接尋址(MOVX@Ri)進(jìn)行的,堆棧位于8051單片機(jī)片內(nèi)數(shù)據(jù)存儲(chǔ)器中。采用這種模式的同時(shí),必須適當(dāng)改變啟動(dòng)配置文件STARTUP.A51中的參數(shù)PDATASTART和PDATALEN;在用BL51進(jìn)行連接時(shí),還必須采用連接控制命令“PDATA”對P2口地址進(jìn)行定位,這樣才能確保P2口為所需要的高8位地址。
③LARGE:變量被定義在片外數(shù)據(jù)存儲(chǔ)器中(最大可達(dá)64KB),通常使用數(shù)據(jù)指針(DPTR)來間接訪問變量(MOVX@DPTR)。這種訪問數(shù)據(jù)的方法效率不高,尤其是對于2個(gè)以上字節(jié)的變量。
KeilC51編譯器在不同編譯模式下的存儲(chǔ)器類型:
|
編譯模式 |
存儲(chǔ)器類型 |
|
SMALL |
DATA |
|
COMPACT |
PDATA |
|
LARGE |
XDATA |
4)運(yùn)算符與表達(dá)式:
KeilC51對數(shù)據(jù)有很強(qiáng)的表達(dá)能力,具有十分豐富的運(yùn)算符。運(yùn)算符就是完成某種特定運(yùn)算的符號(hào),表達(dá)式則是由運(yùn)算符及運(yùn)算對象所組成的具有特定含義的算式。
運(yùn)算符,按其在表達(dá)式中所起的作用,可分為賦值運(yùn)算符、算術(shù)運(yùn)算符、增量與減量運(yùn)算符、關(guān)系運(yùn)算符、邏輯運(yùn)算符、位運(yùn)算符、復(fù)合賦值運(yùn)算符、逗號(hào)運(yùn)算符、條件運(yùn)算符、指針和地址運(yùn)算符、強(qiáng)制類型轉(zhuǎn)換運(yùn)算符等。
⑴賦值運(yùn)算符:
在C51程序中,符號(hào)“=”稱為賦值運(yùn)算符,作用是將一個(gè)數(shù)據(jù)的值賦給一個(gè)變量。
⑵算術(shù)運(yùn)算符:
C語言中的算術(shù)運(yùn)算符有+、-、*、/(除)和%(取余)運(yùn)算符。其中加、減和乘法都符合一般的算術(shù)運(yùn)算規(guī)則,但除法和取余有所不同。如果兩個(gè)整數(shù)相除,其結(jié)果為整數(shù),舍去小數(shù)部分;如果是兩個(gè)浮點(diǎn)數(shù)相除,其結(jié)果為浮點(diǎn)數(shù)。取余運(yùn)算要求兩個(gè)運(yùn)算對象均為整形數(shù)據(jù)。
⑶增量和減量運(yùn)算符:
C51還提供有一種特殊的運(yùn)算符,即++(增量)和--(減量)運(yùn)算符,作用分別是對運(yùn)算對象作加1和減1運(yùn)算。增量和減量運(yùn)算符只能用于變量,不能用于常數(shù)或表達(dá)式,在使用中還要注意運(yùn)算符的位置。例如,++i與i++的意義不同,前者為在使用i前先使i加1,而后者則是在使用i之后再使i的值加1。
⑷關(guān)系運(yùn)算符:
C語言中有以下6種關(guān)系運(yùn)算符:>、<、>=、<=、==、!=。用關(guān)系運(yùn)算符將兩個(gè)表達(dá)式連接起來即稱為關(guān)系表達(dá)式。
⑸邏輯表達(dá)式:
C51中有以下3種邏輯運(yùn)算符:||(邏輯或)、&&(邏輯與)、!(邏輯非)。用邏輯運(yùn)算符將關(guān)系表達(dá)式或邏輯量連接起來即稱為邏輯表達(dá)式。
關(guān)系運(yùn)算符和邏輯運(yùn)算符通常用來判別某個(gè)條件是否滿足,關(guān)系運(yùn)算和邏輯運(yùn)算的結(jié)果只有0和1兩種值。當(dāng)所指定的條件滿足時(shí)結(jié)果為1,條件不滿足時(shí)結(jié)果為0。
⑹位運(yùn)算符:
C51中共有以下6種位運(yùn)算符:~(按位取反)、<<(左移)、>>(右移)、&(按位與)、^(按位異或)、|(按位或)。為運(yùn)算符的作用是按位對變量進(jìn)行運(yùn)算。位運(yùn)算符不能用來對浮點(diǎn)型數(shù)據(jù)進(jìn)行操作。
⑺復(fù)合賦值運(yùn)算符:
在賦值運(yùn)算符“=”的前面加上其他運(yùn)算符,就構(gòu)成了復(fù)合賦值運(yùn)算符。C51中共有以下10種復(fù)合賦值運(yùn)算符:+=(加法賦值)、-=(減法賦值)、*=(乘法賦值)、/=(除法賦值)、%=(取模賦值)、<<=(左移位賦值)、>>=(右移位賦值)、&=(邏輯與賦值)、|=(邏輯或賦值)、^=(邏輯異或賦值)、~=(邏輯非賦值)。
復(fù)合賦值運(yùn)算,首先對變量進(jìn)行某種操作,然后將運(yùn)算的結(jié)果再賦給該變量。采用復(fù)合賦值運(yùn)算符,可以使程序簡化,同時(shí)還可以提高程序的編譯效率。
⑻逗號(hào)運(yùn)算符:
在C51程序中,逗號(hào)“,”是一種特殊的運(yùn)算符,用逗號(hào)運(yùn)算符連接起來的兩個(gè)(或多個(gè))表達(dá)式,稱為逗號(hào)表達(dá)式。在程序運(yùn)行時(shí),對逗號(hào)表達(dá)式的處理是從左至右依次計(jì)算出各個(gè)表達(dá)式的值,而整個(gè)逗號(hào)表達(dá)式的值是最右邊表達(dá)式(即表達(dá)式n)的值。
⑼條件運(yùn)算符:
條件運(yùn)算符“?:”是C51中唯一的三目運(yùn)算符,它要求有3個(gè)運(yùn)算對象,用它可以將3個(gè)表達(dá)式連接構(gòu)成一個(gè)條件表達(dá)式。條件表達(dá)式的一般形式如下:
邏輯表達(dá)式?表達(dá)式1:表達(dá)式2
其功能是:首先計(jì)算邏輯表達(dá)式,當(dāng)值為真(非0值)時(shí),將表達(dá)式1的值作為整個(gè)條件表達(dá)式的值;當(dāng)邏輯表達(dá)式的值為假(0值)時(shí),將表達(dá)式2的值作為整個(gè)條件表達(dá)式的值。
例如,條件表達(dá)式max=(a>b)?a:b的執(zhí)行結(jié)果是將a和b中的較大者賦值給變量max。另外,條件表達(dá)式中邏輯表達(dá)式的類型可以與表達(dá)式1和表達(dá)式2的類型不一樣。
⑽指針和地址運(yùn)算符:
C51中專門規(guī)定了一種指針類型的數(shù)據(jù),變量的指針就是該變量的地址,還可以定義一個(gè)指向某個(gè)變量的指針變量。C51提供了以下兩個(gè)專門的運(yùn)算符:*(取內(nèi)容)、&(取地址)。
取內(nèi)容和取地址運(yùn)算的一般形式如下:
變量=*指針變量
指針變量=&目標(biāo)變量
取內(nèi)容運(yùn)算的含義是將指針變量所指向的目標(biāo)變量的值賦給左邊的變量;取地址運(yùn)算的含義是將目標(biāo)變量的地址賦給左邊的變量。需要注意,指針變量中只能存放地址(即指針型數(shù)據(jù)),不要將一個(gè)非指針類型的數(shù)據(jù)賦值給一個(gè)指針變量。示例:
chardata*p//定義指針變量
p=30H//給指針變量賦值,30H為8051片內(nèi)RAM地址
⑾C51對存儲(chǔ)器和特殊功能寄存器的訪問:
由于8051單片機(jī)存儲(chǔ)器結(jié)構(gòu)自身的特點(diǎn),C51提供了利用庫函數(shù)中的絕對地址訪問頭文件“absacc.h”來訪問不同區(qū)域的存儲(chǔ)器以及片外擴(kuò)展I/O端口的方法。
在“absacc.h”頭文件中進(jìn)行了如下宏定義:
CBYTE[地址](訪問CODE區(qū)char型)
DBYTE[地址](訪問DATA區(qū)char型)
PBYTE[地址](訪問PDATA區(qū)或I/O端口char型)
XBYTE[地址](訪問XDATA區(qū)或I/O端口char型)
CWORD[地址](訪問CODE區(qū)int型)
DWORD[地址](訪問DATA區(qū)int型)
PWORD[地址](訪問PDATA區(qū)或I/O端口int型)
XWORD[地址](訪問XDATA區(qū)或I/O端口int型)
下面的語句是向片外擴(kuò)展端口地址7FFFH寫入一個(gè)字符型數(shù)據(jù):
XBYTE[0x7FFF]=0x80;
下面的語句是將int型數(shù)據(jù)0x9988送入外部RAM單元0000H和0001H:
XWORD[0]=0x9988;
如果采用如下語句定義一個(gè)D/A轉(zhuǎn)換器端口地址:
#defineDAC0832XBYTE[0x7FFF]
那么程序文件中所有出現(xiàn)DAC0832的地方,就是對地址為0x7FFFH的外部RAM單元或I/O端口進(jìn)行訪問。
8051單片機(jī)具有100多個(gè)品種,為了方便訪問不同品種單片機(jī)內(nèi)部特殊功能寄存器,C51提供了多個(gè)相關(guān)頭文件,如reg51.h、reg52.h等。在頭文件中,對單片機(jī)內(nèi)部特殊功能寄存器及其可尋址位進(jìn)行了定義,編程時(shí)只要根據(jù)所采用的單片機(jī),在程序文件的開始處用文件包含處理命令“#include”將相關(guān)頭文件包含進(jìn)來,然后就可以直接引用特殊功能寄存器了。例如,下面語句完成的8051定時(shí)方式寄存器TMOD的賦值:
#include<reg51.h>
TMOD=0x20;
⑿強(qiáng)制類型轉(zhuǎn)換運(yùn)算符:
C語言中的圓括號(hào)“()”也可作為一種運(yùn)算符使用,這就是強(qiáng)制類型轉(zhuǎn)換運(yùn)算符,它的作用是將表達(dá)式或變量的類型強(qiáng)制轉(zhuǎn)換成為所指定的類型。
數(shù)據(jù)類型轉(zhuǎn)換分為隱式轉(zhuǎn)換和顯式轉(zhuǎn)換。隱式轉(zhuǎn)換是在對程序編譯時(shí)由編譯器自動(dòng)處理的,并且只有基本數(shù)據(jù)類型(即char、int、long和float)可以進(jìn)行隱式轉(zhuǎn)換,其他數(shù)據(jù)類型不能進(jìn)行隱式轉(zhuǎn)換,這種情況下就必須利用強(qiáng)制類型轉(zhuǎn)換運(yùn)算符來進(jìn)行顯式轉(zhuǎn)換。強(qiáng)制類型轉(zhuǎn)換運(yùn)算符的一般使用形式如下:
(類型)=表達(dá)式
顯式強(qiáng)制類型轉(zhuǎn)換在給指針變量賦值時(shí)特別有用。例如,預(yù)先在8051單片機(jī)的片外數(shù)據(jù)存儲(chǔ)器(XDATA)中定義了一個(gè)字符型指針變量px,如果想給這個(gè)指針變量賦一初值0xB000,可以寫成px=(charxdata*)0xB00
2. C51程序的基本語句:
C51提供了十分豐富的程序控制語句。
1)表達(dá)式語句:
表達(dá)式語句是最基本的一種語句。在表達(dá)式的后面加一個(gè)分號(hào)“;”,就構(gòu)成了表達(dá)式語句。表達(dá)式語句也可以僅由一個(gè)分號(hào)“;”組成,這種語句稱為空語句。當(dāng)程序在語法上需要有一個(gè)語句,但在語義上并不要求有具體的動(dòng)作時(shí),便可以采用空語句。
2)復(fù)合語句:
復(fù)合語句,是由若干條語句組合而成的一種語句,是用“{}”將若干條語句組合在一起而形成的功能塊,內(nèi)部的各條單語句需以“;”結(jié)束。復(fù)合語句的一般形式如下:
{
局部變量定義;
語句1;
語句2;
......
語句n;
}
復(fù)合語句在執(zhí)行時(shí),其中各條語句依次順序執(zhí)行。整個(gè)復(fù)合語句在語法上等價(jià)于一條單語句。復(fù)合語句允許嵌套,即在復(fù)合語句內(nèi)部還可以包含其他的復(fù)合語句。實(shí)際上,函數(shù)的執(zhí)行部分(函數(shù)體)就是一個(gè)復(fù)合語句。復(fù)合語句中的單語句一般是可執(zhí)行語句,也可以是變量定義語句。在復(fù)合語句內(nèi)所定義的變量,稱為該復(fù)合語句中的局部變量,僅在當(dāng)前復(fù)合語句中有效。
3)條件語句:
條件語句,又稱為分支語句,是用關(guān)鍵字“if”構(gòu)成的。C51提供了3種形式的條件語句:
①if(表達(dá)式)語句
含義是:若條件表達(dá)式的結(jié)果為真(非0值),執(zhí)行后面的語句;反之,若條件表達(dá)式的結(jié)果為假(0值),不執(zhí)行后面的語句。其中的語句也可以是復(fù)合語句。
②if(表達(dá)式)語句1
else語句2
含義是:若條件表達(dá)式的結(jié)果為真(非0值),執(zhí)行語句1;反之,若條件表達(dá)式的結(jié)果為假(0值),執(zhí)行語句2。其中的語句都可以是復(fù)合語句。
③if(條件表達(dá)式1)語句1
elseif(條件表達(dá)式2)語句2
elseif(條件表達(dá)式3)語句3
......
elseif(條件表達(dá)式m)語句m
else語句n
這種條件語句常用來實(shí)現(xiàn)多方向條件分支。當(dāng)分支較多時(shí),會(huì)使條件語句的嵌套層次太多,程序冗長,可讀性降低。
4)開關(guān)語句:
開關(guān)語句也是一種用來實(shí)現(xiàn)多方向條件分支的語句。開關(guān)語句直接處理多分支選擇,使程序結(jié)構(gòu)清晰,使用方便。開關(guān)語句是用關(guān)鍵字switch構(gòu)成的,一般形式如下:
switch(表達(dá)式)
{
case常量表達(dá)式1:語句1;
break;
case常量表達(dá)式2:語句2;
break;
......
case常量表達(dá)式n:語句n;
break;
default:語句d;
}
開關(guān)語句的執(zhí)行過程是:將switch后面的表達(dá)式的值與case后面各個(gè)常量表達(dá)式的值逐個(gè)進(jìn)行比較,若遇到匹配時(shí),就執(zhí)行相應(yīng)case后面的語句,然后執(zhí)行break語句。若無匹配的情況,則只執(zhí)行default后面的語句d。break語句又稱間斷語句,功能是中止當(dāng)前語句的執(zhí)行,使程序跳出switch語句。
5)循環(huán)語句:
實(shí)際應(yīng)用中,很多地方要用到循環(huán)控制,如對于某種操作需要反復(fù)進(jìn)行多次等。在C51程序中,用來構(gòu)成循環(huán)控制的語句有while、do-while、for以及goto等形式的語句。
①采用while構(gòu)成的循環(huán)結(jié)構(gòu):
while(表達(dá)式)語句;
含義是:當(dāng)條件表達(dá)式的結(jié)果為真(非0值)時(shí),程序就重復(fù)執(zhí)行后面的語句,一直執(zhí)行到條件表達(dá)式的結(jié)果變?yōu)榧伲?值)為止。這種循環(huán)結(jié)構(gòu)是先檢查條件表達(dá)式所給出的條件,再根據(jù)檢查結(jié)果決定是否執(zhí)行后面的語句。如果條件表達(dá)式的結(jié)果一開始就為假,則后面的語句一次也不會(huì)被執(zhí)行。這里的語句可以是復(fù)合語句。
②采用do-while構(gòu)成的循環(huán)結(jié)構(gòu):
do語句while(表達(dá)式);
含義是:當(dāng)條件表達(dá)式的值為真(非0值)時(shí),則重復(fù)執(zhí)行循環(huán)體語句,直到條件表達(dá)式的值變?yōu)榧伲?值)為止。這種循環(huán)結(jié)構(gòu)是先執(zhí)行給定的循環(huán)語句,然后再檢查條件表達(dá)式的結(jié)果,任何條件下循環(huán)體語句至少會(huì)被執(zhí)行一次。
③采用for構(gòu)成的循環(huán)結(jié)構(gòu):
for([初值設(shè)定表達(dá)式];[循環(huán)條件表達(dá)式];[更新表達(dá)式])語句;
for語句的執(zhí)行過程是:先計(jì)算初值表達(dá)式的值作為循環(huán)控制變量的初值,再檢查循環(huán)條件表達(dá)式的結(jié)果,當(dāng)滿足條件時(shí)就執(zhí)行循環(huán)體語句并計(jì)算更新表達(dá)式,然后再根據(jù)更新表達(dá)式的計(jì)算結(jié)果來判斷循環(huán)條件是否滿足......一直進(jìn)行到循環(huán)條件表達(dá)式的結(jié)果為假(0值)時(shí)退出循環(huán)體。
6)goto、break、continue語句:
①goto語句:
是一個(gè)無條件轉(zhuǎn)向語句,它的一般形式如下:
goto語句標(biāo)號(hào);
其中,語句標(biāo)號(hào)是一個(gè)帶冒號(hào)“:”的標(biāo)識(shí)符。將goto語句與if語句一起使用,可以構(gòu)成一個(gè)循環(huán)語句,但更常見的是采用goto語句來跳出多重循環(huán)。需要注意,只能用goto語句從內(nèi)層循環(huán)跳到外層循環(huán),而不允許從外層循環(huán)跳到內(nèi)層循環(huán)。
②break語句:
break語句也用于跳出循環(huán)語句,只能用于開關(guān)語句和循環(huán)語句中,是一種具有特殊功能的無條件轉(zhuǎn)移語句。對于多重循環(huán)的情況,break語句只能跳出它所處的那一層循環(huán)。
③continue語句:
continue語句是一種中斷語句,功能是中斷本次循環(huán),通常和條件語句一起用在由while、do-while和for語句構(gòu)成的循環(huán)結(jié)構(gòu)中,也是一種具有特殊功能的無條件轉(zhuǎn)移語句。但與break語句不同,continue語句并不跳出循環(huán)體,而只是根據(jù)循環(huán)控制條件確定是否繼續(xù)執(zhí)行循環(huán)語句。
7)返回語句:
返回語句用于終止函數(shù)的執(zhí)行,并控制程序返回到調(diào)用該函數(shù)時(shí)所處的位置。返回語句有兩種形式:
return(表達(dá)式);
return;
如果return語句后面帶有表達(dá)式,則要計(jì)算表達(dá)式的值,并將表達(dá)式的值作為該函數(shù)的返回值。若使用不帶表達(dá)式的形式,則被調(diào)用函數(shù)返回主函數(shù)時(shí)函數(shù)值不確定。一個(gè)函數(shù)的內(nèi)部,可以含有多個(gè)return語句,但程序僅執(zhí)行其中的一個(gè)return語句而返回主調(diào)用函數(shù)。一個(gè)函數(shù)的內(nèi)部也可以沒有return語句,在這種情況下,當(dāng)程序執(zhí)行到最后一個(gè)界限符“}”處時(shí),就自動(dòng)返回主調(diào)函數(shù)。
3. 函數(shù):
從用戶的角度看,有兩種函數(shù),即標(biāo)準(zhǔn)庫函數(shù)和用戶自定義函數(shù)。標(biāo)準(zhǔn)庫函數(shù)是KeilC51編譯器提供的,可以直接調(diào)用;用戶自定義函數(shù)是用戶根據(jù)自己的需要編寫的,必須先進(jìn)行定義之后才能調(diào)用。
1)函數(shù)的定義:
函數(shù)定義的一般形式如下:
函數(shù)類型函數(shù)名(形式參數(shù)表)
{
局部變量定義;
函數(shù)體語句;
}
其中,函數(shù)類型說明了自定義函數(shù)返回值的類型;函數(shù)名是用標(biāo)識(shí)符表示的自定義函數(shù)的名字;形式參數(shù)表中則列出了主調(diào)用函數(shù)與被調(diào)用函數(shù)之間傳遞的數(shù)據(jù),形式參數(shù)的類型必須加以說明。局部變量是對在函數(shù)內(nèi)部使用的局部變量進(jìn)行定義;函數(shù)體語句是為完成該函數(shù)的特定功能而設(shè)置的各種語句。
ANSIC標(biāo)準(zhǔn),允許在形式參數(shù)表中對形式參數(shù)的類型進(jìn)行說明。如果定義的是無參函數(shù),可以沒有形式參數(shù)表,但圓括號(hào)“()”不能省略。
2)函數(shù)的調(diào)用:
所謂函數(shù)調(diào)用,就是在一個(gè)函數(shù)體中引用另外一個(gè)已經(jīng)定義了的函數(shù),前者稱為主調(diào)函數(shù),后者稱為被調(diào)用函數(shù)。C51程序中,函數(shù)是可以互相調(diào)用的。函數(shù)調(diào)用的一般形式為:
函數(shù)名(實(shí)際參數(shù)表)
其中,函數(shù)名指出被調(diào)用的函數(shù);實(shí)際參數(shù)表中可以包括多個(gè)實(shí)際參數(shù),各個(gè)參數(shù)之間用逗號(hào)“,”分開。實(shí)際參數(shù)的作用是將它的值傳遞給被調(diào)用函數(shù)中的形式參數(shù)。需要注意,函數(shù)調(diào)用中的實(shí)際參數(shù)與函數(shù)定義中的形式參數(shù)必須在個(gè)數(shù)、類型及順序上嚴(yán)格保持一致,以便將實(shí)際參數(shù)的值正確地傳遞給形式參數(shù),否則在函數(shù)調(diào)用時(shí)會(huì)產(chǎn)生意想不到的結(jié)果。如果調(diào)用的是無參函數(shù),則可以沒有形式參數(shù)表,但圓括號(hào)“()”不能省略。
C51中可以采用3種方式完成函數(shù)的調(diào)用:
①函數(shù)語句:
在主調(diào)函數(shù)中,將函數(shù)調(diào)用作為一條語句。這是無參調(diào)用,不要求被調(diào)用函數(shù)返回一個(gè)確定的值,只要求它完成一定的操作。
②函數(shù)表達(dá)式:
在主調(diào)函數(shù)中,將函數(shù)調(diào)用作為一個(gè)運(yùn)算對象直接出現(xiàn)在表達(dá)式中,這種表達(dá)式稱為函數(shù)表達(dá)式。這種函數(shù)調(diào)用方式通常要求被調(diào)用函數(shù)返回一個(gè)確定的值。
③函數(shù)參數(shù):
在主調(diào)函數(shù)中,將函數(shù)調(diào)用作為另一個(gè)函數(shù)調(diào)用的實(shí)際參數(shù)。這種在調(diào)用一個(gè)函數(shù)的過程中又調(diào)用了另外一個(gè)函數(shù)的方式,稱為嵌套函數(shù)調(diào)用。
3)函數(shù)的說明:
與使用變量一樣,在調(diào)用一個(gè)函數(shù)之前(包括標(biāo)準(zhǔn)庫函數(shù)),必須對該函數(shù)的類型進(jìn)行說明,即“先說明,后調(diào)用”。如果調(diào)用的是庫函數(shù),一般應(yīng)在程序的開始處用預(yù)處理命令#include將有關(guān)函數(shù)說明的頭文件包含進(jìn)來。
如果調(diào)用的是用戶自定義函數(shù),而且函數(shù)與調(diào)用它的主調(diào)函數(shù)在同一個(gè)文件中,一般應(yīng)該在主調(diào)用函數(shù)中對被調(diào)用函數(shù)的類型進(jìn)行說明。函數(shù)說明的一般形式如下:
類型標(biāo)識(shí)符被調(diào)用的函數(shù)名(形式參數(shù)表);
其中,類型標(biāo)識(shí)符說明了函數(shù)的返回值的類型;形式參數(shù)表說明了各個(gè)形式參數(shù)的類型。
需要注意,函數(shù)定義與函數(shù)說明是完全不同的,書寫方式上也有差別。函數(shù)定義時(shí),被定義函數(shù)名的圓括號(hào)后面沒有分號(hào)“;”,函數(shù)定義還未結(jié)束,后面應(yīng)接著寫被定義的函數(shù)體部分;而函數(shù)說明結(jié)束時(shí),在圓括號(hào)的后面需要有一個(gè)分號(hào)“;”作為結(jié)束標(biāo)志。
4)中斷服務(wù)函數(shù):
C51支持在C語言源程序中直接編寫8051單片機(jī)的中斷服務(wù)函數(shù)程序,一般形式為:
函數(shù)類型函數(shù)名(形式參數(shù)表)[interruptn][usingn]
關(guān)鍵字interrupt后面的n是中斷號(hào),n的取值范圍為0~31.編譯器從8n+3處產(chǎn)生中斷向量,具體的中斷號(hào)n和中斷向量取決于8051系列單片機(jī)芯片的型號(hào)。常用的中斷源與中斷向量表如下表:
|
中斷號(hào)n |
中斷源 |
中斷向量8n+3 |
|
0 |
外部中斷0 |
0003H |
|
1 |
定時(shí)器0 |
000BH |
|
2 |
外部中斷1 |
0013H |
|
3 |
定時(shí)器1 |
001BH |
|
4 |
串行口 |
0023H |
8051系列單片機(jī)可以在片內(nèi)PAM中使用4個(gè)不同的工作寄存器組,每個(gè)寄存器組中包含8個(gè)工作寄存器(R0~R7)。C51編譯器擴(kuò)展了一個(gè)關(guān)鍵字using,專門用來選擇8051單片機(jī)中不同的工作寄存器組。using后面的n是一個(gè)0~3的常整數(shù),分別選中4個(gè)不同的工作寄存器組。在定義一個(gè)函數(shù)時(shí),using是一個(gè)選項(xiàng),如果不用該選項(xiàng),則由編譯器自動(dòng)選擇一個(gè)寄存器組做絕對寄存器組訪問。
編寫8051單片機(jī)中斷函數(shù)時(shí)應(yīng)遵循以下規(guī)則:
①中斷函數(shù)不能進(jìn)行參數(shù)傳遞,也沒有返回值,因此一般定義為void型。
②在任何情況下都不能直接調(diào)用中斷函數(shù),否則會(huì)產(chǎn)生編譯錯(cuò)誤。
③如果中斷函數(shù)中調(diào)用了其他函數(shù),則被調(diào)用函數(shù)所使用的寄存器組必須與中斷函數(shù)相同。
④C51編譯器從絕對地址8n+3處產(chǎn)生一個(gè)中斷向量,其中n為中斷號(hào),該向量包含一個(gè)到中斷函數(shù)入口地址的絕對跳轉(zhuǎn)。
5. KeilC51編譯器對ANSIC的擴(kuò)展:
1)存儲(chǔ)器類型:
8051單片機(jī)的存儲(chǔ)器空間可分為片內(nèi)外統(tǒng)一編址的程序寄存器ROM、片內(nèi)數(shù)據(jù)存儲(chǔ)器RAM和片外數(shù)據(jù)存儲(chǔ)器RAM。
①C51編譯器對ROM存儲(chǔ)器提供了存儲(chǔ)器類型標(biāo)識(shí)符code,用戶的應(yīng)用程序代碼以及各種表格常數(shù)被定為在code空間。
②數(shù)據(jù)存儲(chǔ)器RAM用于存放各種變量,通常應(yīng)盡可能將變量放在片內(nèi)RAM中以加快操作速度。C51編譯器對片內(nèi)RAM提供了3種存儲(chǔ)器類型標(biāo)識(shí)符,即data、idata、bdata。data地址范圍為0x00~0x7f,位于data空間的變量以直接尋址方式操作,速度很快;idata地址范圍為0x00~0xff,位于idata空間的變量以寄存器間接尋址方式操作,速度略慢于data空間;bdata地址范圍為0x20~0x2f,位于bdata空間的變量,除了可以進(jìn)行直接尋址或間接尋址之外,還可以進(jìn)行位尋址操作。
③片外數(shù)據(jù)RAM簡稱XRAM,C51提供了xdata和pdata兩個(gè)存儲(chǔ)器類型標(biāo)識(shí)符。xdata空間地址范圍為0x0000~0xffff,位于xdata空間的變量以MOVX@DPTR方式尋址,可以操作整個(gè)64KB地址范圍內(nèi)的變量,但這種方式速度最慢;pdata空間又稱為片外分頁XRAM空間,它將地址0x0000~0xffff均勻地分成256頁,每頁地址都為0x00~0xff,位于pdata空間的變量以MOVX@R0、MOVX@R1方式尋址。實(shí)際上,XRAM空間并非全部用于存放變量,用戶擴(kuò)展的I/O接口也位于XRAM地址范圍之內(nèi)。有些新型的80C51單片機(jī)還提供有片內(nèi)XRAM,其操作方式與傳統(tǒng)的XRAM相同,但一般要先對相應(yīng)的特殊功能寄存器(SFR)進(jìn)行配置之后才能使用。
一些新型的8051單片機(jī)能夠進(jìn)行大容量存儲(chǔ)器擴(kuò)展,如到8MB甚至16MB的code和xdata存儲(chǔ)器空間。C51編譯器針對這種大容量擴(kuò)展存儲(chǔ)器定義了far和constfar兩種存儲(chǔ)器類型,分別用以操作這種擴(kuò)展的片外RAM和片外ROM空間。
對于傳統(tǒng)的8051單片機(jī),如果具有可以映射到xdata的附加存儲(chǔ)器空間,或者提供了一種地址擴(kuò)展特殊功能寄存器,則可以根據(jù)具體硬件電路通過修改配置文件XBANKING.A51來使用far和constfar類型的變量。需要注意,在使用far和constfar存儲(chǔ)器類型時(shí),必須采用LX51擴(kuò)展連接定位器,同時(shí)還必須采用OMF2格式的目標(biāo)文件。
下表列出了KeilC51編譯器能夠識(shí)別的存儲(chǔ)器類型:
|
存儲(chǔ)器類型 |
說明 |
|
code |
程序存儲(chǔ)器(64KB),用MOVC@A+DPTR指令訪問 |
|
data |
直接尋址的片內(nèi)數(shù)據(jù)存儲(chǔ)器(128B),訪問速度最快 |
|
idata |
間接訪問的片內(nèi)數(shù)據(jù)存儲(chǔ)器(256B),允許訪問全部片內(nèi)地址 |
|
bdata |
可位尋址的片內(nèi)數(shù)據(jù)存儲(chǔ)器(16B),允許位與字節(jié)混合訪問 |
|
xdata |
片外數(shù)據(jù)存儲(chǔ)器(64KB),用MOVX@DPTR指令訪問 |
|
pdata |
分頁尋址的片外數(shù)據(jù)存儲(chǔ)器(256B),用MOVX@R0、MOVX@R1指令訪問 |
|
far |
高達(dá)16MB的擴(kuò)展RAM和ROM,專用芯片擴(kuò)展訪問或用戶自定義子程序進(jìn)行訪問 |
2)編譯模式:
如果定義變量時(shí)沒有明確指出具體的存儲(chǔ)器類型,則按C51編譯器采用的編譯模式來確定變量的默認(rèn)存儲(chǔ)器空間。KeilC51編譯器控制命令SMALL、COMPACT、LARGE對變量存儲(chǔ)空間的影響如下:
①SMALL:所有變量都被定義在8051單片機(jī)的片內(nèi)RAM中,對這種變量的訪問速度最快。另外,堆棧也必須位于片內(nèi)RAM中,實(shí)際的堆棧長度取決于不同函數(shù)的嵌套深度。采用SMALL編譯模式,與定義變量時(shí)指定data存儲(chǔ)器類型具有相同的效果。
②COMPACT:所有變量被定義在分頁尋址的片外XRAM中,每一頁片外XRAM的長度都為256B。這時(shí)對變量的訪問是通過寄存器間接尋址(MOVX@R0、MOVX@R1)進(jìn)行的,變量的低8位地址由R0或R1確定,變量的高8位地址由P2口確定。采用這種模式時(shí),必須適當(dāng)改變配置文件STARTUP.A51中參數(shù)PDATASTART和PDATALEN;同時(shí)還必須在編譯器菜單“option選項(xiàng)/BL51Locator標(biāo)簽欄/Pdata”打開的對話框中鍵入合適的地址參數(shù),以確保P2口能輸出所需要的高8位地址。而堆棧則位于8051單片機(jī)片內(nèi)數(shù)據(jù)存儲(chǔ)器中。采用COMPACT編譯模式,與定義變量時(shí)指定pdata存儲(chǔ)器類型具有相同的效果。
③LARGE:所有變量被定義在片外XRAM中(最大可達(dá)64KB),通常使用數(shù)據(jù)指針(DPTR)來間接訪問變量(MOVX@DPTR)。這種編譯模式對數(shù)據(jù)訪問的效率最低,而且將增加程序的代碼長度。采用LARGE編譯模式與定義變量時(shí)指定xdata存儲(chǔ)器類型具有相同的效果。
3)數(shù)據(jù)類型bit、sbit、sfr、sfr16:
KeilC51編譯器支持標(biāo)準(zhǔn)C語言的數(shù)據(jù)類型,另外還根據(jù)8051單片機(jī)的特點(diǎn)擴(kuò)展了數(shù)據(jù)類型,如bit、sbit、sfr、sfr16。
①bit:所有bit類型的變量都被定位在8051片內(nèi)RAM的可位尋址區(qū)。由于8051單片機(jī)的可位尋址區(qū)只有16個(gè)字節(jié)長,所以在某個(gè)范圍內(nèi)最多只能聲明128個(gè)bit類型變量。聲明bit類型變量時(shí),可以帶有存儲(chǔ)器類型data、idata或bdata。對于bit類型變量有如下限制:如果在函數(shù)中采用預(yù)處理命令“#pragmadisable”禁止了中斷,或者在函數(shù)聲明時(shí)采用關(guān)鍵字“usingn”明確進(jìn)行了寄存器組切換,則該函數(shù)不能返回bit類型的值,否則C51在進(jìn)行編譯時(shí)會(huì)產(chǎn)生編譯錯(cuò)誤;另外,不能定義bit類型指針,也不能定義bit類型數(shù)組。
②sbit:sbit用于定義可獨(dú)立尋址訪問的位變量。C51編譯器提供了一個(gè)存儲(chǔ)器類型bdata,帶有bdata存儲(chǔ)器類型的變量被定為在8051單片機(jī)片內(nèi)RAM的可位尋址區(qū)。帶有bdata存儲(chǔ)器類型的變量可以進(jìn)行字節(jié)尋址,也可以進(jìn)行位尋址,因此對bdata變量可用sbit指定其中任一位為可位尋址變量。需要注意,采用bdata及sbit所定義的變量都必須是全局變量,并且采用sbit定義可位尋址變量時(shí)要求基址對象的存儲(chǔ)器類型為bdata。
例如,可先定義變量的數(shù)據(jù)類型和存儲(chǔ)器類型:
intbdataibase;//定義ibase為bdata整型變量
charbdatabary[4];//定義bary[4]為bdata字符型數(shù)組
然后使用sbit定義可位尋址變量:
sbitmybit0=ibase^0;//定義mybit0為ibase的第0位
sbitmybit15=ibase^15;//定義mybit15為ibase的第15位
sbitAry07=bary[0]^7;//定義Ary07為bary[0]的第7位
sbitAry37=bary[3]^7;//定義Ary37為bary[3]的第7位
操作符“^”后面的數(shù)值范圍取決于基址變量的數(shù)據(jù)類型,對于char型是0~7,對于int型是0~15,對于long型是0~31。bdata變量ibase和bdata數(shù)組bary[4]可以進(jìn)行字或字節(jié)尋址,sbit變量可以直接操作可尋址位。例如:
ibase=-1;//字尋址,對ibase賦值為-1
bary[3]=’a’;//字節(jié)尋址,對bary[3]賦值為’a’
Ary37=0;//清0bary[3]的第7位
mybit15=1;//置1ibase的第15位
對bdata變量可以向?qū)ata變量一樣處理,所不同的是,bdata變量必須位于8051單片機(jī)的片內(nèi)RAM的可位尋址區(qū),其長度不能超過16個(gè)字節(jié)。
sbit還可以用于定義結(jié)構(gòu)與聯(lián)合,利用這一特點(diǎn)可以實(shí)現(xiàn)對float型數(shù)據(jù)指定bit變量。例如:
unionlft{
floatmf;
longml;
};
bdatastructbad{
charmc;
unionlftu;
}tcp;
sbirtcpf31=tcp.u.ml^31;//float數(shù)據(jù)的第31位
sbirtcpm10=tcp.mc^0;
sbirtcpm17=tcp.mc^7;
采用sbit類型時(shí),需要指定一個(gè)變量作為基地址,再通過指定該基地址變量的bit位來獲得實(shí)際的物理bit地址。并不是所有類型變量的物理bit地址都與其邏輯bit地址相一致。物理上的bit0對應(yīng)第一個(gè)字節(jié)的bit0,物理上的bit8對應(yīng)第二個(gè)字節(jié)的bit0.對于int類型的數(shù)據(jù),由于它是按高字節(jié)在前的方式存儲(chǔ)的,int類型數(shù)據(jù)的bit0應(yīng)位于第二個(gè)字節(jié)的bit0,因此采用sbit指定int類型數(shù)據(jù)bit0時(shí)應(yīng)使用物理上的bit8。
③sfr:8051單片機(jī)片內(nèi)RAM中與idata空間相重疊的高128字節(jié)(地址范圍為80~FFH)稱為特殊功能寄存器SFR區(qū)。單片機(jī)對片內(nèi)集成的定時(shí)器、串行口、I/O等操作都是通過SFR來實(shí)現(xiàn)的。為了能夠直接訪問8051系列單片機(jī)內(nèi)部的SFR,C51編譯器擴(kuò)充了關(guān)鍵字sfr和sfr16,利用這種擴(kuò)充關(guān)鍵字可以在C51源程序中直接定義8051單片機(jī)的SFR,定義方法如下:
sfr特殊功能寄存器名=地址常數(shù);
例如:
sfrP0=0x80;//定義P0寄存器地址為0x80
sfrSCON=0x90;//定義串行口控制寄存器地址為0x90
需要注意,關(guān)鍵字sfr后面必須跟一個(gè)標(biāo)識(shí)符作為特殊功能寄存器名,名字可任意選取,但應(yīng)符合一般習(xí)慣。等號(hào)后面必須是常數(shù),不允許有帶運(yùn)算符的表達(dá)式。傳統(tǒng)8051單片機(jī)地址常數(shù)的范圍是0x80~0xff。
④sfr16:在一些新型8051單片機(jī)中,特殊功能寄存器經(jīng)常組合成16位來使用,采用關(guān)鍵字sfr16可以定義這種16位的SFR。例如,8052單片機(jī)的定時(shí)器T2,可定義為:
sfr16T2=0xCC;//定義TIMER2地址為T2L=0xCC,T2H=0xCD
這里的T2為SFR名,等號(hào)后面使它的低字節(jié)地址,其高字節(jié)地址必須在物理上直接位于低字節(jié)之后。
4)SFR特定位的定義:
在8051單片機(jī)應(yīng)用系統(tǒng)中經(jīng)常需要訪問特殊功能寄存器SFR中的一些特定位,可以利用C51編譯器提供的擴(kuò)充關(guān)鍵字sbit來定義特殊功能寄存器SFR中的可位尋址對象,定義方法有如下三種:
①sbit位變量名=位地址;
這種方法將位的絕對地址賦給位變量,位地址位于0x80~0xFF之間。例如:
sbitOV=0xD2;//定義溢出標(biāo)志位地址
sbitCY=0xD7;//定義進(jìn)位標(biāo)志位地址
②sbit位變量名=特殊功能寄存器名^位;
當(dāng)可尋址位位于特殊功能寄存器SFR中時(shí)可采用這種方法,位是一個(gè)0~7之間的常數(shù)。例如:
sfrPSW=0xD0;//定義PSW寄存器地址為0xD0
sbitOV=PSW^2;//定義溢出標(biāo)志位
sbitCY=PSW^7;//定義進(jìn)位標(biāo)志位
③sbit位變量名=字節(jié)地址^位;
這種方法以一個(gè)常數(shù)(字節(jié)地址)作為基地址,該常數(shù)必須在0x80~0xFF之間。位是一個(gè)0~7之間的常數(shù)。例如:
sbitOV=0xD0^2;//定義溢出標(biāo)志位地址
sbitCY=0xD0^7;//定義進(jìn)位標(biāo)志位地址
需要注意,用sbit定義的特殊功能寄存器中的可尋址位是一個(gè)獨(dú)立的定義類(class),不能與其他位定義和位域互換。
5)一般指針與基于存儲(chǔ)器的指針及其轉(zhuǎn)換:
KeilC51編譯器支持兩種指針類型,即一般指針和基于存儲(chǔ)器的指針。一般指針需要占用3個(gè)字節(jié),基于存儲(chǔ)器的指針只需要占用1~2個(gè)字節(jié)。一般指針具有較好的兼容性,但運(yùn)行速度緩慢,基于存儲(chǔ)器的指針是C51編譯器專門針對8051單片機(jī)存儲(chǔ)器的特點(diǎn)進(jìn)行的擴(kuò)展,只適用于8051單片機(jī),但具有較高的運(yùn)行速度。
①一般指針:
定義一般指針的方法與ANSIC相同,例如:
char*sptr;//定義char型指針
int*numptr;//定義int型指針
一般指針在內(nèi)存中占用3字節(jié),第一字節(jié)存放該指針的存儲(chǔ)器類型編碼(由編譯模式確定),第二和第三字節(jié)分別存放該指針的高位和低位地址偏移量。一般指針的存儲(chǔ)器類型編碼見表:
|
存儲(chǔ)器類型 |
idata/data/bdata |
xdata |
pdata |
code |
|
編碼值 |
0x00 |
0x01 |
0xFE |
0xFF |
一般指針可用于存取任何變量,而不用考慮變量在8051單片機(jī)存儲(chǔ)器空間的位置,許多C51庫函數(shù)都采用一般指針。函數(shù)可以利用一般指針來存取位于任何存儲(chǔ)器空間的數(shù)據(jù)。
定義一般指針時(shí),可以在“*”后帶一個(gè)存儲(chǔ)器類型選項(xiàng),用于指定一般指針本身的存儲(chǔ)器空間位置。例如:
char*xdatasptr;//定義位于xdata空間的一般指針,char型數(shù)據(jù)
int*datanumptr;//定義位于data空間的一般指針,int型數(shù)據(jù)
long*idatavarptr;//定義位于idata空間的一般指針,long型數(shù)據(jù)
由于一般指針?biāo)笇ο蟮拇鎯?chǔ)器空間位置,只有在運(yùn)行期間才能確定,編譯器在編譯期間無法優(yōu)化存儲(chǔ)方式,必須生成一般代碼以保證能對任意空間的對象進(jìn)行存取,因此一般指針?biāo)a(chǎn)生的代碼運(yùn)行速度較慢。
②基于存儲(chǔ)器的指針:
基于存儲(chǔ)器的指針具有明確的存儲(chǔ)器空間,長度可為1字節(jié)(存儲(chǔ)器類型為idata、data、pdata)或2字節(jié)(存儲(chǔ)器類型為code、xdata)。定義指針時(shí),如果在“*”前面增加一個(gè)存儲(chǔ)器類型選項(xiàng),該指針就被定義為基于存儲(chǔ)器的指針。例如:
chardata*str;//定義指向data空間char型數(shù)據(jù)的指針
intxdata*num;//定義指向xdata空間int型數(shù)據(jù)的指針
longcode*pow;//定義指向code空間long型數(shù)據(jù)的指針
與一般指針類型類似,定義基于存儲(chǔ)器的指針時(shí)還可以指定指針本身的存儲(chǔ)器空間位置,即在“*”后面帶一個(gè)存儲(chǔ)器類型選項(xiàng)。例如:
chardata*xdatastr;//定義指向data空間char型數(shù)據(jù)的指針,指針在xdata空間
intxdata*datanum;//定義指向xdata空間int型數(shù)據(jù)的指針,指針在data空間
longcode*idatapow;//定義指向code空間long型數(shù)據(jù)的指針,指針在idata空間
基于存儲(chǔ)器的指針長度比一般指針短,可以節(jié)省存儲(chǔ)器空間,運(yùn)行速度快,但它所指對象具有確定的存儲(chǔ)器空間,缺乏兼容性。
③一般指針與基于存儲(chǔ)器的指針之間的轉(zhuǎn)換:
一般指針與基于存儲(chǔ)器的指針可以相互轉(zhuǎn)換。在某些函數(shù)調(diào)用中進(jìn)行參數(shù)傳遞時(shí)需要采用一般指針,例如C51的庫函數(shù)printf()、sprintf()、gets()等便是如此。當(dāng)傳遞的參數(shù)是基于存儲(chǔ)器的指針時(shí),若不特別指明,C51編譯器會(huì)自動(dòng)將其轉(zhuǎn)換為一般指針。
需要注意,如果采用基于存儲(chǔ)器的指針作為自定義函數(shù)的參數(shù),而程序中又沒有給出該函數(shù)原型,則基于存儲(chǔ)器的指針就自動(dòng)轉(zhuǎn)換為一般指針,有時(shí)會(huì)導(dǎo)致錯(cuò)誤發(fā)生。為了避免這類錯(cuò)誤,應(yīng)該在程序的開始處用預(yù)處理命令“#include”將函數(shù)原型說明文件包含進(jìn)來,或者直接給出函數(shù)原型聲明。
6)C51編譯器對ANSIC函數(shù)定義的擴(kuò)展:
C51編譯器提供了幾種對于ANSIC函數(shù)定義的擴(kuò)展,可用于選擇函數(shù)的編譯模式、規(guī)定函數(shù)所使用的工作寄存器組、定義中斷服務(wù)函數(shù)、指定再入方式等。
C51程序中進(jìn)行函數(shù)定義的一般格式如下:
函數(shù)類型函數(shù)名(形式參數(shù)表)[編譯模式][reentrant][interruptn][usingn]
{
局部變量定義
函數(shù)體語句
}
其中,函數(shù)類型說明了自定義函數(shù)返回值的類型,函數(shù)名是用標(biāo)識(shí)符表示的自定義函數(shù)名字,形式參數(shù)表中列出了在主調(diào)用函數(shù)與被調(diào)用函數(shù)之間傳遞數(shù)據(jù)的形式參數(shù),形式參數(shù)的類型必須加以說明。
編譯模式選項(xiàng)是C51對ANSIC的擴(kuò)展,可以是SMALL、COMPACT或LARGE,用于指定函數(shù)中局部變量和參數(shù)的存儲(chǔ)器空間;reentrant選項(xiàng)是C51對ANSIC的擴(kuò)展,用于定義再入函數(shù);interruptn選項(xiàng)是C51對ANSIC的擴(kuò)展,用于定義中斷服務(wù)函數(shù),n為中斷號(hào),可為0~31;usingn選項(xiàng)是C51對ANSIC的擴(kuò)展,用于確定中斷服務(wù)程序所使用的工作寄存器組,n可以是0~3。
①堆棧及函數(shù)的參數(shù)傳遞:
函數(shù)在運(yùn)行過程中需要使用堆棧,8051單片機(jī)的堆棧必須位于片內(nèi)RAM空間,其最大范圍只有256B。(對于一些新型8051單片機(jī),C51編譯器可以使用擴(kuò)展堆棧區(qū),最大可達(dá)幾千字節(jié))。為了節(jié)省堆??臻g,C51編譯器采用一個(gè)固定的存儲(chǔ)器區(qū)域來進(jìn)行函數(shù)參數(shù)的傳遞。發(fā)生函數(shù)調(diào)用時(shí),主調(diào)函數(shù)先將實(shí)際參數(shù)復(fù)制到該固定的存儲(chǔ)器區(qū)域,然后再將程序流程控制交給被調(diào)函數(shù),被調(diào)函數(shù)則從該固定的存儲(chǔ)器區(qū)域取得所需要的參數(shù)進(jìn)行操作。這樣,就需要將函數(shù)的返回地址保存到堆棧區(qū)。由于中斷服務(wù)函數(shù)可能要進(jìn)行工作寄存器組切換,因此需要采用較多的堆??臻g。
C51編譯器可以采用控制命令“REGPARMS”和“NOREGPARMS”來決定是否通過工作寄存器傳遞函數(shù)參數(shù)。默認(rèn)狀態(tài)下,C51編譯器通過工作寄存器最多傳遞3個(gè)函數(shù)參數(shù),這種方式可以提高程序執(zhí)行效率。如果沒有寄存器可用,則通過固定的存儲(chǔ)器區(qū)域來傳遞函數(shù)的參數(shù)。
②函數(shù)的編譯模式:
不同類項(xiàng)的8051單片機(jī)片內(nèi)RAM空間大小不同,有些衍生產(chǎn)品只有64個(gè)字節(jié)的片內(nèi)RAM,因此在定義函數(shù)時(shí)要根據(jù)具體情況來決定應(yīng)采用的編譯模式。函數(shù)參數(shù)和局部變量都存放在由編譯模式?jīng)Q定的默認(rèn)存儲(chǔ)器空間中,可以根據(jù)需要對不同函數(shù)采用不同的編譯模式。在SMALL編譯模式下,函數(shù)參數(shù)和局部變量被存放在8051的片內(nèi)RAM空間,這種方式對數(shù)據(jù)的處理效率最高。但片內(nèi)RAM空間有限,對于較大的程序若采用SMALL編譯模式可能不能滿足要求,這時(shí)就需要采用其他編譯模式。下面的函數(shù)分別采用了不同的編譯模式:
#pragmasmall//默認(rèn)編譯模式為small
externintcalc(chari,intb)largereentrant;//采用LARGE編譯模式
externintfunc(inti,floatf)large;//采用LARGE編譯模式
externvoid*tcp(charxdata*xp,intndx)small;//采用SMALL編譯模式
intmtest(inti,inty){
return(i*y+y*i+func(-1,4.75));//采用默認(rèn)編譯模式
}
intlarge_func(inti,intk){large
return(mtest(i,k)+2);//采用LARGE編譯模式
}
③寄存器組切換:
8051單片機(jī)片內(nèi)RAM中最低32個(gè)字節(jié)平均分為4組,每組8個(gè)字節(jié)都命名為R0~R7,統(tǒng)稱為工作寄存器組。利用擴(kuò)展關(guān)鍵字“using”可以在定義函數(shù)時(shí)規(guī)定所使用的工作寄存器組,只要在后面跟一個(gè)數(shù)字0~3,即可規(guī)定所使用的工作寄存器組。
需要注意,關(guān)鍵字using不能用在以寄存器返回一個(gè)值的函數(shù)中,并且要保證任何寄存器組的切換都只在仔細(xì)控制的區(qū)域內(nèi)發(fā)生,否則將產(chǎn)生不正確的結(jié)果。帶using屬性的函數(shù)原則上不能返回bit類型的值。
8051單片機(jī)復(fù)位時(shí)PSW的值為0x00,因此在默認(rèn)狀態(tài)下所有非中斷函數(shù)都將使用工作寄存器0區(qū)。C51編譯器可以通過控制命令“REGISTERBAN”為源程序中的所有函數(shù)指定一個(gè)默認(rèn)的工作寄存器組,為此用戶需要修改啟動(dòng)代碼選擇不同的寄存器組,然后采用控制命令“REGISTERBAN”來指定新的工作寄存器組。
在默認(rèn)狀態(tài)下,C51編譯器生成的代碼將使用絕對尋址方式來訪問工作寄存器R0~R7,從而提高操作性能。絕對寄存器尋址方式可以通過編譯控制命令“AREGS”或“NOAREGS”來激活或禁止。采用了絕對寄存器的函數(shù)不能被另一個(gè)使用了不同工作寄存器組的函數(shù)所調(diào)用,否則會(huì)導(dǎo)致不可預(yù)知的結(jié)果。為了使函數(shù)對當(dāng)前工作寄存器組不敏感,該函數(shù)必須采用控制命令“NOAREGS”進(jìn)行編譯。
需要注意,C51編譯器對函數(shù)之間使用的工作寄存器組是否匹配不做檢查,因此使用了交替寄存器組的函數(shù)只能調(diào)用沒有設(shè)定默認(rèn)寄存器組的函數(shù)。
④中斷函數(shù):
利用控制關(guān)鍵字“interrupt”可以直接在C51程序中定義中斷服務(wù)函數(shù)。在“interrupt”后跟一個(gè)0~31的數(shù)字,用于規(guī)定中斷源和中斷入口。關(guān)鍵字“interrupt”對中斷函數(shù)目標(biāo)代碼的影響如下:
·在進(jìn)入中斷函數(shù)時(shí),特殊功能寄存器ACC、B、DPH、DPL、PSW將被保存入棧
·如果不使用關(guān)鍵字using進(jìn)行工作寄存器切換,則將中斷函數(shù)中所有用到的工作寄存器入棧
·函數(shù)退出之前所有的寄存器內(nèi)容出棧恢復(fù)
·中斷函數(shù)由8051單片機(jī)指令RETI結(jié)束
·C51編譯器根據(jù)中斷號(hào)自動(dòng)生成中斷函數(shù)入口向量地址
⑤再入函數(shù):
利用C51編譯器的擴(kuò)展控制字“reentrant”可以定義一個(gè)再入函數(shù)。再入函數(shù)可以進(jìn)行遞歸調(diào)用,或者同時(shí)被兩個(gè)以上的其他函數(shù)同時(shí)調(diào)用。通常,在實(shí)時(shí)系統(tǒng)應(yīng)用中或在中斷函數(shù)與非中斷函數(shù)需要共享一個(gè)函數(shù)時(shí),應(yīng)將該函數(shù)定義為再入函數(shù)。
再入函數(shù)可被遞歸調(diào)用,無論何時(shí),包括中斷服務(wù)函數(shù)在內(nèi)的任何函數(shù)都可調(diào)用再入函數(shù)。與非再入函數(shù)的參數(shù)傳遞和局部變量的存儲(chǔ)分配方法不同,C51編譯器為再入函數(shù)生成一個(gè)模擬棧,通過這個(gè)模擬棧來完成參數(shù)傳遞和存放局部變量。根據(jù)再入函數(shù)所采用的編譯模式,模擬??梢晕挥谄瑑?nèi)或片外存儲(chǔ)器空間,SMALL模式下的再入棧位于data空間,COMPACT模式下的再入棧位于pdata空間,LARGE模式下的再入棧位于xdata空間。當(dāng)程序中包含有多種存儲(chǔ)器模式的再入函數(shù)時(shí),C51編譯器為每種模式單獨(dú)建立一個(gè)模擬棧并獨(dú)立管理各自的棧指針。再入函數(shù)的局部變量及參數(shù)都被放在再入棧中,從而使再入函數(shù)可以進(jìn)行遞歸調(diào)用。而非再入函數(shù)的局部變量被放在再入棧之外的暫存區(qū)內(nèi),如果對非再入函數(shù)進(jìn)行遞歸調(diào)用,則上次調(diào)用時(shí)使用的局部變量數(shù)據(jù)將被覆蓋。
KeilC51編譯器對于再入函數(shù)有如下規(guī)定:
·再入函數(shù)不能徹底傳遞bit類型的參數(shù),也不能定義局部位變量。再入函數(shù)不能操作可位尋址變量。
·與PL/M51兼容的alien函數(shù)不能具有reentrant屬性,也不能調(diào)用再入函數(shù)。
·再入函數(shù)可以同時(shí)具有其他屬性,如interrupt、using等,還可以聲明存儲(chǔ)器模式SMALL、COMPACT、LARGE。
·在同一個(gè)程序中可以定義和使用不同存儲(chǔ)器模式的再入函數(shù),每個(gè)再入函數(shù)都必須具有合適的函數(shù)原型,原型中還應(yīng)包含該函數(shù)的存儲(chǔ)器模式。
·如果函數(shù)的返回地址保存在8051單片機(jī)的硬件堆棧內(nèi),任意其他的PUSH和POP指令都會(huì)影響8051硬件堆棧。
·不同存儲(chǔ)器模式下的再入函數(shù)具有其自己的模擬再入棧以及再入棧指針。例如,若在同一模塊內(nèi)定義了SMALL和LARGE模式的再入函數(shù),則C51編譯器會(huì)同時(shí)生成對應(yīng)的兩種再入棧及其再入棧指針。
8051單片機(jī)的常規(guī)??偸俏挥趦?nèi)部數(shù)據(jù)RAM中,而且是“向上生長”型的,而模擬再入棧是“向下生長”型的。如果編譯時(shí)采用SMALL模式,常規(guī)棧和再入函數(shù)的模擬棧將被放在內(nèi)部RAM中,從而使有限的內(nèi)部數(shù)據(jù)存儲(chǔ)器得到充分利用。模擬再入棧及其再入棧指針可以通過配置文件“STARTUP.A51”進(jìn)行調(diào)整。使用再入函數(shù)時(shí),應(yīng)根據(jù)需要對該配置文件進(jìn)行適當(dāng)修改。
5. C51編譯器的數(shù)據(jù)調(diào)用協(xié)議:
1)bit類型的數(shù)據(jù):只有一位長度,不允許定義位指針和位數(shù)組。Bit對象始終位于8051單片機(jī)內(nèi)部可位尋址的數(shù)據(jù)存儲(chǔ)器空間(20H~2FH),只要有可能,BL51連接定位器將對位對象進(jìn)行覆蓋操作。
2)char類型的數(shù)據(jù):長度為一個(gè)字節(jié)(8位),可存放于8051單片機(jī)內(nèi)部或外部數(shù)據(jù)存儲(chǔ)器中。
3)int和short類型的數(shù)據(jù):長度為兩個(gè)字節(jié)(16位),可存放于8051單片機(jī)內(nèi)部或外部數(shù)據(jù)存儲(chǔ)器中。數(shù)據(jù)在內(nèi)存中按高字節(jié)地址在前、低字節(jié)地址在后的順序存放。例如,int類型數(shù)據(jù)0x1234,在內(nèi)存中的存儲(chǔ)格式如下:
|
地址 |
+0 |
+1 |
|
內(nèi)容 |
0x12 |
0x34 |
4)long類型的數(shù)據(jù):長度為4個(gè)字節(jié)(32位),可存放于8051單片機(jī)內(nèi)部或外部數(shù)據(jù)存儲(chǔ)器中。數(shù)據(jù)在內(nèi)存中按高字節(jié)地址在前、低字節(jié)地址在后的順序存放。例如,long類型數(shù)據(jù)0x12345678,在內(nèi)存中的存儲(chǔ)格式如下:
|
地址 |
+0 |
+1 |
+2 |
+3 |
|
內(nèi)容 |
0x12 |
0x34 |
0x56 |
0x78 |
5)float類型的數(shù)據(jù):長度為4個(gè)字節(jié)(32位),存放于8051單片機(jī)內(nèi)部或外部數(shù)據(jù)存儲(chǔ)器中。一個(gè)float類型數(shù)據(jù)的數(shù)值范圍是:
在內(nèi)存中按IEEE-754標(biāo)準(zhǔn)單精度32位浮點(diǎn)數(shù)的格式存儲(chǔ):
|
地址 |
+0 |
+1 |
+2 |
+3 |
|
內(nèi)容 |
SEEEEEEE |
EMMMMMMM |
MMMMMMMM |
MMMMMMMM |
其中,S為符號(hào)位,0表示正,1表示負(fù)。E為用原碼表示的階碼,占用8位二進(jìn)制數(shù),存放在兩個(gè)字節(jié)中,E的取值范圍是1~254。(實(shí)際上,以2為底的指數(shù)要用E的值減去偏移量127,從而實(shí)際冪指數(shù)的取值范圍為-126~+127)。M為尾數(shù)的小數(shù)部分,用23位二進(jìn)制表示,存放在3個(gè)字節(jié)中。尾數(shù)的整數(shù)部分永遠(yuǎn)為1,因此不予保存,但是隱含存在的。小數(shù)點(diǎn)位于隱含的整數(shù)位1的后面。
例如,一個(gè)值為-12.5的float類型數(shù)據(jù),在內(nèi)存中的存儲(chǔ)格式如下:
|
地址 |
+0 |
+1 |
+2 |
+3 |
|
二進(jìn)制內(nèi)容 |
11000001 |
01001000 |
00000000 |
00000000 |
|
十六進(jìn)制內(nèi)容 |
0xC1 |
0x48 |
0x00 |
0x00 |
如果階碼E為全1(即255),小數(shù)部分M為全0,則根據(jù)符號(hào)位,分別表示正負(fù)無窮大:
正無窮:+INF=7F800000H負(fù)無窮:-INF=FF800000H
階碼E為全0,小數(shù)部分M也全0的浮點(diǎn)數(shù),認(rèn)為是0。絕對值最小的正常浮點(diǎn)數(shù)為階碼E為1,小數(shù)部分M為全0的數(shù):
除了正常浮點(diǎn)數(shù),在以及之間的數(shù)為非正常數(shù)。按IEEE754標(biāo)準(zhǔn),浮點(diǎn)數(shù)的數(shù)值如果在正常數(shù)值之外,即為溢出錯(cuò)誤,二進(jìn)制表示為:
非正常數(shù):NaN=0FFFFFFFFH
6)指針:C51編譯器支持一般指針和基于存儲(chǔ)器的指針。基于存儲(chǔ)器類型data、idata和pdata的指針具有1個(gè)字節(jié)的長度,基于存儲(chǔ)器類型xdata和code的指針具有兩字節(jié)的長度,一般指針具有3字節(jié)的長度。
在一般指針的3個(gè)字節(jié)中,第一個(gè)字節(jié)表示存儲(chǔ)器類型,第二、第三字節(jié)表示指針的地址偏移量。一般指針在內(nèi)存中的存儲(chǔ)格式如下:
|
地址 |
+0 |
+1 |
+2 |
|
內(nèi)容 |
存儲(chǔ)器類型 |
高字節(jié)地址偏移量 |
低字節(jié)地址偏移量 |
在第一個(gè)字節(jié)中,存儲(chǔ)器類型的編碼如下:
|
存儲(chǔ)器類型 |
idata/data/bdata |
xdata |
pdata |
code |
|
編碼值(8051) |
0x00 |
0x01 |
0xFE |
0xFF |
|
編碼值(8051Mx) |
0x7F |
0x00 |
0x00 |
0x80 |
采用一般指針時(shí),必須使用規(guī)定的存儲(chǔ)器類型編碼值。如果使用其他類型的值,將導(dǎo)致不可預(yù)測的后果。
例如,將xdata類型的地址0x1234作為一般指針表示如下:
|
地址 |
+0 |
+1 |
+2 |
|
內(nèi)容 |
0x01 |
0x12 |
0x34 |
6. 絕對地址訪問:
在進(jìn)行8051單片機(jī)應(yīng)用系統(tǒng)程序設(shè)計(jì)時(shí),用戶會(huì)關(guān)心如何直接操作各個(gè)存儲(chǔ)器的地址空間。C51程序經(jīng)過編譯后,產(chǎn)生的目標(biāo)代碼具有浮動(dòng)地址,其絕對地址必須經(jīng)過BL51連接定位后才能確定。為了能夠在C51程序中直接對任意指定的存儲(chǔ)器地址進(jìn)行操作,可以采用擴(kuò)展關(guān)鍵字“_at_”、指針、預(yù)定義宏以及連接定位控制命令。
1)采用擴(kuò)展關(guān)鍵字“_at_”或指針定義變量的絕對地址:
在C51源程序中定義變量時(shí),可以利用C51編譯器提供的擴(kuò)展關(guān)鍵字“_at_”來指定變量的存儲(chǔ)器空間絕對地址。一般格式如下:
[存儲(chǔ)器類型]數(shù)據(jù)類型標(biāo)識(shí)符_at_地址常數(shù)
其中,存儲(chǔ)器類型為idata、data、xdata等C51編譯器能夠識(shí)別的所有類型,如果省略該選項(xiàng),則按編譯模式SMALL、COMPACT和LARGE規(guī)定的默認(rèn)存儲(chǔ)器類型確定變量的存儲(chǔ)器空間;數(shù)據(jù)類型除了可用int、long、float等基本類型外,還可以采用數(shù)組、結(jié)構(gòu)等復(fù)雜數(shù)據(jù)類型;標(biāo)識(shí)符為要定義的變量名;地址常數(shù)規(guī)定了變量的絕對地址,它必須位于有效存儲(chǔ)器空間之內(nèi)。下面是采用關(guān)鍵字“_at_”進(jìn)行變量的絕對地址定位的示例:
structlink{
structlinkidata*next;
charcode*test;
};
idatastructlinklist_at_0x40;//結(jié)構(gòu)變量list定位于idata空間地址0x40
xdatachartext[256]_at_0xE000;//數(shù)組array定位于xdata空間地址0xE000
xdataintil_at_0x8000;//int變量il定位于xdata空間地址0x8000
利用擴(kuò)展關(guān)鍵字“_at_”定義的變量稱為絕對變量,對該變量的操作就是對指定存儲(chǔ)器空間絕對地址的直接操作,因此不能對絕對變量進(jìn)行初始化。對于函數(shù)和位bit類型變量不能采用這種方法進(jìn)行絕對地址定位。采用關(guān)鍵字“_at_”所定義的絕對變量必須是全局變量,在函數(shù)內(nèi)部不能采用“_at_”關(guān)鍵字指定局部變量的絕對地址。另外,在XDATA空間定義全局變量的絕對地址時(shí),還可以在變量前面加一個(gè)關(guān)鍵字“volatile”,這樣對該變量的訪問就不會(huì)被C51編譯器優(yōu)化掉。
利用基于存儲(chǔ)器的指針也可以指定變量的存儲(chǔ)器絕對地址,其方法是先定義一個(gè)基于存儲(chǔ)器的指針變量,然后對該變量賦以存儲(chǔ)器絕對地址。下面是一個(gè)利用基于存儲(chǔ)器的指針進(jìn)行變量的絕對地址定位的示例:
charxdatatemp_at_0x4000;//定義全局變量temp,地址為XDATA空間0x4000
voidmain(){
charxdata*xdp;//定義一個(gè)指向XDATA存儲(chǔ)器空間的指針
chardata*dp;//定義一個(gè)指向DATA存儲(chǔ)器空間的指針
xdp=0x2000;//XDATA指針賦值,指向XDATA存儲(chǔ)器地址0002H
temp=*xdp;//讀取XDATA空間地址0x2000的內(nèi)容送往0x4000單元
*xdp=0xAA;//將數(shù)據(jù)0xAA送往XDATA空間0x2000地址單元
dp=0x30;//XDATA指針賦值,指向DATA存儲(chǔ)器地址30H
*dp=0xBB;//將數(shù)據(jù)0xBB送往指定的DATA空間地址
2)采用預(yù)定義宏指定變量的絕對地址:
C51編譯器的運(yùn)行庫中提供了如下一套預(yù)定義宏:
CBYTECWORDFARRAY
DBYTEDWORDFCARRAY
PBYTEPWORDFCVAR
XBYTEXWORDFVAR
這些宏定義包含在頭文件“ABSACC.H”中。在C51源程序中可以利用這些宏來指定變量的絕對地址。例如:
#include<ABSACC.H>
charc_var;
inti_var;
XBYTE[0X12]=c_var;//向XDATA存儲(chǔ)器地址0012H寫入數(shù)據(jù)C_var
i_var=XWORD[0x100];//從XDATA存儲(chǔ)器地址0200H中讀取數(shù)據(jù)并賦值給i_var
上面語句中的XWORD[0x100]是對地址“2*0x100”進(jìn)行操作,將字節(jié)地址0x200和0x201的內(nèi)容取出來并賦值給int型變量i_var。
用戶可以充分利用C51運(yùn)行庫中提供的預(yù)定義宏來進(jìn)行絕對地址的直接操作。例如,可以采用如下方法定義一個(gè)D/A轉(zhuǎn)換接口地址,每向該地址寫入一個(gè)數(shù)據(jù),即可完成一次D/A轉(zhuǎn)換。
#include<ABSACC.H>
#defineDAC0832XBYTE[0x7FFF]//定義DAC0832端口地址
DAC0832=0x80;//啟動(dòng)一次D/A轉(zhuǎn)換
總結(jié)
以上是生活随笔為你收集整理的Keil C51程序设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 贵州有什么财经大学(2022年贵州有哪些
- 下一篇: 选购合适自己的充电器,聊聊氮化镓多口充