《單片機原理及接口技術》課件第8章_第1頁
《單片機原理及接口技術》課件第8章_第2頁
《單片機原理及接口技術》課件第8章_第3頁
《單片機原理及接口技術》課件第8章_第4頁
《單片機原理及接口技術》課件第8章_第5頁
已閱讀5頁,還剩129頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

第8章單片機C程序設計及應用8.1單片機C51程序設計

8.2采用C51程序的設計實例

本章小結(jié)

練習與思考題

8.1單片機C51程序設計

8.1.1單片機C程序的基本概念

目前仍在使用的單片機開發(fā)設計語言大致有兩類:匯編語言和C語言。C語言由于其結(jié)構(gòu)化、移植性好和高效性的特點,是進行單片機開發(fā)的一種利器。C語言是一種源于編寫UNIX操作系統(tǒng)的語言,與匯編語言相比,有以下優(yōu)點:

(1)不需要了解51單片機的指令系統(tǒng),僅僅要求初步了解存儲器結(jié)構(gòu)。

(2)程序有規(guī)范的結(jié)構(gòu),可分為不同的函數(shù),使程序結(jié)構(gòu)化。

(3)程序可讀性好。

(4)提供很多標準庫函數(shù),數(shù)據(jù)處理能力強。

(5)程序易于做到模塊化,移植性好。8.1.2單片機C程序的基本結(jié)構(gòu)

C語言是一種通用性很強的結(jié)構(gòu)化程序設計語言。從程序流程的角度來看,單片機C程序可以分為3種基本結(jié)構(gòu):順序結(jié)構(gòu)、選擇結(jié)構(gòu)和循環(huán)結(jié)構(gòu)。這3種基本結(jié)構(gòu)可以組成各種復雜程序。

1.順序結(jié)構(gòu)

順序結(jié)構(gòu)程序是僅包含一個main()函數(shù)的簡單程序,適當運用表達式語句就能設計出具有某特定功能的順序結(jié)構(gòu)C51程序。這是一種最簡單的基本結(jié)構(gòu),程序只由低地址向高地址順序執(zhí)行指令代碼,如圖8-1所示。雖然該程序設計方法簡單,但在具體運用中的算法仍然采用自頂向下逐步求精的方法進行設計。圖8-1順序結(jié)構(gòu)

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

使單片機具有決策能力的是選擇結(jié)構(gòu),這種結(jié)構(gòu)也稱為分支結(jié)構(gòu),如圖8-2(a)所示。選擇結(jié)構(gòu)中包含一個判斷框,執(zhí)行流程根據(jù)判斷條件P的成立與否,選擇執(zhí)行其中的一路分支。圖8-2(b)所示的是特殊的選擇結(jié)構(gòu),即一路為空的選擇結(jié)構(gòu)。這種選擇結(jié)構(gòu)中,當P條件成立時,執(zhí)行A操作,然后脫離選擇結(jié)構(gòu);如果P條件不成立,則直接脫離選擇結(jié)構(gòu)。它包括if語句結(jié)構(gòu)和switch語句結(jié)構(gòu)兩種。圖8-2選擇結(jié)構(gòu)

1)?if語句結(jié)構(gòu)

C語言的if語句有3種形式:基本if形式、if-else形式、if-else-if形式。

基本if形式語法結(jié)構(gòu)如下:

if(表達式)

處理程序;

處理機理是:如果表達式的值為“真”,則執(zhí)行“處理程序”的語句內(nèi)容,否則不執(zhí)行該語句內(nèi)容。例如:

voidmain()

{

ucharsp0=0,buffer0[2]={0,0};

if(sp0==0)

buffer0[sp0]=RXBUF0;//接收串口數(shù)據(jù)

}

if-else形式語法結(jié)構(gòu)如下:

if(表達式)

處理程序1;

else

處理程序2;處理機理是:如果if表達式的值為“真”,則執(zhí)行“處理程序1”的語句內(nèi)容,否則執(zhí)行“處理程序2”語句內(nèi)容。例如:

voidmain()

{

ucharend,rev_flag;

if(end==1)

rev_flag0=1;

else

rev_flag0=0;

}

if-else-if形式語法結(jié)構(gòu)如下:

if(表達式1)

處理程序1;

elseif(表達式2)

處理程序2;

else(表達式n)

處理程序n;處理機理是:如果表達式1的值為“真”,則執(zhí)行與之相對應的“處理程序1”的語句內(nèi)容;如果表達式2的值為“真”,則執(zhí)行與之相對應的“處理程序2”的語句內(nèi)容,依次判斷表達式“x”是否為“真”,如果為“真”則執(zhí)行與之相對應的“處理程序x”語句內(nèi)容。例如:

voidmain()

{

ucharsp0=0,rev_byte0,buffer0[2]={0,0},

receive_frame[10];

if(sp0==0)

{

buffer0[sp0]=RXBUF0;//接收串口數(shù)據(jù)

if(buffer0[0]==0xEB)sp0++;

}

/*判斷第二個字節(jié)*/

elseif(sp0==1)

{

buffer0[sp0]=RXBUF0;

if((buffer0[0]==0xEB)&&(buffer0[1]==0x90))

sp0++;//數(shù)據(jù)為EB90

elsesp0=0;

}

elseif(sp0>=2)

{

receive_frame[rev_byte0]=RXBUF0;

rev_byte0++;

}

2)?switch語句結(jié)構(gòu)

C語言的switch語句又稱開關語句,它可以從多種情況中選擇滿足條件的一種情況,是多分支選擇結(jié)構(gòu)語句。

switch形式語法結(jié)構(gòu)如下:switch(表達式)

{

case<常量表達式1>:[處理序列1;[break]]

case<常量表達式2>:[處理序列2;[break]]

case<常量表達式n>:[處理序列n;[break]]

[default:處理序列n+1;]

}處理機理是:計算表達式的值,并逐個與其后的常量表達式的值相比較,當表達式的值與某個常量表達式的值相等,即執(zhí)行其后的處理序列語句,然后不再進行判斷,繼續(xù)執(zhí)行后面所有case后的處理序列語句。如表達式的值與所有case后的常量表達式都不相同時,則執(zhí)行default后的處理序列語句。C語言還提供了一種break語句,專用于跳出switch語句。例如:voidmain()

{

ucharflag=0,up=0,down=0,left=0,right=0;

switch(flag)

{

case1:up=1;break;//置標志

case2:down=1;break;

case3:left=1;break;

case4:right=1;break;

default:error=1;break;

}

}本例中輸入一個整數(shù),經(jīng)switch判斷后,選擇輸出是一周中的星期幾,整數(shù)不在1~7的范圍內(nèi)時就輸出“Error”??梢姶祟惗喾种С绦蛴胹witch語句可以很容易實現(xiàn)。

3.循環(huán)結(jié)構(gòu)

計算機的基本特征之一就是具有重復執(zhí)行一組語句的能力——循環(huán)能力。循環(huán)結(jié)構(gòu)是程序中一種很重要的結(jié)構(gòu)。其特點是:在給定條件成立時,反復執(zhí)行某程序段,直到條件不成立時為止。

循環(huán)結(jié)構(gòu)有兩種形式:當型循環(huán)和直到型循環(huán)。

1)當型循環(huán)

判斷條件P是否成立,若成立,則重復執(zhí)行A操作,直至某次判斷條件P不再成立,就不再執(zhí)行A操作而退出循環(huán)結(jié)構(gòu),見圖8-3(a)。

2)直到型循環(huán)

重復執(zhí)行A操作,然后判斷條件P是否成立,如果不成立再執(zhí)行A操作,直到條件P成立,不再執(zhí)行A操作,退出循環(huán),見圖8-3(b)。圖8-3循環(huán)結(jié)構(gòu)無論是順序結(jié)構(gòu)、選擇結(jié)構(gòu),還是循環(huán)結(jié)構(gòu),它們有一個共同點,即只有一個入口且只有一個出口。從示意圖中可以看到,如果把基本結(jié)構(gòu)看做是一個整體(用虛線框表示),執(zhí)行流程從a點進入基本結(jié)構(gòu),而從b點脫離基本結(jié)構(gòu)。整個程序由若干個這樣的基本結(jié)構(gòu)組合而成,必然有良好的可讀性和可維護性。它包括for語句結(jié)構(gòu)和while語句結(jié)構(gòu)兩種。

(1)?for語句結(jié)構(gòu)。C語言中,for語句是一種使用最為方便靈活的循環(huán)控制語句結(jié)構(gòu),它提供了一個應用非常靈活的控制部分,既可以實現(xiàn)計數(shù)循環(huán)程序設計,又可以實現(xiàn)條件控制循環(huán)程序設計。

for形式語法結(jié)構(gòu)如下:

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

處理程序;處理機理是:首先計算“表達式1”的值;再計算“表達式2”的值,若值為“真”則執(zhí)行循環(huán)體一次,否則跳出循環(huán);然后再計算“表達式3”的值,轉(zhuǎn)回第2步重復執(zhí)行。在整個for循環(huán)過程中,“表達式1”只計算一次,作為for的入口語句條件,“表達式2”和“表達式3”則可能計算多次。循環(huán)體也可能多次執(zhí)行,也可能一次都不執(zhí)行。例如:

voidmain()

{

intn,sum=0;

for(n=0;n<=50;n++)

sum+=n;

}

在使用for語句中有幾點要特別注意:①循環(huán)體內(nèi)的處理程序可以為空操作;②for語句的各表達式都可以省,而分號不能省,在省略各表達式時要特別小心分析,防止造成無限死循環(huán)。

(2)?while語句結(jié)構(gòu)。while形式語法結(jié)構(gòu)有當while形式和直到while形式兩種。

當while形式如下:

while(表達式)

處理程序;

處理機理是:計算“表達式”的值,若為“真”則執(zhí)行循環(huán)體的處理程序一次,然后再對表達式進行計算執(zhí)行,直到表達式的值為“假”時停止循環(huán)。循環(huán)體也可能多次執(zhí)行,也可能一次都不執(zhí)行。例如:

voidmain()

{

intn=0,sum=0;

while(n<50)

{

n+=1;

sum+=n;

}

}

直到循環(huán)do-while形式如下:

do

處理程序;

while(表達式);

處理機理是:先執(zhí)行處理程序,到while時計算“表達式”的值,若為“真”則再次執(zhí)行循環(huán)體的處理程序一次,直到表達式的值為“假”時停止循環(huán)。循環(huán)體至少會執(zhí)行一次。例如:

voidmain()

{

intn=0,sum=0;

do

{

n+=1;

sum+=n;

}

while(n<=50);

}8.1.3單片機C程序的數(shù)據(jù)類型

數(shù)據(jù)是計算機操作的對象。無論用何種語言、算法進行程序設計,最終在計算機中運行的只有數(shù)據(jù)流。數(shù)據(jù)的不同格式稱為數(shù)據(jù)類型。開始單片機C程序的學習之前先應該熟悉它所支持的數(shù)據(jù)類型。

C語言數(shù)據(jù)類型包括:基本類型、構(gòu)造類型、指針類型以及空類型。其中,基本數(shù)據(jù)類型包括位(bit)、字符(char)、整型(int)、短整型(short)、長整型(long)、浮點型(float)以及雙精度浮點型(double);構(gòu)造類型包括數(shù)組(array)、結(jié)構(gòu)體(struct)、共用體(union)以及枚舉類型(enum)。對于51系列單片機編程而言,支持的數(shù)據(jù)類型是和編譯器有關的,比如C51編譯器中整型(int)和短整型(short)相同,浮點型(float)和雙精度浮點型(double)相同。表8-1列出了C51編譯器KEILuVision2C51編譯器所支持的數(shù)據(jù)類型。表8-1KEILuVision2C51編譯器所支持的數(shù)據(jù)類型下面來看看它們的具體定義。

1.字符類型char

char類型的長度是一個字節(jié),通常用于定義處理字符類型的變量或常量。它分為無符號字符類型unsignedchar和有符號字符類型signedchar,默認值為signedchar類型。unsignedchar類型用字節(jié)中所有位表示數(shù)值,可以表達的數(shù)值范圍是0~(28-1)。signedchar類型用字節(jié)中最高位表示數(shù)據(jù)的符號,“0”表示正數(shù),“1”表示負數(shù),負數(shù)用補碼表示,可以表達的數(shù)值范圍是?-27~+(27-1)。

2.整型int

int類型的長度是兩個字節(jié),用于存放一個雙字節(jié)數(shù)據(jù),它分為無符號整型unsignedint和有符號整型signedint,?默認值為signedint類型。?unsignedint表示的數(shù)值范圍是0~216-1。signedint類型用字節(jié)中最高位表示數(shù)據(jù)的符號,“0”表示正數(shù),“1”表示負數(shù),負數(shù)用補碼表示,可以表達的數(shù)值范圍是-215~+(215-1)。

3.長整型long

long類型的長度為4個字節(jié),用于存放一個4字節(jié)數(shù)據(jù),分為無符號長整型unsignedlong和有符號長整型signedlong,默認值為signedlong類型。unsignedlong表示的數(shù)值范圍是0~232-1。signedlong類型用字節(jié)中最高位表示數(shù)據(jù)的符號,“0”表示正數(shù),“1”表示負數(shù),負數(shù)用補碼表示,可以表達的數(shù)值范圍是?-231~+(231-1)。

4.浮點型float

float類型的長度是32位,占用4個字節(jié),與整型數(shù)據(jù)相比,浮點類型帶有小數(shù)位,并且可以表示更大范圍的數(shù)值。它用符號位表示數(shù)的符號,用階碼與尾數(shù)表示數(shù)的大小。浮點型數(shù)據(jù)在運算時往往有舍入誤差,它與該浮點數(shù)在計算機內(nèi)的表示值,可能會有微小差別。

5.指針型*

*(星號)類型本身就是一個變量,在這個變量中存放指向另一個數(shù)據(jù)的地址。這個指針變量要占據(jù)一定的內(nèi)存單元。對不同的處理器其長度也不盡相同,在C51中,它的長度一般為1~3個字節(jié)。

6.位類型bit

bit(位)類型是C51編譯器的一種擴充數(shù)據(jù)類型,利用它可以定義一個位變量,但不能定義位指針,也不能定義位數(shù)組。它的值是一個二進制位,不是0就是1,類似一些高級語言中的布爾變量True和False。

7.特殊功能寄存器sfr

sfr類型也是一種擴充數(shù)據(jù)類型,占一個內(nèi)存單元,值域為0~255。利用它可以訪問51單片機內(nèi)部的所有特殊功能寄存器。例如:

sfrP0=0x80;//定義P0為P0端口在片內(nèi)的寄存器,P0

口地址為80H

sfrP1=0x90;//定義P1為P1端口在片內(nèi)的寄存器,P1

口地址為90H

8051單片機片內(nèi)有21個特殊功能寄存器,它們分散在片內(nèi)RAM區(qū)的高128字節(jié)中,地址為80H~0FFH。對sfr的操作,只能用直接尋址方式。

8.16位特殊功能寄存器sfr16

sfr16類型占用兩個內(nèi)存單元,值域為0~65535。sfr16和sfr一樣用于操作特殊功能寄存器,所不同的是它用于操作占兩個字節(jié)的寄存器,如定時器T0和T1。

9.可尋址位sbit

sbit類型也是C51中的一個擴充類型,利用它可以訪問芯片內(nèi)部的RAM中的可尋址位或特殊功能寄存器中的可尋址位。例如:

sbitP1_1=P1^1;//P1_1為P1中的P1.1引腳

這樣在以后的程序語句中就可以用P1_1來對P1.1引腳進行讀/寫操作。8.1.4單片機C程序的算術表達式

C程序的運算符主要有7種類型。

1.算術運算符和表達式

算術運算符用于各類數(shù)值運算,包括加(+)、減(-)、乘(*)、除(?/?)、求余(或稱模運算,%)、自增(++)、自減(--)共7種。用算術運算符和括號將運算對象連接起來的式子稱為算術表達式,其中運算對象包括常量、變量、函數(shù)、數(shù)組、結(jié)構(gòu)等。加法運算符“+”為雙目運算符,即應有兩個量參與加法運算,如a+b,4+8等。具有左結(jié)合性。

減法運算符“-”為雙目運算符。但減號“-”也可作負值運算符,此時為單目運算,如?-x,-5等,具有左結(jié)合性。

乘法運算符“*”為雙目運算符,具有左結(jié)合性。

除法運算符“?/?”為雙目運算符,具有左結(jié)合性。參與運算量均為整型時,結(jié)果也為整型,舍去小數(shù)。如果運算量中有一個是實型,則結(jié)果為雙精度實型。

求余運算符(模運算符)“%”為雙目運算符,具有左結(jié)合性。要求參與運算的量均為整型。求余運算的結(jié)果等于兩數(shù)相除后的余數(shù)。自增1運算符記為“++”,其功能是使變量的值自增1。自減1運算符記為“--”,其功能是使變量值自減1。自增1、自減1運算符均為單目運算,都具有右結(jié)合性??捎幸韵聨追N形式:

++i:i自增1后再參與其他運算;

--i:i自減1后再參與其他運算;

i++:i參與運算后,i的值再自增1;

i--:i參與運算后,i的值再自減1。

在理解和使用上容易出錯的是i++和i--,特別是當它們出現(xiàn)在較復雜的表達式或語句中時,常常難于弄清,因此應仔細分析。

2.關系運算符和表達式

關系運算符用于比較運算,包括大于(>)、小于(<)、大于等于(>=)、小于等于(<=)、等于(=?=)和不等于(!=)6種。

前4種優(yōu)先級相同,后兩種優(yōu)先級相同,前4種的優(yōu)先級又高于后兩種。關系運算符的優(yōu)先級低于算術運算符,但高于賦值運算符。例如:

c>a+b等效于 c>(a+b)

a>b!=c等效于 (a>b)!=c

關系運算符的結(jié)合性為左結(jié)合。

用關系運算符將兩表達式(算術表達式、關系表達式、邏輯表達式等)連接起來的式子,稱為關系表達式。關系表達式的結(jié)果為邏輯真或假。C語言以1代表真,0代表假。例如:若a=5,b=3,c=0,則:

a>b的值為真,表達式的值為1;

d=a>b,d的值為1;

b+c<a的值為假,表達式的值為0;

e=a>b>c,由于結(jié)合性為左結(jié)合,故a>b的值為1,而1>c的值為0,因此e的值為0。3.邏輯運算符和表達式

C語言提供了3種邏輯運算符:與運算(&&),或運算(||),非運算(!)。

與運算符“&&”和或運算符“||”均為雙目運算符,具有左結(jié)合性。非運算符“!”為單目運算符,具有右結(jié)合性。非運算符“!”的優(yōu)先級是這3種中最高的,比算術運算符、關系運算符、與運算符、或運算符及賦值運算符都高。與運算符“&&”和或運算符“||”只比賦值運算符的優(yōu)先級高。例如:

a>b&&c>d等價于 (a>b)&&(c>d)

!b==c||d<a等價于 ((!b)==c)||(d<a)

a+b>c&&x+y<b等價于

((a+b)>c)&&((x+y)<b)

用邏輯運算符將關系表達式或邏輯量連接起來的式子稱為邏輯表達式,邏輯表達式的結(jié)合性為自左向右,其值應該是一個邏輯的真或假。邏輯表達式的值和關系表達式的值相同,以1代表真,以0代表假。

例如:若a=8,b=6,則:

因為a=8為真,所以?!a為假(0);

因為a、b均為真,所以a||b為真(1),a&&b為真(1);

因為“!”的優(yōu)先級高于“&&”,所以?!a&&b為假(0)。

4.位操作運算符和表達式

位操作運算符是用來進行二進制位運算的運算符,包括邏輯位運算符和移位運算符。邏輯位運算符是位與(&)、位或(?|?)、位取反(~)和位異或(^);移位運算符是位左移(<<)和位右移(>>)。除了位取反(~)是單目運算符,其他位操作運算符均為雙目運算符。

位取反(~)用來將二進制數(shù)按位取反,即1變0,0變1。位取反(~)運算符優(yōu)先級比別的算術運算符、關系運算符和其他運算符都高。位與運算符(&)的運算規(guī)則如下:參與運算的兩個運算對象,若兩者相應的位都為1,則該位結(jié)果為1,否則為0。

位或運算符(?|?)的運算規(guī)則如下:參與運算的兩個運算對象,若兩者相應的位都為0,則該位結(jié)果值為零,否則為1。

位異或運算符(^)的運算規(guī)則如下:參與運算的兩個運算對象,若兩者相應的位值相同,則結(jié)果值為0,若兩者相應的位值不同,則結(jié)果值為1。

位左移運算符(<<)、位右移運算符(>>)用來將一個數(shù)的二進制位全部左移或右移若干位,移位后,空白位補0,而溢出的位舍棄。例如:若a=ABH=10101011B,則:

a=a<<2,將a值左移2位,其結(jié)果為10101100B=ACH;

a=a>>2,將a值右移2位,其結(jié)果為00101010B=2AH。

5.賦值運算符和表達式

賦值運算符用于賦值運算,分為簡單賦值(=)、復合算術賦值(+=,-?=,*=,/=,%=)和復合位運算賦值(&=,|=,^=,>>=,<<=)3類共11種。

簡單賦值運算符記為“=”,由“=”連接的式子稱為賦值表達式。其形式為

變量=表達式

例如:

x=a+b

w=sin(a)+sin(b)

賦值表達式的功能是計算表達式的值再賦予左邊的變量。賦值運算符具有右結(jié)合性。因此a=b=c=5可理解為a=(b=c=5)。

在其他高級語言中,賦值構(gòu)成了一個語句,稱為賦值語句。而在C中,把等于符號“=”定義為運算符,從而組成賦值表達式。例如,式子x=(a=3)+(b=6)是合法的。它的意義是把3賦予a,6賦予b,再把a、b相加,其和賦予x,故x應等于9。

如果賦值運算符兩邊的數(shù)據(jù)類型不相同,則系統(tǒng)自動進行類型轉(zhuǎn)換,即把賦值號右邊的類型換成左邊的類型。具體規(guī)定如下:

(1)實型賦予整型,舍去小數(shù)部分。

(2)整型賦予實型,數(shù)值不變,但將以浮點形式存放,即增加小數(shù)部分(小數(shù)部分的值為0)。

(3)字符型賦予整型,由于字符型為一個字節(jié),而整型為兩個字節(jié),故將字符的ASCⅡ碼值放到整型量的低8位中,高8位為0。

(4)整型賦予字符型,只把低8位賦予字符量。在賦值符“=”之前加上其他二目運行符可構(gòu)成復合賦值符。如:+=,-=,*=,/=,%=,<<=,>>=,&=,^=,!=。構(gòu)成復合賦值表達式的一般形式為

變量雙目運算符=表達式

它等效于:

變量=變量運算符表達式例如:

a+=5等價于a=a+5;

x*=y+7等價于x=x*(y+7)

r%=p等價于r=r%p。

復合賦值符的這種寫法,可能對初學者來說不習慣,但十分有利于編譯處理,能提高編譯效率并產(chǎn)生質(zhì)量較高的目標代碼。

6.條件運算符

這是一個三目運算符,唯一的三目運算是條件運算,條件運算符是“?:”。條件表達式的形式為

<表達式1>?<表達式2>:<表達式3>

其含義為:若<表達式1>的值為“真”,則條件表達式取<表達式2>的值;否則取<表達式3>的值。

7.指針運算符

指針運算符用于進行取內(nèi)容(*)和取地址(&)兩種運算。C語言中,運算符的運算優(yōu)先級共分為15級。在表達式中,優(yōu)先級較高的先于優(yōu)先級較低的進行運算。而在一個運算量兩側(cè)的運算符優(yōu)先級相同時,則按運算符的結(jié)合性所規(guī)定的結(jié)合方向處理。C語言中各運算符的結(jié)合性分為兩種,即左結(jié)合性(自左向右)和右結(jié)合性(自右向左)。例如算術運算符的結(jié)合性是自左向右,即先左后右。如表達式x-y+z,則y應先與減號“-”結(jié)合,執(zhí)行x-y運算,然后再執(zhí)行+z的運算。這種自左向右的結(jié)合方向就稱為“左結(jié)合性”。而自右向左的結(jié)合方向稱為“右結(jié)合性”。最典型的右結(jié)合性運算符是賦值運算符。如x=y=z,由于“=”的右結(jié)合性,應先執(zhí)行y=z再執(zhí)行x=(y=z)運算。C語言運算符中有不少為右結(jié)合性,應注意區(qū)別,以避免理解錯誤。8.1.5單片機C程序的一般語法結(jié)構(gòu)

51單片機的C程序的基本程序結(jié)構(gòu)與一般的C語言沒什么差別,也是函數(shù)定義的集合體,即一個單片機的C語言的程序是由若干個函數(shù)組成的,集合中僅有一個名為main的主函數(shù)。在這些函數(shù)中,main函數(shù)是系統(tǒng)執(zhí)行這個程序的入口,它在整個程序中起著總體控制的作用。在main函數(shù)中,可以調(diào)用其他函數(shù)完成總的設計目標,其他函數(shù)也可以互相調(diào)用,其中的所有執(zhí)行語句執(zhí)行完畢,則程序執(zhí)行結(jié)束。

單片機C語言程序的一般組成結(jié)構(gòu)如下:全局變量聲明

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

{

局部變量聲明

執(zhí)行語句

}

函數(shù)1(形參表)

{

局部變量聲明

執(zhí)行語句

}

函數(shù)n(形參表)

{

局部變量聲明

執(zhí)行語句

}

單片機C程序的執(zhí)行從main()函數(shù)開始,調(diào)用其他函數(shù)后返回到主函數(shù)main()中,最后在main()函數(shù)中結(jié)束整個程序的運行。8.1.6C51語言程序設計

1.KeilC51軟件應用

KeilC51是美國KeilSoftware公司出品的51系列兼容單片機C語言軟件開發(fā)環(huán)境,是眾多單片機應用開發(fā)的優(yōu)秀軟件之一,它集編輯、編譯、仿真于一體,支持匯編、PLM語言和C語言的程序設計。KeilC51軟件提供豐富的庫函數(shù)和功能強大的集成開發(fā)調(diào)試工具,全Windows界面,界面友好,易學易用。

下面介紹KeilC51軟件的使用方法。

1)軟件啟動

進入KeilC51后,先是Keil公司的屏幕顯示,幾秒鐘后出現(xiàn)KeilC51的編輯界面,如圖8-4所示。圖8-4進入KeilC51后的編輯界面

2)簡單程序的調(diào)試

學習程序設計語言,學習某種程序軟件,最好的方法是直接操作實踐。下面通過簡單的編程、調(diào)試,引導大家學習KeilC51軟件的基本使用方法和基本的調(diào)試技巧。

(1)建立一個新工程。單擊“Project”菜單,在彈出的下拉菜單中選擇“NewProject”選項。

(2)然后選擇要保存的路徑,輸入工程文件的名字,比如保存到C51目錄里,工程文件的名字為C51,如圖8-5所示,然后單擊“保存”按鈕。圖8-5建立新工程

(3)這時會彈出一個對話框,要求選擇單片機的型號,你可以根據(jù)你使用的單片機來選擇。KeilC51幾乎支持所有的51核的單片機,這里以大家用得比較多的Atmel的AT89C52來說明,如圖8-6所示,選擇AT89C52之后,右邊欄是對這個單片機的基本說明,然后單擊“確定”按鈕。圖8-6單片機選型對話框

(4)完成上一步驟后,屏幕如圖8-7所示。圖8-7建立好一個新工程

(5)在圖8-7中,單擊“File”菜單,再在下拉菜單中單擊“New”選項,屏幕上出現(xiàn)如圖8-8所示對話框。圖8-8建立新文件保存該空白的文件,單擊菜單上的“File”,在下拉菜單中選中“SaveAs”選項單擊,屏幕如圖8-9所示。在“文件名”欄右側(cè)的編輯框中,鍵入欲使用的文件名,同時,必須鍵入正確的擴展名。如果用C語言編寫程序,則擴展名為(.c);如果用匯編語言編寫程序,則擴展名必須為(.asm)。然后,單擊“保存”按鈕。圖8-9保存文件

(6)回到編輯界面后,單擊“Target1”前面的“+”號,然后在“SourceGroup1”上單擊右鍵,彈出如圖8-10所示的菜單。圖8-10添加源文件菜單在彈出的菜單上單擊“AddFiletoGroup‘SourceGroup1’”選項,屏幕如圖8-11所示。圖8-11添加源文件到工作組選中Text1.c,然后單擊“Add”按鈕,出現(xiàn)如圖8-12所示屏幕。

注意到“SourceGroup1”文件夾中多了一個子項“Text1.c”了嗎?子項的多少與所增加的源程序的多少相同。圖8-12完成文件到工作組的添加

(7)然后,就可以輸入如下程序,進行C51語言的編程了。

#include<reg52.h>

//包含文件

#include<stdio.h>

voidmain(void)

//主函數(shù)

{

SCON=0x52;

TMOD=0x20;

TH1=0xf3;

TR1=1;

//此行及以上3行為

PRINTF函數(shù)所必須

printf("HelloIamKEIL.\n");

//打印程序執(zhí)行的信息

printf("Iwillbeyourfriend.\n");

while(1);

}圖8-12完成文件到工作組的添加

(8)在圖8-12中,單擊“Project”菜單,再在下拉菜單中單擊“BuiltTarget”選項(或者使用快捷鍵F7),編譯成功后,再單擊“Project”菜單,在下拉菜單中單擊“Start/StopDebugSession”(或者使用快捷鍵Ctrl+F5),屏幕如圖8-13所示。圖8-13編譯工程

(9)調(diào)試程序。在圖8-13中,單擊“Debug”菜單,在下拉菜單中單擊“Go”選項(或者使用快捷鍵F5);然后再單擊“Debug”菜單,在下拉菜單中單擊“StopRunning”選項(或者使用快捷鍵Esc);單擊“View”菜單,再在下拉菜單中單擊“SerialWindows#1”選項,就可以看到程序運行后的結(jié)果,其結(jié)果如圖8-14所示。圖8-14程序調(diào)試完成

2.程序設計基本規(guī)范

編程規(guī)范只是一個規(guī)范,也可以不遵守,但是要做一個有良好編程風格的程序員,就一定要遵守編程規(guī)范,不僅方便自己以后的閱讀,也方便與其他程序員的交流。要做到這一點,程序員應遵循一定的規(guī)范并貫穿程序的始終。首要考慮的是程序的可行性、可讀性、可移植性、可維護性及可測試性,這是總則。

1)頭文件

一個C源文件配置一個h頭文件,或者整個項目的C文件配置一個h頭文件,而一般采用整個項目的C文件配置一個h頭文件的方法。頭文件應該按固定的順序編寫,首先使用?#include包含語句編寫本頭文件中需要包含的其他頭文件,其次聲明函數(shù)原型,接著定義用到的數(shù)據(jù)常量。定義數(shù)據(jù)常量使用?#define語句,并且使用?#ifndef/#define/#endif宏來防止重復定義,方便各模塊之間相互調(diào)用。在每個文件的開頭寫清楚這個文件歸屬哪個項目里的哪個模塊,是在什么編譯環(huán)境下編譯的,編程者(或修改者)和編程日期。值得注意的是,一定不要忘了編程日期,因為以后再看文件時,會知道大概是什么時候編寫的,有些什么功能,并且可以知道類似模塊之間的差異。對于一些固定的常量如圓周率PI或者常需要在調(diào)試時修改的參數(shù)最好用?#define定義,但要注意宏定義只是簡單的替換,因此有些括號不可少。

2)變量命名

變量的命名應該能夠反映變量的數(shù)據(jù)類型和含義,最好能做到見名知意。命名必須具有一定的實際意義。例如:

常量的命名:全部用大寫。

變量的命名:變量名加前綴,前綴反映變量的數(shù)據(jù)類型,用小寫;反映變量意義的第一個字母大寫,其他小寫。

函數(shù)的命名:函數(shù)名首字大寫,若包含有兩個單詞的,則每個單詞首字母大寫。函數(shù)原型說明包括引用外部函數(shù)及內(nèi)部函數(shù),外部引用必須在右側(cè)注明函數(shù)來源(模塊名及文件名),內(nèi)部函數(shù)只要注釋其定義文件名。

3)幾條好的書寫規(guī)范

(1)書寫代碼時要注意括號對齊,固定縮進。一個{}各占一行,根據(jù)個人習慣,縮進4個字符,應該還是比較合適的。if/for/while/do等語句各占一行,執(zhí)行語句不得緊跟其后。無論執(zhí)行語句多少都要加{},千萬不要寫成如下格式:

for(i=0;i<100;i++){fun1();fun2();}

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

fun1();

fun2();

}

而應該寫成:

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

{

fun1();

fun2();

}

(2)一行只實現(xiàn)一個功能,比如:

a=2;b=3;c=4;

宜改成:

a=2;

b=3;

c=4;

(3)重要難懂的代碼要寫注釋,每個函數(shù)要寫注釋,每個全局變量要寫注釋,一些局部變量也要寫注釋。注釋寫在代碼的上方或者右方,千萬不要寫在下方。

(4)對各運算符的優(yōu)先級有所了解,記不清沒關系,加括號就是了,不要自作聰明說自己記得很牢。

(5)不管有沒有無效分支,switch函數(shù)一定要default這個分支。一來讓閱讀者知道程序員并沒有遺忘default,并且防止程序運行過程中出現(xiàn)的意外(健壯性)。

(6)函數(shù)的參數(shù)和返回值沒有的話最好使用void。

(7)goto語句。從匯編轉(zhuǎn)型成C的人很喜歡用goto,但goto是C語言的大忌。但是老實說,程序出錯是程序員自己造成的,不是goto的過錯;最好只在一種情況下使用goto語句,即從多層循環(huán)體中跳出時。

(8)指針是C語言的精華,但是在C51中少用為妙。一來有時反而要花費更多的空間,二來在對片外數(shù)據(jù)進行操作時會出錯(可能是時序的問題)。

9)當項目比較大時,最好分模塊編程,一個模塊一個程序,既方便修改,也便于重用和閱讀。

(10)程序應該能方便地進行測試,其實這也與編程的思維有關。程序的編程方式一般有3種:一種是自上而下先整體再局部;一種是自下而上先局部再整體;還有一種是結(jié)合兩者往中間湊。通常情況下,可以先大概規(guī)劃一下整個編程,然后一個模塊一個模塊獨立編程,每個模塊調(diào)試成功再拼湊在一塊調(diào)試。另外,如果程序不大,可以用一個文件直接編定;如果程序很大,宜采用自上而下的方式;但更多的是那種處在中間的情況,宜采用自下而上或者結(jié)合的方式。

4)編輯風格

(1)縮進??s進以Tab為單位,一個Tab為4個空格大小。預處理語句、全局數(shù)據(jù)、函數(shù)原型、標題、附加說明、函數(shù)說明、標號等均頂格書寫。語句塊的“{”“}”配對對齊,并與其前一行對齊。

(2)空格。數(shù)據(jù)和函數(shù)在其類型、修飾名稱之間適當留空格并依據(jù)情況對齊。關鍵字原則上空一格,如:if(...)等,運算符的空格規(guī)定如下:“->”、“[”、“]”、“++”、“-”、“~”、“!”、“+”、“-”(指正負號),“&”(取址或引用)、“*”(指使用指針時)等幾個運算符兩邊不空格(其中單目運算符系指與操作數(shù)相連的一邊),其他運算符(包括大多數(shù)二目運算符和三目運算符“?:”兩邊均空一格,“(”、“)”運算符在其內(nèi)側(cè)空一格,在作函數(shù)定義時還可依據(jù)情況多空或不空格來對齊,但在函數(shù)實現(xiàn)時可以不用?!?”運算符只在其后空一格,需對齊時也可不空或多空格,對語句行后加的注釋應用適當空格與語句隔開并盡可能對齊。

(3)對齊。原則上關系密切的行應對齊,對齊包括類型、修飾、名稱、參數(shù)等各部分對齊。每一行的長度不應超過屏幕太多,必要時適當換行,換行時盡可能在“,”處或運算符處,換行后最好以運算符打頭,并且以下各行均以該語句首行縮進,但該語句仍以首行的縮進為準,即如其下一行為“{”,應與首行對齊。

(4)空行。程序文件結(jié)構(gòu)各部分之間空兩行,若不必要也可只空一行,各函數(shù)實現(xiàn)之間一般空兩行。

(5)修改。版本封存以后的修改一定要將老語句用?/**/?封閉,不能自行刪除或修改,并要在文件及函數(shù)的修改記錄中加以記錄。

(6)形參。在定義函數(shù)時,在函數(shù)名后面括號中直接進行形式參數(shù)說明,不再另行說明。

8.2采用C51程序的設計實例

8.2.18×8點陣LED顯示屏的設計

1.設計要求

在8?×?8點陣LED上顯示柱形,讓其先從左到右平滑移動3次,其次從右到左平滑移動3次,再次從上到下平滑移動3次,最后從下到上平滑移動3次,如此循環(huán)下去。

2.電路原理圖

電路原理圖如圖8-15所示。圖8-158×8點陣LED顯示原理圖

3.硬件電路連線

(1)把“單片機系統(tǒng)”區(qū)域中的P1端口用8芯排線連接到“點陣模塊”區(qū)域中的“DR1~DR8”端口上。

(2)把“單片機系統(tǒng)”區(qū)域中的P3端口用8芯排線連接到“點陣模塊”區(qū)域中的“DC1~DC8”端口上。

4.程序設計內(nèi)容

8×8點陣共需要64個發(fā)光二極管,且每個發(fā)光二極管是放置在行線和列線的交叉點上。當對應的某一列置1電平,某一行置0電平,則相應的二極管就亮。因此要實現(xiàn)一根柱形的亮法,對應的一列為一根豎柱,或者對應的一行為一根橫柱,則實現(xiàn)柱形的亮法如下

所述:

一根豎柱:對應的列置1,而行則采用掃描的方法來實現(xiàn)。

一根橫柱:對應的行置0,而列則采用掃描的方法來實現(xiàn)。

5.C語言源程序

#include<AT89S51.H>

//定義字形字位碼

unsignedcharcodetaba[]={0xfe,0xfd,0xfb,0xf7,0xef,

0xdf,0xbf,0x7f};

unsignedcharcodetabb[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

voiddelay(void)

{

unsignedchari,j;

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

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

}

voiddelay1(void)

{

unsignedchari,j,k;

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

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

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

}

voidmain(void)

{

unsignedchari,j;

while(1)

{

for(j=0;j<3;j++)

//fromlefttoright3time

{

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

{

P3=taba[i];

P1=0xff;

delay1();

}

}

for(j=0;j<3;j++)

//fromtoptobottom3time

{

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

{

P3=0x00;

P1=tabb[7-i];

delay1();

}

}for(j=0;j<3;j++)

//fromtoptobottom3time

{

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

{

P3=0x00;

P1=tabb[7-i];

delay1();

}

}for(j=0;j<3;j++)

//frombottomtotop3time

{

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

{

P3=0x00;

P1=tabb[i];

delay1();

}

}

}

}8.2.2數(shù)字電壓表的設計

1.設計要求

利用單片機AT89S51與ADC0809設計一個數(shù)字電壓表,能夠測量0~5V之間的直流電壓值,4位數(shù)碼顯示,但要求使用的元器件數(shù)目最少。

2.電路原理圖

數(shù)字電壓表的原理圖如圖8-16所示。圖8-16數(shù)字電壓表電路原理圖

3.系統(tǒng)板上硬件連線

(1)把“單片機系統(tǒng)”區(qū)域中的P1.0~P1.7與“動態(tài)數(shù)碼顯示”區(qū)域中的a、b、c、d、e、f、g、dp端口用8芯排線連接。

(2)把“單片機系統(tǒng)”區(qū)域中的P2.0~P2.3與“動態(tài)數(shù)碼顯示”區(qū)域中的S1、S2、S3、S4端口用8芯排線連接。

(3)把“單片機系統(tǒng)”區(qū)域中的P3.0與“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的START端子用導線相連接。

(4)把“單片機系統(tǒng)”區(qū)域中的P3.1與“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的ENABLE端子用導線相連接。

(5)把“單片機系統(tǒng)”區(qū)域中的P3.2與“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的EOC端子用導線相連接。

(6)把“單片機系統(tǒng)”區(qū)域中的P3.3與“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的CLOCK端子用導線相連接。

(7)把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的ADDA、ADDB、ADDC端子用導線連接到“電源模塊”區(qū)域中的GND端子上。

(8)把“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的IN0端子用導線連接到“三路可調(diào)電壓模塊”區(qū)域中的VR1端子上。

(9)把“單片機系統(tǒng)”區(qū)域中的P0.0~P0.7用8芯排線連接到“模數(shù)轉(zhuǎn)換模塊”區(qū)域中的2-1、2-2、2-3、2-4、2-5、2-6、2-7、2-8端子上。

4.程序設計內(nèi)容

(1)由于ADC0809

溫馨提示

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

評論

0/150

提交評論