版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 電信課程設(shè)計(jì)案例
- 總賬初始化設(shè)置課程設(shè)計(jì)
- 小學(xué)生外國傳統(tǒng)課程設(shè)計(jì)
- 2024年黑龍江省安全員C證考試題庫
- 系統(tǒng)soc課程設(shè)計(jì)
- 磚混廠房概預(yù)算課程設(shè)計(jì)
- 穩(wěn)壓電流源課程設(shè)計(jì)
- 籃球暑期課程設(shè)計(jì)意圖
- 研學(xué)課程設(shè)計(jì)南鑼鼓巷
- 糖化熱量衡算課程設(shè)計(jì)
- 湖南2025年湖南機(jī)電職業(yè)技術(shù)學(xué)院合同制教師招聘31人歷年參考題庫(頻考版)含答案解析
- 2024年電子交易:電腦買賣合同
- 中國文化概論知識(shí)試題與答案版
- 期末復(fù)習(xí)提升測(cè)試(試題)(含答案)2024-2025學(xué)年四年級(jí)上冊(cè)數(shù)學(xué)人教版
- 生和碼頭港口設(shè)施維護(hù)管理制度(3篇)
- 黑龍江省哈爾濱市第六中學(xué)2025屆高考數(shù)學(xué)三模試卷含解析
- 傷口治療師進(jìn)修匯報(bào)
- 研學(xué)活動(dòng)協(xié)議書合同范本
- ISBAR輔助工具在交班中應(yīng)用
- AIGC行業(yè)報(bào)告:國內(nèi)外大模型和AI應(yīng)用梳理
- 換熱器的原理及構(gòu)造
評(píng)論
0/150
提交評(píng)論