《單片機(jī)原理及應(yīng)用系統(tǒng)設(shè)計(jì)》課件第5章_第1頁
《單片機(jī)原理及應(yīng)用系統(tǒng)設(shè)計(jì)》課件第5章_第2頁
《單片機(jī)原理及應(yīng)用系統(tǒng)設(shè)計(jì)》課件第5章_第3頁
《單片機(jī)原理及應(yīng)用系統(tǒng)設(shè)計(jì)》課件第5章_第4頁
《單片機(jī)原理及應(yīng)用系統(tǒng)設(shè)計(jì)》課件第5章_第5頁
已閱讀5頁,還剩134頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

5.1C51基本語法規(guī)則

5.2C51程序設(shè)計(jì)技巧

5.3匯編語言與C語言的混合編程

5.4C51與匯編語言的對(duì)照

5.5C51程序設(shè)計(jì)小結(jié)

習(xí)題五第五章C51程序設(shè)計(jì)語言5.1.1C51數(shù)據(jù)類型

C51支持的數(shù)據(jù)類型如表5-1所示。標(biāo)準(zhǔn)C語言和C51相同的數(shù)據(jù)類型不再詳細(xì)說明,下面主要解釋C51擴(kuò)展的特殊

數(shù)據(jù)類型。5.1C51基本語法規(guī)則表5-1C51支持的數(shù)據(jù)類型5.1.2常量與變量

1.常量

常量就是程序運(yùn)行過程中不能改變值的量,可用在值不必改變的場(chǎng)合,如固定的數(shù)據(jù)表、字庫等。

常量的定義方式有如下幾種:

(1)用預(yù)定義語句定義常量,如:

#difineFalse0x0;//定義False為0

(2)用code語句定義常量,如:

unsignedintcodea=100;//定義a為無符號(hào)int常量100

(3)用const語句定義常量,如:

constunsignedintc=100;//定義c為無符號(hào)int常量100

常量的數(shù)據(jù)類型有整型、浮點(diǎn)型、字符型、字符串型和位標(biāo)量,這與標(biāo)準(zhǔn)C語言的常量一致。

2.變量

定義一個(gè)變量的格式如下:

[存儲(chǔ)種類]數(shù)據(jù)類型[存儲(chǔ)器類型]變量名稱

表5-2給出了C51編譯器能夠識(shí)別的存儲(chǔ)器類型,變量名稱的命名規(guī)則與標(biāo)準(zhǔn)C語言一致,下面給出了一些變量定義的例子:chardatavar1 ;在data區(qū)定義字符型變量var1

intidatavar2 ;在data區(qū)定義字符型變量var2

inta=5 ;定義變量a,同時(shí)賦以初值5,變量a位

;于由編譯模式確定的默認(rèn)存儲(chǔ)區(qū)

externfloatidatax,y,z;在idata區(qū)定義外部浮點(diǎn)型變量x,y,z表5-2C51能夠識(shí)別的存儲(chǔ)器類型

C51編譯器有三種存儲(chǔ)模式,具體如下:

(1)小(small)模式

(2)緊湊(compact)模式

(3)大(large)模式

1)全局變量

全局變量是指在程序開始處或各個(gè)功能函數(shù)的外面定義的變量。全局變量在整個(gè)程序的執(zhí)行過程中都要占用內(nèi)存單元。在程序開始處定義的全局變量對(duì)于整個(gè)程序都有效,可供程序中所有函數(shù)共同使用。例如:#include〈reg51.h〉 ;頭文件,定義單片機(jī)片內(nèi)資源#defineucharunsignedchar ;定義常量uchar=unsignedchar

ucharkey ;定義全局變量key

voidmain()

{

}在各功能函數(shù)外面定義的全局變量只對(duì)從定義處開始往后的各個(gè)函數(shù)有效。若一個(gè)全局變量不是在程序文件開始處定義的,但又希望在它的定義點(diǎn)之前的函數(shù)中引用該變量,這時(shí)應(yīng)在引用該變量的函數(shù)中用關(guān)鍵字extern將其說明為外部變量。特別是當(dāng)一個(gè)程序能由多個(gè)源程序文件組成時(shí),如果一個(gè)程序中需要引用另外一個(gè)文件中已經(jīng)定義的外部變量,必須要使用extern來聲明。例如:文件1:

#include〈reg51.h〉

unsignedintarray[10];定義全局變量array

voidfillarray()

voidinit_ser()

{

}

voidmain()

{

}文件2:

externintarray[10];在另外一個(gè)文件中引用變量array

voidfillarray()

{

}

2)局部變量

下面給出了一個(gè)局部變量聲明的例子:

voidfillarray()

{

intarray[10];定義局部array

}5.1.3運(yùn)算符與表達(dá)式

C51的運(yùn)算符和表達(dá)式與標(biāo)準(zhǔn)C語言差別不大,表5-3總結(jié)性地給出了運(yùn)算符及其在表達(dá)式中的優(yōu)先級(jí)關(guān)系,供讀者參考。表5-3C51支持的運(yùn)算符及其優(yōu)先級(jí)5.1.4程序控制語句

1.表達(dá)式語句

表達(dá)式語句是一種最基本的語句。C51語言中,在表達(dá)式右邊加一個(gè)分號(hào)“;”就構(gòu)成了表達(dá)式語句,下面的語句都是合法的表達(dá)式語句:

b=b*10;Count++;

X=A;Y=B;

Page=(a+b)/a-1;在C51語言中有一個(gè)特殊的表達(dá)式語句,稱為空語句,它僅僅由一個(gè)分號(hào)“;”組成。有時(shí)候?yàn)榱耸拐Z法正確,但并不要求有具體的動(dòng)作,這時(shí)就可以采用空語句。例如:

repeat:; //定義標(biāo)號(hào)

gotorepeat; //無條件跳轉(zhuǎn)到標(biāo)號(hào)repeat處

上述程序利用標(biāo)號(hào)repeat和無條件轉(zhuǎn)移指令goto語句構(gòu)成循環(huán),但在標(biāo)號(hào)repeat處并不需要有具體的動(dòng)作??照Z句在循環(huán)中也經(jīng)常用到。

2.復(fù)合語句

若干條表達(dá)式語句組合而成的語句稱為復(fù)合語句,其一般形式為:

{

局部變量定義

語句1;

語句2;

語句n;

}復(fù)合語句通常出現(xiàn)在函數(shù)中。下面給出了一個(gè)復(fù)合語句短句的簡單例子:

{

intx1,y1; //定義局部變量

x1=5;

y1=8;

printf(″%d%d″,x1,y1); //打印x1,y1

}

3.條件語句

C51語言提供了三種形式的條件語句:

(1)基本形式,其語法結(jié)構(gòu)為:

if(表達(dá)式)語句:

語義:如果表達(dá)式的值為真,則執(zhí)行其后的語句,否則不執(zhí)行該語句。

(2)if-else形式,其語法結(jié)構(gòu)為:

if(表達(dá)式)語句1;

else語句2;

語義:如果表達(dá)式的值為真,則執(zhí)行語句1,否則執(zhí)行語句2。

(3)if-else-if形式,其語法結(jié)構(gòu)為:

if(表達(dá)式1)語句1;

elseif(表達(dá)式2) 語句2;

elseif(表達(dá)式3) 語句3;

elseif(表達(dá)式m) 語句m;

else 語句n;

語義:依次判斷表達(dá)式的值,當(dāng)出現(xiàn)某個(gè)值為真時(shí),則執(zhí)行其對(duì)應(yīng)的語句。然后跳到整個(gè)if語句之外繼續(xù)執(zhí)行程序。如果所有的表達(dá)式均為假,則執(zhí)行語句n。下面給出了一個(gè)簡單的條件語句應(yīng)用的例子:

voidmain()

{

Inta,b; //定義變量

Printf(″inputtwonumbers:″)

Scanf(″%d%d″,&a,&b);//從外部輸入兩個(gè)數(shù)據(jù)

If(a>b)printf(″max=%d\n″,a) //比較大小,并

//打印最大值

elseprintf(″max=%d\n″,b);

}

4.開關(guān)語句

開關(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:語句n+1;

}

語義:計(jì)算表達(dá)式的值,并逐個(gè)與其后的常量表達(dá)式的值相比較,當(dāng)表達(dá)式的值與某個(gè)常量表達(dá)式的值相等時(shí),則執(zhí)行case后面的語句,再執(zhí)行break(間斷語句)語句,跳出switch語句。如果case后沒有和條件相等的值時(shí)就執(zhí)行default后的語句。當(dāng)要求沒有符合的條件時(shí)不做任何處理,則不寫default語句。

使用switch語句時(shí)要注意,在case后的各常量表達(dá)式的值不能相同,否則會(huì)出現(xiàn)錯(cuò)誤。在case后,允許有多個(gè)語句,可以不用“{}”括起來。各case和default子句的先后順序可

以變動(dòng),而不會(huì)影響程序執(zhí)行結(jié)果。voidmain()

{

inta;

printf(″inputintegernumber:″);

scanf(″%d″,&a); //從外部輸入一個(gè)數(shù)據(jù)

switch(a)

{

case1:printf(″Monday\n″);break;

//如果該數(shù)據(jù)為1,打印星期一,退出switch語

case2printf(″Tuesday\n″);break;

//如果該數(shù)據(jù)為2,打印星期二,退出switch語句

case3:printf(″Wednesday\n″);break;

//如果該數(shù)據(jù)為3,打印星期三,退出switch語句

case4:printf(″Thursday\n″);break;

//如果該數(shù)據(jù)為4,打印星期四,退出switch語句

case5:printf(″Firday\n″);break;

//如果該數(shù)據(jù)為5,打印星期五,退出switch語句

case6:printf(″Saturday\n″);break;

//如果該數(shù)據(jù)為6,打印星期六,退出switch語句

case1:printf(″Sunday\n″);break;

//如果該數(shù)據(jù)為7,打印星期日,退出switch語句

default:printf(″e(cuò)rror\n″); //否則,打印出錯(cuò)信息

}

}

5.循環(huán)語句

提供了四種循環(huán)語句:

(1)while語句,其語法結(jié)構(gòu)為:

while(表達(dá)式)語句;

(2)do-while語句,其語法結(jié)構(gòu)為:

do

語句;

while(表達(dá)式);

(3)for語句,for語句是C51語言所提供的功能更強(qiáng),使用更廣泛的一種循環(huán)語句,其語法結(jié)構(gòu)為:

for(表達(dá)式1;表達(dá)式2;表達(dá)式3)

語句;

下面給出了一個(gè)循環(huán)語句應(yīng)用的簡單例子,完成1~10的累加并通過串口顯示:

#includde〈AT89X51.H〉

#include〈stdio,h〉

intcount(void);//聲明函數(shù)

voidmain(void){

unsignedinttemp;

SCON=0x50; //串口方式1,允許接收TMOD=0x20;定時(shí)器1定時(shí)方式2

TCON=0x40; //設(shè)置定時(shí)器1開始計(jì)數(shù)

TH1=0xE8; //晶振11.0592MHz,1200波特率,TL1=0xE8;

TI=1;

TR1=1; //啟動(dòng)定時(shí)器

Temp=Count();

printf(11-10SUM=%d\n11,temp);//顯示

while(1);

}

intcount(void)

{

unsignedintI,SUM;

for(I=1;I<=10;I++)

{

SUM=I+SUM; //累加

}

return(SUM);

}

6.轉(zhuǎn)移語句

(1)goto語句。goto語句也稱為無條件轉(zhuǎn)移語句,其語法結(jié)構(gòu)為:

goto語句標(biāo)號(hào);

(2)break語句。break語句只能用在switch語句或循環(huán)語句中,其語法結(jié)構(gòu)為:

break;

(3)continue語句。continue語句只能用在循環(huán)體中,其語法結(jié)構(gòu)為:

continue;

(4)return語句。return語句是返回語句,其語法結(jié)構(gòu)為:

return(表達(dá)式);

return;5.1.5函數(shù)

1.函數(shù)的調(diào)用

(1)函數(shù)語句。在主調(diào)用函數(shù)中直接將被調(diào)用函數(shù)作為一個(gè)語句。如:

Print(″HelloWord!\n″);

(2)函數(shù)表達(dá)式。這種調(diào)用方式是將被調(diào)用函數(shù)作為一個(gè)表達(dá)式,這種表達(dá)式稱為函數(shù)表達(dá)式,如:

c=power(x,n)+power(y,m);

(3)函數(shù)參數(shù)。這種參數(shù)調(diào)用方式是指將被調(diào)用函數(shù)作為另一個(gè)函數(shù)的實(shí)際參數(shù),如:

M=jiec(jiec(3));

2.被調(diào)用函數(shù)的說明

與使用變量一樣,在調(diào)用一個(gè)函數(shù)之前,包括標(biāo)準(zhǔn)庫函數(shù),必須對(duì)該函數(shù)的類型進(jìn)行說明,即“先說明,后調(diào)用”。如果調(diào)用的是標(biāo)準(zhǔn)庫函數(shù),一般應(yīng)在程序的開始處用預(yù)處理命令#include將有關(guān)函數(shù)說明的頭文件包含進(jìn)來,如:

include〈reg51.h〉如果調(diào)用的是用戶自定義函數(shù),而且該函數(shù)與調(diào)用它的主調(diào)用函數(shù)在同一個(gè)文件中,一般應(yīng)在主調(diào)用函數(shù)中對(duì)被調(diào)用函數(shù)的類型進(jìn)行說明。函數(shù)說明的一般形式為:

類型標(biāo)識(shí)符函數(shù)的名稱(形式參數(shù)表);

其中,“類型標(biāo)識(shí)符”說明了函數(shù)返回值的類型,“形式參數(shù)表”說明了各個(gè)形式參數(shù)的類型。

例如:

intcount(void);

3.函數(shù)的返回值

在調(diào)用函數(shù)過程中,經(jīng)常希望得到一個(gè)從被調(diào)用函數(shù)中帶回來的值,這就是函數(shù)的返回值。

4.參數(shù)的傳遞

(1)數(shù)值傳遞

(2)地址傳遞

5.重入函數(shù)

重入函數(shù)聲明的關(guān)鍵字為reentrant,重入函數(shù)的聲明的格式為:

函數(shù)類型函數(shù)名(形式參數(shù)表)reentrant下面給出了一個(gè)簡單重入函數(shù)定義的例子:

charmax(chara,charb,charc)reentrant

{

charmax_data;

max_data=(a>b)?a:b; //將a,b兩數(shù)中的最大

//值賦給max_data

max_data=(max_data>c)?max_data:c; //將a,b,c三數(shù)中的

//最大值賦予maxdata

return(max_data); //返回最大值

}

6.中斷服務(wù)函數(shù)

中斷服務(wù)函數(shù)聲明的關(guān)鍵字為interrupt,聲明的格式為:

函數(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),常用中斷源和中斷向量。如表5-4所示。表5-4單片機(jī)常用中斷號(hào)與中斷向量下面給出了一個(gè)簡單的中斷服務(wù)函數(shù)的例子:

unsignedintg_wTCount;

unsignedcharg_bySecond;

voidtimer0(void)interrupt1using1

{

g_wTCount++

if(g_wTCount>=20 //如果計(jì)數(shù)到20

{

g_bySecond++; //另一個(gè)計(jì)數(shù)器

g_wTCount=0; //計(jì)數(shù)器清零

}

}5.1.6指針

圖5-1形象地給出看了指針變量和它所指向的變量之間的關(guān)系。圖5-1指針變量和它所指向的變量

2.指針變量的定義

指針變量的定義與一般變量的定義類似,其一般形式如下:

數(shù)據(jù)類型[存儲(chǔ)器類型1]*[存儲(chǔ)器類型2]標(biāo)識(shí)符;

(1)通用指針變量:不選用“存儲(chǔ)器類型1”選項(xiàng)的指針變量稱為通用指針變量,其聲明和標(biāo)準(zhǔn)C語言中一樣。如:

char*s;

int*numptr;

long*state;

(2)存儲(chǔ)器指針變量:選用“存儲(chǔ)器類型1”選項(xiàng)的指針變量稱為存儲(chǔ)器指針變量,如:

chardata*str;

intxdata*numtab;

longcode*powtab;下面的示例程序說明了使用不同的指針在代碼長度、占用數(shù)據(jù)空間和運(yùn)行時(shí)間上的不同:

Description IdataPointer XdataPointer

GenericPointer

C源程序 idata*ip; charxdata*xp;

char*p;

charval; charval;

charval;

val=*ip; val=*xp;

val=*xp;

編譯后的代碼 MOVR0,ip MOVDPL,xp+1

MOVR1,p+2

MOVval,@R0 MOVDPH,xpMOVR2,p+1

MOVA,@DPTRMOVR3,p

MOVval,ACALLCLDPTR

指針大小 1byte 2byte

3byte

代碼長度 4byte 9byte

11byte+librarycall

執(zhí)行時(shí)間 4cycles 7cycles 13cycles由于許多庫函數(shù)會(huì)使用通用指針,但為了提高效率,用戶在程序中其自定義的函數(shù)可能會(huì)使用存儲(chǔ)器指針。在不同指針的函數(shù)之間進(jìn)行調(diào)用時(shí),往往要進(jìn)行指針的轉(zhuǎn)換。指針的轉(zhuǎn)換可以用類型轉(zhuǎn)換的直接程序代碼來強(qiáng)迫轉(zhuǎn)換,或在編譯器內(nèi)部強(qiáng)制轉(zhuǎn)換。C51編譯器指針轉(zhuǎn)換的規(guī)則如表5-5所示。表5-5通用指針與存儲(chǔ)器指針之間的轉(zhuǎn)換

3.指針變量的操作

(1)取地址運(yùn)算符&:該運(yùn)算符用來取變量的地址。如取變量a地址的指令為&a。

(2)間接訪問運(yùn)算符*:該運(yùn)算符用來間接訪問變量。如*p為指針變量p所指向的變量。

指針變量經(jīng)過定義后可以像其他基本變量一樣引用,下面的例子給出了指針變量基本操作:

inti,x,y,*pi,*px //定義指針變量

pi=&i;

//指針變量賦值將變量i的地址賦

//給指針變量pi,使pi指向i

*pi+=1 //指針變量的運(yùn)算,等價(jià)于i+=1

下面是一個(gè)指針應(yīng)用的簡單例子:

#include〈reg51.H〉

#inculde〈stdio.h〉

voidmain(void)

{

intx,y; //定義一般變量

int*p,*p1,*p2; //定義指針變量

printf(″inputxandy:\n″);

sacnf(″%d%d,&x,&y″); //輸入兩個(gè)數(shù)

p1=&x;p2=&y;

if(x<y)

{

p=p1;p1=p2;p2=p; //將大的數(shù)放在指針p1指向的變量,小

//的數(shù)放在p2指向的變量

printf(″max=%d,min=%d,\n″,*p1,*p2);//打印結(jié)果

while(1);

}5.1.7構(gòu)造數(shù)據(jù)類型

1.數(shù)組

數(shù)組是一組有序數(shù)據(jù)的集合,數(shù)組中的每一個(gè)數(shù)據(jù)都屬于同一種數(shù)據(jù)類型。數(shù)組中的各個(gè)元素可以用數(shù)組名和下標(biāo)來唯一地確定。按照維數(shù),數(shù)組可以分為一維數(shù)組和多維數(shù)組。在C51中數(shù)組必須先定義,然后才能使用。一維數(shù)組的定義形式如下:

數(shù)據(jù)類型數(shù)組名[常量表達(dá)式];定義多維數(shù)組時(shí),只要在數(shù)組名后面增加相應(yīng)于維數(shù)的常量表達(dá)式即可,其一般形式如下:

數(shù)據(jù)類型數(shù)組名[常量表達(dá)式1]…[常量表達(dá)式N];

下面給出了幾個(gè)數(shù)組定義的例子:

unsignedintxcount[10];

//定義一堆無符號(hào)整型數(shù)組,有10個(gè)數(shù)據(jù)單元

charinputstring[5];

//定義一維字符型數(shù)組,有5個(gè)數(shù)據(jù)單元

floatoutnum[10],[10];

//定義二維浮點(diǎn)型數(shù)組,有100個(gè)數(shù)據(jù)單元

2.結(jié)構(gòu)

結(jié)構(gòu)是由基本數(shù)據(jù)類型構(gòu)成的,并用一個(gè)標(biāo)識(shí)符來命名的各種變量的組合。結(jié)構(gòu)中可以使用不同的數(shù)據(jù)類型。結(jié)構(gòu)也是一種數(shù)據(jù)類型,可以使用結(jié)構(gòu)變量,因此,像其他類型的變量一樣,在使用結(jié)構(gòu)變量時(shí)要先對(duì)其定義。定義結(jié)構(gòu)變量的一般格式為:

struct結(jié)構(gòu)名

{

數(shù)據(jù)類型變量名;

數(shù)據(jù)類型變量名;

}

結(jié)構(gòu)變量;構(gòu)成結(jié)構(gòu)的每一個(gè)類型變量稱為結(jié)構(gòu)成員,它像數(shù)組的元素一樣,但數(shù)組中元素是以下標(biāo)來訪問的,而結(jié)構(gòu)是按變量名字來訪問成員的。下面的例子定義了一個(gè)結(jié)構(gòu)名為string的結(jié)構(gòu)變量person:

structstring

{

charname[8];

intage;

charsex[2];

chardepart[20];

floatwage1,wage2,wage3,wage4,wage5;

}

person;結(jié)構(gòu)是一個(gè)新的數(shù)據(jù)類型,因此結(jié)構(gòu)變量也可以像其他類型的變量一樣賦值、運(yùn)算,不同的是結(jié)構(gòu)變量以成員作為基本變量。結(jié)構(gòu)成員的表示方式為:

結(jié)構(gòu)變量.成員名

如果將“結(jié)構(gòu)變量.成員名”看成一個(gè)整體,則這個(gè)整體的數(shù)據(jù)類型與結(jié)構(gòu)中該成員的數(shù)據(jù)類型相同,這樣就可像前面所講的變量那樣使用它們。如對(duì)上面例子中的年齡進(jìn)行賦值:

person.age=20;

3.聯(lián)合

聯(lián)合也是一種新的數(shù)據(jù)類型,它是一種特殊形式的變量。聯(lián)合說明和聯(lián)合變量定義與結(jié)構(gòu)十分相似。其形式為:

union聯(lián)合名

數(shù)據(jù)類型成員名;

數(shù)據(jù)類型成員名;

}

聯(lián)合變量名;聯(lián)合表示幾個(gè)變量共用一個(gè)內(nèi)存位置,在不同的時(shí)間保存不同的數(shù)據(jù)類型和不同長度的變量。下面的例子定義了一個(gè)聯(lián)合名為a_bc的聯(lián)合變量lgc:

uniona_bc

{

inti;

charmm;

}

lgc同樣聯(lián)合變量也可以定義成數(shù)組或指針,但當(dāng)定義為指針時(shí),此時(shí)聯(lián)合訪問成員可表示成:

聯(lián)合名_成員名

另外,聯(lián)合可以出現(xiàn)在結(jié)構(gòu)內(nèi),它的成員也可以是結(jié)構(gòu)。例如:

struct

{

intage;

char*addr;

union

{

inti;

char*ch;

}

x;

}

y[10];

4.枚舉

枚舉是一個(gè)被命名的整型常數(shù)的集合,枚舉的說明與結(jié)構(gòu)的聯(lián)合相似,其形式為:

enum枚舉名

{

標(biāo)示符[=整型常數(shù)],

標(biāo)示符[=整型常數(shù)],

標(biāo)示符[=整型常數(shù)],

}

枚舉變量;若果枚舉沒有初始化,即省掉“=整型常數(shù)”時(shí),則從第一個(gè)標(biāo)示符開始,順次賦給標(biāo)示符0,1,2,…。但當(dāng)枚舉中的某個(gè)成員賦值后,其后的成員按依次加一的規(guī)則確定其值。例如下列枚舉:

enumstring{x1,x2,x3,x4}x;

說明后,x1,x2,x3,x4的值分別為0,1,2,3,當(dāng)定義改變成:

enumstring

{

x1,

x2=0,

x3=50,

x4,

}

x;5.1.8C51位操作及其表達(dá)式

C51提供了如下位操作運(yùn)算符:

& 按位與

| 按位或

^ 按位異或

~ 按位取反

<< 位左移

>> 位右移

1.“按位與”運(yùn)算符“&”

運(yùn)算規(guī)則:參加運(yùn)算的兩個(gè)運(yùn)算對(duì)象,若兩者相應(yīng)的位都為1,則該位結(jié)果值為1,否則為0。即

0&0=0

0&1=0

1&0=0

1&1=1

【例5-1】若a=54H=010100B,b=3BH=00111011B,

則表達(dá)式c=a&b的值為10H,即

a:01010100

b:&00111011

(10H)

c:=0010000

2.“按位或”運(yùn)算符“|”

運(yùn)算規(guī)則:參加運(yùn)算的兩個(gè)運(yùn)算對(duì)象,若兩者相應(yīng)的位置中只要有一個(gè)為1,則該位結(jié)果為1。即

0|0=0

0|1=1

1|0=1

1|1=1

【例5-2】若a=30H=00110000B,b=0FH=00001111B,

則表達(dá)式c=a|b的值為3FH,即

A:00110000

B:|

00001111

(3FH)

C=00111111

3.“按位異或”運(yùn)算符“^”

運(yùn)算規(guī)則:參加運(yùn)算的兩個(gè)運(yùn)算對(duì)象,若兩者相應(yīng)的位置相同,則結(jié)果為0;若兩者相應(yīng)的位置相異,則結(jié)果為1。即

0^0=0

0^1=1

1^0=1

1^1=0

【例5-3】若a=A5H=10100101,b=37H=00110111,

則表達(dá)式c=a^b的值為92H,即

a:10100101

b:00110111

(92H)

10010010

4.“按位取反”運(yùn)算符“~”

~是一個(gè)單目運(yùn)算符,用來對(duì)一個(gè)二進(jìn)制數(shù)按位進(jìn)行取反,即0變1,1變0。

【例5-4】若a=FOH=11110000B,則表達(dá)式a=~a值為0FH,即

a:11110000

~

(0FH)

00001111

5.“位左移”和“位右移”運(yùn)算符“<<”和“>>”

位左移運(yùn)算符<<和位右移運(yùn)算符>>,用來將一個(gè)數(shù)各二進(jìn)制位的全部左移或右移若干位,移位后,空白為補(bǔ)0,而溢出位舍棄。

【例5-5】若a=FAH=111010101B,則表達(dá)式a=a<<2將a值左移兩位,其結(jié)果為A8H,即

【例5-6】若a=11000011B=E3H,將a值右循環(huán)位移2位。

a值右循環(huán)位移n位,即將a中原來左邊(8-n)位右移n位,而將原來右邊的n位移到最左面n位。

上述問題可以通過下列步驟來實(shí)現(xiàn):

(1)將a的右端n位先放到b的高n位中,即

b=a<<(8-n);

(2)將a的右端n位,其左邊高n位補(bǔ)0,即

c=a>>n;

(3)將b、c進(jìn)行或運(yùn)算,即

a=c|b;

故對(duì)a進(jìn)行循環(huán)右移2位的程序可這樣編寫:

main()

{

unsignedchara=0xc3,b,c;

intn=2;

b=a<<(8-n);

c=a>>n;

a=c|b;

}

結(jié)果:循環(huán)右移前a=11000011

循環(huán)右移后a=11110000

【例5-7】分析下面程序段的作用。

#definePORTAXBYTE[0XFFC0]

voidmain()

{…

PORTA=(PORTA&0xbf)|0x4;

}5.1.9自增減運(yùn)算符、復(fù)合運(yùn)算符及其表達(dá)式

1.自增減運(yùn)算符

【例5-8】若i值原來為5,則

j=++i:j值為6,i值也為6

j=i++:j值為5,i值為6

【例5-9】若i原值為3,則表達(dá)式k=(++i)+(++i)+(++i)的值為18。這是因?yàn)?++i最先執(zhí)行,先對(duì)表達(dá)式進(jìn)行掃描,對(duì)i進(jìn)行3次自加(++i),此時(shí)i=6,然后執(zhí)行k=6+6+6=18,故k值為18。

而表達(dá)式k=(i++)+(i++)+(i++)其結(jié)果是:k值為9,而i值為6。因?yàn)橄葘?duì)i進(jìn)行3次相加,再執(zhí)行3次i的自加。

注意:(1)自增運(yùn)算符(++)和自減運(yùn)算符(--)只能用于變量而不能用于常量表達(dá)式。

(2)(++)和(--)的結(jié)合方向是“自右向左”。

【例5-10】-i++相當(dāng)于-(i++),假如i的原值為3,則表達(dá)式k=-i++的結(jié)果k值為-3,而i值為4。

2.復(fù)合運(yùn)算符及其表達(dá)式

凡是雙目運(yùn)算符,都可以與賦值運(yùn)算符“=”一起組成復(fù)合賦值運(yùn)算符。C51共提供了10種復(fù)合賦值運(yùn)算符。即

+=,-=,*=,/=,%=,<<=,>>=,&=,^=,|=

采用這種復(fù)合賦值運(yùn)算的目的是簡化程序,提高C程序編譯效率。如:a+=b 相當(dāng)于 a=a+b

a-=b 相當(dāng)于 a=a-b

a*=b 相當(dāng)于 a=a*b

a/=b 相當(dāng)于 a=a/b

a%=b 相當(dāng)于 a%b

a<<=8 相當(dāng)于 a=a<<8

a>>8 相當(dāng)于 a=a>>8

5.2.1存取AT89S52單片機(jī)特殊功能寄存器

單片機(jī)AT89S52內(nèi)部有一些特殊功能寄存器(SFR),如P0、P1其對(duì)應(yīng)的內(nèi)存地址分別為80H、90H、A0H、B0H……在編寫匯編程序時(shí)可以對(duì)端口1做輸出控制:

MOVA,#0

MOVP1,A5.2C51程序設(shè)計(jì)技巧這兩條指令將端口1全部設(shè)為低電位。對(duì)于C51語言,則可以用以下方式來控制:

#include″AT89S52reg.h″

P1=0;

只要將定義文件AT89S521reg.h包括進(jìn)來即可。因?yàn)轭^文件中已對(duì)AT89S52內(nèi)部各個(gè)專用寄存器做了定義,其內(nèi)容如下:/*

*AT89S52internalregisterdehnitionsforDDSMICRO-C/51

*

*Copyright1991-1994DaveDunfield

*Allrightsreserved.

*/

externalregisterunsignedcharPSW,SP,DPH,DPL,P0,P1,P2,P3,IP,IE,TMOD,TCON,TH0,TL0,TH1,TL1,SCON,SBUF,PCON,

T2CON,TH2,TL2,RCAP2H,RCAP2L;

若想從端口1中讀取數(shù)據(jù)至變量in中,可以用如下指令:

#include“AT89S52.reg.h”

charin;

in=P15.2.2位的控制

AT89S52內(nèi)部有一些特殊功能寄存器,其中可以分別做位的控制,如P0、P1、P2、P3等。例如,將端口1位7設(shè)為高電位。可以使用匯編語言指令:

setbP1.7

將其設(shè)為低電位可以使用指令:

clrP1.7

將位取反可以使用指令:

cplP1.7

而在C51中則可以使用如下指令:#include"AT89S52io.h" /*一般I/O定義*/

#include"AT89S52lbit.h" /*位設(shè)定/取消宏定義*/

#include"AT89S52reg.h" /*8051寄存器定義*/

setbit(P1.7), /*設(shè)為高電位*/

clrbit(P1.7); /*設(shè)為低電位*/

cplbit(P1.7); /*位取反*/上述3指令在AT89S52bit.h定義中已用宏處理了。其內(nèi)容如下:

/*

*MacrostoallowdirectaccesstotheI/ObitsoftheAT89S52

*internalregistersfromDDSMICRO-C/51.

*REQUIRESTHEEXTERNALPREPROCESSOR(MCP)!

*

*Copyright1991-1994DaveDunfield

*Allrightsreserved.

*/

#definesetbit(bit)asm{/*MacrotosetaI/Obit*/

SETBbit

}#defineclrbit(bit)asm{/*MacrotoclearanI/Obit*/

CLRbit

}

Definecplbit(bit)asm{/*MacrotocomplemetanI/Obit*/

CPLbit

}5.2.3中斷子程序的設(shè)計(jì)

在有關(guān)中斷的頭文件AT89S52INT.H中,有關(guān)于中斷向量的執(zhí)行地址,如下所示:/*

*Common8025interruptvectoradresses

(Mustbedecimal)

*/

defineIEO3/*Externalinterrupt0*/

#defineTFO11/*Timer0rollover*/

defineIE119/*Externalinterrupt1*/

defineTF127/*Timer1rollover*/

#defineSER35/*SerialportRXorTX*/

#defineTF243/*Timer2rollover*/

defineEXF243/*Timer2externalflag*/若中斷程序?qū)憺槿缦碌某绦蚪Y(jié)構(gòu):

INTERRUPT(-TF0-)t0–isr()

{

程序內(nèi)容

}

【例5-11】以計(jì)時(shí)器0模式1做每隔5ms的計(jì)時(shí)中斷,即每隔5ms執(zhí)行一次中斷服務(wù)程序t0-isr()。

#include″AT89S52i0.h″

#include″AT89S52reg.h″

#include″AT89S52bit.h″

#include″AT89S52lint.h″

#dehneHI238/*5msrun1timeISR*/

#defineLO0

INTERRUPT(-TF0-)t0–isr()

{

TH0=HI;

TL0=LO;

}

main()

{

TMOD=0x01;

TH0=HI;

TL0=LO;

IE=0x82;

TCON=0x10;

}5.2.4內(nèi)存應(yīng)對(duì)式I/O

【例5-12】將外部RAM從2000H起的連續(xù)100字節(jié)全部填為“55H”。

程序如下:

#defineadd(char*)0x2000

test–ext-ram()

inti;

char*pt;

pt=add;

for(i=0;i<100;i++)

*pt++=0x55

【例5-13】從AT89S52單板上8255端口A送出數(shù)據(jù)“55H”。

程序如下:

#definepa(*(char*)0x8000)

definepb(*(char*)0x8001)

definepc(*(char*)0x8002)

definecr(*(char*)0x8003)

text-8255()

{

cr=0x80;

pa=0x55;

}5.2.5C51程序設(shè)計(jì)舉例

1.“求和”的C51程序設(shè)計(jì)

【例5-14】已知x=10,y=20,計(jì)算z=x+y的結(jié)果。

main() /*主函數(shù)名*/

{ /*主函數(shù)體開始*/

intx,y,z; /*主函數(shù)的內(nèi)部變量類型說明*/

x=10:y=20; /*變量賦值*/

z=x+y; /*計(jì)算z=x+y的值*/

} /*程序結(jié)束*/

2.求最大值的C51程序設(shè)計(jì)

【例5-15】求最大值。

#include〈stdio.h〉 /*預(yù)處理命令*/

include〈reg51.h〉

main() /*主函數(shù)名*/

{ /*主函數(shù)體開始*/

inta,A,c; /*主函數(shù)的內(nèi)部變量類型說明*/

intmax(intx,inty); /*功能函數(shù)max及其形式參數(shù)說明*/

SCON=0x52; /*8051單片機(jī)串行口初始化*/

TMOD=0x20;

TCON=0x0F3

scanf(″%d%d,&a,&A″)/*輸入變量a和A的值*/

c=max(a,A); /*調(diào)用max函數(shù)*/

printf(″max=%d″,c) /*輸出變量c的值*/

} /*主程序結(jié)束*/

intmax(intx,inty) /*定義max函數(shù),x、y為形式參數(shù)*/

{ /*max函數(shù)體開始*/

intz; /*max函數(shù)內(nèi)部變量類型說明*/

if(x>y)z=x /*計(jì)算最大值*/

elsez=y;

return(z);/*將計(jì)算得到的最大值z(mì)返回到調(diào)用處*/

} /*max函數(shù)結(jié)束*/

C51本身提供有“asm”語句,有以下兩種格式。

格式1:

asm″匯編語言指令″;

在此格式中,雙引號(hào)內(nèi)的所有指令將全部送到匯編語言編譯器。注意,在語句的最后要加上分號(hào),作為語句的結(jié)束,如同一般的C語言程序。

格式2:

asm{

匯編語言指令

};5.3匯編語言與C語言的混合編程下面舉一個(gè)在C語言程序設(shè)計(jì)中加入?yún)R編語言語句的實(shí)例。

#include"AT89S52io.h"

#include"AT89S52reg.h"

#include"AT89S52bit"

/**/

text-asm0.

{

asm"nop";

asm"nop";

asm"clrP1.7"

}

/**/

text-asml()

{

asm{

NOP

NOP

CPLPI.7

}

}

/**/

main()

{

test-asm()

test-asm()

}5.3.1C51和A51接口所涉及的幾個(gè)主要問題

1.C51函數(shù)名的轉(zhuǎn)換及其命名規(guī)則

C51中函數(shù)名的轉(zhuǎn)換規(guī)則如表5-6所示。表5-6C51函數(shù)名的轉(zhuǎn)換規(guī)則

2.C51函數(shù)及其相關(guān)段的命名規(guī)則

依賴于所使用的存儲(chǔ)器模式,這些段的段名按表5-7所列規(guī)則命名,在相互調(diào)用時(shí),匯編語言必須服從C51有關(guān)段名的命名規(guī)則。表5-7各種存儲(chǔ)器模式下函數(shù)相關(guān)段名的命名規(guī)則

3.C51函數(shù)的參數(shù)傳遞規(guī)則

表5-8是利用寄存器傳遞參數(shù)的規(guī)則。表5-8C51中的參數(shù)傳遞當(dāng)函數(shù)具有返回值時(shí),也需傳遞參數(shù),這種返回值參數(shù)的傳遞均是通過CPU內(nèi)部寄存器完成,其傳遞規(guī)則如表5-9所示。表5-9函數(shù)返回使用的寄存器下面給出了一個(gè)C51程序及其編譯后的程序清單,從中可以更直觀地理解C51的函數(shù)名轉(zhuǎn)換規(guī)則、段命名規(guī)則及參數(shù)傳遞規(guī)則。

/*

文件名:ASM.c

功能:計(jì)算x/y

*/

#Include<reg51.h>

#deinfineucharunsignedchar

ucharfunc(ucharx,uchary); /*函數(shù)func原型聲明*/

voidmain(void) /*主函數(shù)*/

{

func(0x12,0x34); /*調(diào)用函數(shù)func*/

}

ucharfunc(ucharx,uchary) /*函數(shù)func*/

{

return(x/y) /*計(jì)算x/y并返回結(jié)果*/

}

;********************************

;文件名;ASM.SRC

;說明:此文件是ASM.C編譯后的匯編輸出文件(限于篇幅,有所省略)

;********************************

?PR?main?ASMSEGMENTCODE /*主函數(shù)main代碼段聲明*/

?PR?_func?ASMSEGMENTCOME /*函數(shù)func代碼段聲明*/

PUBLIC_func /*公開函數(shù)名以便可被其他模塊調(diào)用*/

PUBLICmain

RSEG?PR?main?ASM

main /*主函數(shù)代碼段起始*/

;{

;func(0x12,0x34);

MOVR7,#02H /*R7傳遞第一個(gè)char參數(shù)*/

MOVR5,#034H /*R5傳遞第二個(gè)char參數(shù)*/

LCALI_func /*調(diào)用函數(shù)func*/

;}

RET /*返回*/

;ucharfunc(ucharx,uchary)

RSEG?PR?_func?ASM_func; /*函數(shù)func代碼段起始*/

;{

;return(x/y);

MOVA,R7; /*計(jì)算x/y*/

MOVB,R5

DIVAB

MOVR7,A /*結(jié)果經(jīng)R7返回*/

;}

RET /*返回*/

END /*結(jié)束*/5.3.2C51程序中嵌入?yún)R編

(1)通過預(yù)編譯指令“#pragmaasm”和“#pragma.asm”在C語言代碼中插入?yún)R編語言代碼,如:

#include〈reg51.h〉

voidmain(void)

{

P2=1;

#pragmaasm//從此處插入?yún)R編代碼

MOVR7,#10

DEL:MOVR6,#20

DJNZR6,$

DJNZR7,DEL

#pragmaendasm//結(jié)束匯編代碼

P2=0;

}

(2)在project窗口中包含匯編代碼的C文件上單擊右鍵,選擇“Optionsfor…”選項(xiàng),單擊右邊的“GenerateassemblerSRCFile”和“AssembleSRCFile”,使復(fù)選框由灰色變成黑色狀態(tài),設(shè)置完成之后的對(duì)話框如圖5-2所示。

圖5-2SRC選項(xiàng)設(shè)置完成之后的對(duì)話框

(3)根據(jù)選擇的編譯模式,把相應(yīng)的庫文件(如Small模式時(shí)是Keil\C51\Lib\C51S.Lib)加入工程中,該文件必須作為工程的最后文件。如果沒有做這一步,編譯時(shí)會(huì)出現(xiàn)如下警告:

“UNRESOLVEDEXTERNALSYMBOL”。

(4)編譯,即可生成目標(biāo)代碼。5.3.3C51與匯編函數(shù)的相互調(diào)用

1)先用C語言編寫所有的代碼,包括需要匯編語言實(shí)現(xiàn)的部分。這里所選的例子就是前面討論的單片機(jī)模擬節(jié)能路燈的例子,延時(shí)子程序用匯編語言編寫,其余程序用C語言編寫。

則程序清單如下:/*

文件名:main.c

功能:模擬節(jié)能路燈的控制過程主程序

*/

#include〈AT89X51.H〉

SbitK1=P3^0;

SbitL1=P1^0;

externvoiddelay02s(void);//延時(shí)0.2s子程序

voidmain(void)

{

while(I)

{

if(K1==0){

L1=0; //點(diǎn)亮發(fā)光二極管

delay02s(); //調(diào)用延時(shí)子程序

L1=1; //熄滅發(fā)光二極管

}

else

{

L1=1; //熄滅發(fā)光二極管

}

}

}/*

文件名:delay.c

功能:延時(shí)0.2s

*/

delay02s(void)

{

unsignedchari,j,k;

for(i=20;i>0;i--)

for(j=20;j>0;j--)

for(k=248;k>0;k--);

}

(2)建立項(xiàng)目文件,將main.c和delay.c都包含進(jìn)項(xiàng)目。

(3)在project窗口中包含匯編代碼的.c文件上單擊右鍵,選擇“Optionsfor…”選項(xiàng),單擊右邊的“GenerateassemblerSRCFile”和“AssembleSRCFile”,使復(fù)選框由灰色變成黑色(有效)狀態(tài)。本例是在delay.c文件上進(jìn)行此操作。

(4)根據(jù)選擇的匯編模式,把相應(yīng)的庫文件(Small模式時(shí),是Keil\C51\Lib\C51S.Lib)加入工程,該文件必須作為工程的最后文件。

(5)編譯這個(gè)項(xiàng)目后將會(huì)產(chǎn)生一個(gè)delay.SRC的文件,將這個(gè)文件名改為delay.A51。為了讓用戶更直觀地認(rèn)識(shí)C程序經(jīng)編譯器編譯之后的情況,下面給出了由編譯器產(chǎn)生的不做任何修改的delay.a51的清單:

;\delay.SRCgeneratedfrom:delay.c

;COMPILERINVOKEDBY:

;d:\keil\C51\BIN\C51.EXEdelay.cBROWSEDEBUGOBJECTEXTENDSRC(.\delay.SRC)

NAMEDELAY

?PR?delay02s?DELAYSEGMENTCODE

PUBLICdelay02S

;/*

;文件名:delay.c

;功能:延時(shí)0.2s

;*/

;voiddelay02s(void)

RSEG?PR?delay02s?DELAY

Delay02s

USING0

;SOURCELINE#5

;{

;SOURCELINE#6

;unsignedchari,j,k;

;for(i=20;i>0;i--)

;SOURCELINE#8;

;Variable′i?040′assignedtoRegister′R7′

MOVR7,#014H

?Cooo1:

;for(j=20;j>0;j--)

;SOURCELINE#9

;Variable′j?041′assignedtoRegister′R6′

MOVR6,#014H

?C0001:

;for(k=248;k>0;k--)

;SOURCELINE#10

;Variable′k?042′assignedtoregister′R5′

MOVR5,#0F8H

?C0007

DJNZR5,?C0007

?C0006

DJNZR6,?C0004

?C0003

DJNZR7,?C0001

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論