版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第3章單片機(jī)C語言編程技術(shù)3.1FranklinC51編譯器簡介3.2C51數(shù)據(jù)的存儲(chǔ)類型3.3MCS-51單片機(jī)的C51定義3.4C51函數(shù)及功能3.5單片機(jī)C語言程序設(shè)計(jì)3.6小結(jié)習(xí)題與思考題3.1FranklinC51編譯器簡介3.1.1C51編譯器為C語言在MCS-51單片機(jī)上提供編程的系統(tǒng)稱為C語言編譯器,簡稱C51,這種編程工作最早始于1985年?,F(xiàn)今已有眾多公司的C51編譯器產(chǎn)品在使用,但并不是所有的C51都會(huì)產(chǎn)生能發(fā)揮MCS-51單片機(jī)特點(diǎn)的有效代碼。下面簡要介紹幾種典型的C51編譯器。
(1)?Avocet:可產(chǎn)生一個(gè)匯編語言文件,編譯較快,軟件包包括編譯器、匯編器、連接器等。
(2)?Bso/Tasking:軟件格式符合IntelOML-51和IntelHex標(biāo)準(zhǔn),它的C編譯器支持內(nèi)置函數(shù)使用51單片機(jī)指令;它的匯編器與Intel匯編器兼容。
(3)?Achimedes:是支持分組開關(guān)的編譯器,與ANSI兼容。程序需要一個(gè)較復(fù)雜的連接程序控制文件支持,才能運(yùn)行。
(4)?Franklin:支持浮點(diǎn)、長整數(shù)、重入和遞歸,可產(chǎn)生最少的代碼。不提供庫源代碼,僅產(chǎn)生混合代碼,不生成匯編代碼,只能修改后匯編。如果使用匯編語言,應(yīng)分開編程,然后手工連接。
以上幾種C51編譯器在用于單片機(jī)的C語言編程時(shí),使用性能方面各有不同。比較它們的優(yōu)劣時(shí),常常采用如下一些指標(biāo):
●編譯器對(duì)浮點(diǎn)數(shù)、長整數(shù)的算術(shù)支持;
●生成代碼的大小,因單片機(jī)存儲(chǔ)容量有限,自然是越小越好;
●開發(fā)速度是否較快,開發(fā)是否方便;
●是否有浮點(diǎn)庫(浮點(diǎn)庫體現(xiàn)編譯器的價(jià)值),等等。對(duì)比以上各種編譯器,F(xiàn)ranklinC51的性能最優(yōu),它產(chǎn)生的目標(biāo)代碼占存儲(chǔ)空間少,運(yùn)行速度快,代碼緊湊且使用方便,符合C語言的ANSI標(biāo)準(zhǔn);生成的代碼不僅遵循Intel目標(biāo)文件,而且還能與PL/M51語言目標(biāo)代碼、A51匯編語言混用。Achimedes的性能和資料較完善,其次是Bso/Tasking和Avocet。本書以介紹FranklinC51為主,書中凡提到C51,均指FranklinC51編譯器。3.1.2C51一般格式
C51程序由一個(gè)或多個(gè)函數(shù)構(gòu)成,是一個(gè)函數(shù)定義的集合。在這個(gè)集合中,必定有一個(gè)名為main()的主函數(shù)。主函數(shù)提供了程序的入口,主函數(shù)中所有語句執(zhí)行完畢,程序自行結(jié)束。通常C51程序還有其它的函數(shù)供主函數(shù)main()在執(zhí)行中調(diào)用,其它函數(shù)的排列順序與程序執(zhí)行無關(guān),程序執(zhí)行從主函數(shù)main()開始,又在主函數(shù)main()中結(jié)束。C51程序同一般的C程序在結(jié)構(gòu)上沒有區(qū)別。
C51程序的編程規(guī)則如下:
(1)函數(shù)是C51程序的基本單位,一個(gè)C51程序至少有一個(gè)主函數(shù)main(),也可以由一個(gè)主函數(shù)main()和若干個(gè)其它函數(shù)構(gòu)成。若干其它函數(shù)受主函數(shù)調(diào)用,被調(diào)用的函數(shù)既可以是編譯器提供的庫函數(shù),也可以是用戶自己根據(jù)需要設(shè)定編制的函數(shù)。
(2)一個(gè)函數(shù)由函數(shù)說明部分和函數(shù)體兩部分組成。
(3)函數(shù)說明部分由函數(shù)名、函數(shù)類型、函數(shù)屬性、函數(shù)參數(shù)名和形式參數(shù)類型組成,其中允許沒有函數(shù)參數(shù),函數(shù)名后面必須有1個(gè)圓括號(hào),括號(hào)內(nèi)就是可有可無的形式參數(shù)表。
(4)函數(shù)體是用大括號(hào){}圍起來的部分。大括號(hào)內(nèi)有兩部分內(nèi)容:一部分是變量及變量的定義;另一部分是由若干語句組成的執(zhí)行部分。如果一個(gè)函數(shù)內(nèi)有多個(gè)大括號(hào),則最外層的一對(duì)大括號(hào)為函數(shù)體的范圍。有的函數(shù)體既有變量定義部分,又有執(zhí)行部分;有的函數(shù)體僅有執(zhí)行部分無變量定義部分;有的函數(shù)這兩部分都沒有。
(5)語句的組成規(guī)則為:
●每個(gè)變量必須先定義后使用;
●變量名由英文字母組成,英文字母要區(qū)分大小寫,大小寫不同則變量名不同;
●書寫格式自由,一行可以寫多個(gè)語句,一個(gè)語句也可以寫成多行,但每條語句必須以“;”結(jié)尾;
●分號(hào)是C語言的必須組成部分,每個(gè)語句和數(shù)據(jù)在定義的最后必須有一個(gè)分號(hào),程序的最后一個(gè)語句也應(yīng)有分號(hào)。
(6)?C語言對(duì)I/O操作實(shí)現(xiàn)了“函數(shù)化”,分別調(diào)用庫函數(shù)scanf和printf等函數(shù)完成,無專門的輸入/輸出語句。
(7)?C51的注釋用/*…*/表示,有了注釋,閱讀程序更方便。C51程序結(jié)構(gòu)如下:全局變量說明 /*可被各函數(shù)引用*/main() /*主函數(shù)*/{ /*函數(shù)體開始*/局部變量說明 /*限于在本函數(shù)內(nèi)使用*/執(zhí)行語句(包括調(diào)用其它函數(shù)的語句) } /*主函數(shù)的函數(shù)體結(jié)束*/function1(形式參數(shù)表) /*可被調(diào)用的一個(gè)函數(shù)*/形式參數(shù)說明 { /*函數(shù)1的函數(shù)體開始*/局部變量說明 執(zhí)行語句(包括調(diào)用其它函數(shù)的語句) } /*函數(shù)1的函數(shù)體結(jié)束*/functionn(形式參數(shù)表) /*可被調(diào)用的第n個(gè)函數(shù)*/ /*格式同函數(shù)1,從“{”開始,到“}”結(jié)束*/3.1.3FranklinC51編譯器支持的數(shù)據(jù)類型具有一定格式的數(shù)字或數(shù)值叫做數(shù)據(jù);數(shù)據(jù)的不同格式被稱為數(shù)據(jù)類型,數(shù)據(jù)的位數(shù)稱為數(shù)據(jù)長度。
FranklinC51支持的數(shù)據(jù)類型、長度和值域(取值范圍)如表3-1所示,其中位型(bit)數(shù)據(jù)只有1種,取值0或1。字符型(char)、整型(int)、長整型(long)數(shù)據(jù)各有無符號(hào)(unsigned)和有符號(hào)(signed)兩類。一般情況下選用無符號(hào)類數(shù)據(jù),這樣可以免去編譯器對(duì)符號(hào)位的檢測處理,使得生成的程序比有符號(hào)類短得多。浮點(diǎn)型數(shù)據(jù)長度為32位,占4個(gè)字節(jié),值域的有效數(shù)字為6位。雙精度浮點(diǎn)型數(shù)據(jù)長度為64位,占8個(gè)字節(jié),值域的有效數(shù)字為10位。指針型數(shù)據(jù)有3類,分別為1~3字節(jié)指針,其中1字節(jié)指針又有data、idata和pdata3種,每一種適用于不同的用途。數(shù)據(jù)類型定義為data或idata,表明指針指向片內(nèi)數(shù)據(jù)RAM(地址為1字節(jié));如果定義成pdata,指針指向片外數(shù)據(jù)RAM,但必須是@Ri(i=0,1)間址,這種情況下片外數(shù)據(jù)RAM的16位地址中的低8位依舊是1字節(jié)。當(dāng)數(shù)據(jù)類型定義成code時(shí),表示指針指向64KB的程序ROM16位地址;當(dāng)定義成xdata時(shí),指向用@DPTR間址的片外64KB數(shù)據(jù)RAM,這時(shí)的地址顯然是2字節(jié)16位。指針型數(shù)據(jù)的第3類是通用指針類型,占3個(gè)字節(jié)。這種情況適用于任何存儲(chǔ)器的任何存儲(chǔ)空間,3字節(jié)指針長度的第1字節(jié)表示不同的存儲(chǔ)器,第2、3字節(jié)表示存儲(chǔ)器地址或地址偏移量的高、低8位。表3-2給出了第1字節(jié)與存儲(chǔ)器類型之間的關(guān)系。例如有1個(gè)指針變量(設(shè)該變量的名字為Var)的值為0342A0H,第1字節(jié)編碼03H表示數(shù)據(jù)類型為pdata,用@Ri尋址片外數(shù)據(jù)RAM42A0H單元,編程時(shí)可使用賦值語句實(shí)現(xiàn)。在編譯程序時(shí),C51具有自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型的能力,例如將位型變量賦值給一個(gè)字符變量時(shí),位型將自動(dòng)轉(zhuǎn)換成字符型,有符號(hào)變量的符號(hào)也能自動(dòng)處理;當(dāng)運(yùn)算符兩邊的變量不同類型時(shí),C51會(huì)將長度低的類型自動(dòng)轉(zhuǎn)換成長度高的類型。
C51支持的數(shù)據(jù)有常量和變量兩類。常量數(shù)據(jù)是程序執(zhí)行過程中其值不變的量,在C語言中用“0×”表示。常見的常量有二進(jìn)制數(shù)、十進(jìn)制數(shù)、十六進(jìn)制數(shù)、ASCII字符等。常量可分為數(shù)值型和符號(hào)型兩種。對(duì)于符號(hào)型常量,需要宏定義指令#define進(jìn)行定義,定義過程同于匯編語言中的EQU偽指令,例如: #defineMASK43.7此后程序中出現(xiàn)MASK,編譯程序?qū)⑵渥g為43.7,對(duì)應(yīng)的匯編語言偽指令為
MASKEQU43.7程序運(yùn)行中其值可以改變的量叫做變量。變量由變量名和變量值組成。變量名的功能之一是表示存儲(chǔ)單元的符號(hào)地址,變量值是該單元存放的內(nèi)容。在C51中,只需在數(shù)據(jù)類型后面出現(xiàn)變量名就能定義,同于匯編語言中的DB、DW、DD等變量定義偽指令。例如C51程序:#defineMASK43.7 /*符號(hào)常量MASK=43.7*/main() /*主函數(shù)*/{ /*函數(shù)體開始*/intvarible,result;
/*定義了兩個(gè)整型變量varible和result*/variable=30;
/*變量variable的值是30*/result=variable*MASK;
/*變量result=30×43.7=1311*/printf(“result=%d\n”,result); /*輸出"result=1311"*/}習(xí)慣上符號(hào)常量名用大寫字母;變量名用小寫字母。3.2C51數(shù)據(jù)的存儲(chǔ)類型
1.數(shù)據(jù)的傳送數(shù)據(jù)的傳送既可以用匯編指令,又可以用C賦值語句來完成,如表3-3所示。
2.存儲(chǔ)類型
FranklinC51所定義的任何數(shù)據(jù)類型必定以某種方式存放在單片機(jī)的某一存儲(chǔ)區(qū)內(nèi),這種存儲(chǔ)方式又稱為存儲(chǔ)類型。由此可知,在定義變量類型時(shí),還必須定義其存儲(chǔ)類型。表3-4給出了C51數(shù)據(jù)的存儲(chǔ)類型與51單片機(jī)存儲(chǔ)空間之間的關(guān)系。如果用data、bdata存儲(chǔ)類型定義常量和變量,C51編譯器會(huì)把它們定位在片內(nèi)RAM中;如果用idata存儲(chǔ)類型定義常量和變量,C51編譯器會(huì)將它們定位到片內(nèi)RAM位尋址區(qū)。類似地,如果使用的是pdata/xdata/code,那么分別定位到片外RAM(256B)/片外RAM(64KB)/程序ROM。定義變量的各種數(shù)據(jù)存儲(chǔ)類型時(shí),應(yīng)當(dāng)將經(jīng)常使用的變量置于片內(nèi)數(shù)據(jù)RAM中,這是因?yàn)樵L問片內(nèi)RAM的速度比訪問片外RAM快得多。變量存儲(chǔ)類型定義舉例如下:chardatavarl;
/*字符變量varl的存儲(chǔ)類型data,定位于片內(nèi)RAM*/bitbdataMuck;
/*位變量Muck的存儲(chǔ)類型bdata定位于片內(nèi)尋址區(qū)*/unsignedcharxdatavector[8][2][2];/*無符號(hào)字符三維變量vector定義成xdata,C51將它定位到片外64KBRAM內(nèi),占8×2×2=32個(gè)字節(jié)存儲(chǔ)空間,用于存放三維變量數(shù)組*/
3.存儲(chǔ)模式如果用戶不對(duì)常量和變量定義存儲(chǔ)類型,C51編譯器將會(huì)默認(rèn)其存儲(chǔ)類型。當(dāng)存儲(chǔ)模式不同時(shí),默認(rèn)的存儲(chǔ)類型也不同。存儲(chǔ)模式有3種(如表3-5所示),由編程人員在預(yù)處理命令中設(shè)置。
C51的一個(gè)標(biāo)準(zhǔn)特征是在固定的存儲(chǔ)區(qū)內(nèi)完成變量傳遞。SMALL、COMPACT、LARGE各有自己的變量存放和傳遞區(qū)間,但是C51也支持混合模式,比如在LARGE模式下,生成的程序也可以將一些函數(shù)放到SMALL模式中,從而使執(zhí)行速度更快。存儲(chǔ)模式定義舉例如下:#pragmalarge; /*預(yù)處理命令,置于程序之首,用于將程序中的未定義存儲(chǔ)類型的變量和參數(shù)傳遞區(qū)默認(rèn)為xdata*/
C51編譯命令C51ROUT.CCOMPACT的功能同上,僅默認(rèn)為pdata。3.3MCS-51單片機(jī)的C51定義3.3.1特殊功能寄存器SFR的C51定義
FranklinC51為了能直接訪問SFR,引入了關(guān)鍵字“sfr”,用于給SFR賦予字節(jié)地址。例如P1口的字節(jié)地址為90H,在單片機(jī)C語言編程中,必須首先用
sfrP1=0×90H/*給P1口賦予地址90H*/定義地址,后面的程序就可以直接使用寄存器名P1。這是與單片機(jī)匯編語言編程不同的地方。在匯編編程中,P1可以直接用來表示地址,無須事先定義。指令MOVA,P1和指令MOVA,90H功能相同,都能直接使用。這種定義方法有3個(gè)問題需要說明:
(1)給每一個(gè)SFR賦予的地址只能使用它們自己的字節(jié)地址。例如給P1口賦予地址只能賦予90H,不能使用E0H,因?yàn)镋0H是累加器A的字節(jié)地址。
(2)?SFR的名字用大寫字母定義。
(3)這種定義方法與標(biāo)準(zhǔn)C語言不兼容,僅適用于單片機(jī)C語言編程。3.3.2P0~P3口及片外擴(kuò)展硬件I/O口的C51定義
FranklinC51對(duì)并行I/O接口P0~P3口的定義如下:
sfrP0=0×80; /*定義P0口地址80H*/ sfrP1=0×90; /*定義P1口地址90H*/ sfrP2=0×A0;
/*定義P2口地址A0H*/ sfrP3=0×B0;
/*定義P3口地址B0H*/
FranklinC51對(duì)片外擴(kuò)展硬件I/O的定義用包含語句#include<absacc.h>建立頭文件absacc.h,用#define語句定義其硬件譯碼地址。如: #include<absacc.h> #definePORTAXBYTE[0×20f4] /*將PORTA定義為片外I/O端口,長度為8位,地址為20F4H*/頭文件absacc.h中的函數(shù)有:CBYTE (訪問code區(qū),字符型,char)DBYTE (訪問data區(qū),字符型)PBYTE (訪問pdata區(qū)或I/O口,字符型)XBYTE (訪問xdata區(qū)或I/O口,字符型)CWORD (訪問code區(qū),整型,int)DWORD (訪問data區(qū),整型)PWORD (訪問pdata區(qū)或I/O口,整型)XWORD (訪問xdata區(qū)或I/O口,整型)3.3.3位尋址變量的C51定義
FranklinC51編譯器對(duì)位尋址變量的定義方法有3種。第一種,支持“bit”數(shù)據(jù)類型,例如:
bitlock; /*將lock定義為位變量,位地址由C51安排在可位尋址的bdata區(qū)*/ bitnumber_pointer; /*將number_pointer定義為位變量*/第二種,先定義變量的數(shù)據(jù)類型,再用“sbit”定義其中的位,例如:
bdataintibase; /*將ibase定義成bdata整型變量*/ sbitmy9=ibase^9; /*my9定義為ibase的第9位*/ sbitmy14=ibase^14;/*my14定義為ibase的第14位*/第三種,使用頭文件reg51.h和sbit定義符,這種方法用于定義特殊功能寄存器SFR中沒有位名字的可尋址位。頭文件reg51.h由C51建立,該文件中不僅對(duì)所有可尋址位進(jìn)行了sbit定義,還對(duì)所有SFR進(jìn)行了sfr定義。例如:#include<reg51.h>sbitP0_3=P0^3;
/*定義P0_3是P0口的第3位*/sbitac=ACC^7;
/*定義ac是A的第7位*/也可以在頭文件reg51.h后直接用位名,例如:#include<reg51.h>
EA=1; /*IE.7賦值為1*/EX0=1; /*IE.0賦值為0*/也可以不用頭文件reg51.h,先用sfr定義寄存器的地址,再用sbit定義位。例如:sfrPSW=0×d0;
/*定義PSW地址D0H*/sfrRS1=PSW^4;
/*定義RS1是PSW的D4位*/sfrRS0=PSW^3;
/*定義RS0是PSW的D3位*/3.3.4C51的運(yùn)算符定義
1.C51的基本算術(shù)運(yùn)算符
C51的基本算術(shù)運(yùn)算符有5種:+(加或正號(hào)),-(減或負(fù)號(hào)),*(乘),/(除),%(模運(yùn)算符,又稱求余。例如8%5是8除以5,余數(shù)為3)。它們的優(yōu)先級(jí)為:先括號(hào)內(nèi),后括號(hào)外;先乘除,后加減。
2.C51的關(guān)系運(yùn)算符
C51的關(guān)系運(yùn)算符有6種:<(小于),>(大于),<=(小于或等于),>=(大于或等于),==(相等),!=(不等于)。前4種關(guān)系運(yùn)算符的優(yōu)先級(jí)別高(彼此間優(yōu)先級(jí)相同),后兩種關(guān)系運(yùn)算符的優(yōu)先級(jí)較低(彼此間優(yōu)先級(jí)相同)。關(guān)系運(yùn)算的結(jié)果只有兩種:“真”(用“1”表示)和“假”(用“0”表示)。例如設(shè)a=5,b=4,c=3,則a>b的值為“真”,表達(dá)式的值為1。又如d=a>b>c,按運(yùn)算優(yōu)先級(jí),先算a>b,表達(dá)式的值為1;再算1>c,表達(dá)式的值為0,所以d=0。
3.C51的邏輯運(yùn)算符
C51的邏輯運(yùn)算符有3種:&&(邏輯與),||?(邏輯或),!(邏輯非)。
邏輯運(yùn)算結(jié)果只有兩個(gè):“真”(用“1”表示)和“假”(用“0”表示)。各種C51運(yùn)算符的優(yōu)先級(jí)別如圖3-1所示。圖3-1運(yùn)算優(yōu)先級(jí)比較
【例3-1】
求X>Y+Z的值,設(shè)運(yùn)算前X=3,Y=1,Z=4。先進(jìn)行算術(shù)運(yùn)算Y+Z,再進(jìn)行關(guān)系運(yùn)算“>”。因Y+Z=5,X>5結(jié)果為假(0)。
【例3-2】設(shè)X=7,則!X的值為假(0),因X=7為真。
【例3-3】
設(shè)X=3,Y=4,則X||Y為真,因X、Y為“真”,兩數(shù)邏輯或也為“真”;X&&Y為真;!X&&Y為假。
4.C51位操作運(yùn)算符
C51位操作運(yùn)算符有6種:&(按位與),|(按位或),^(按位異或),~(位取反),<<(位左移,低位補(bǔ)零),>>(位右移,高位補(bǔ)零)。
【例3-4】設(shè)X=10011110B,Y=10100101B,則X^Y的運(yùn)算過程為:X^Y的值為00111011B。
【例3-5】
設(shè)X=F0H,則X=~X的值為0FH。設(shè)X=3BH,則X=X<<2的值為11101100B,左移兩位的低位補(bǔ)0,高位移走后舍棄。
5.C51自增減運(yùn)算符
C51自增減運(yùn)算符有4種:++i(使用i前,先使i加1),--i(使用i前,先使i減1),i++(使用i后,再使i加1),i--(使用i后,再使i減1)。
【例3-6】設(shè)i值為8,則
j=++i,使用前i為8,加1后為9,則i、j值都是9;
j=i++,使用前i為8,先將8賦給j,使用后使i加1,所以i=9,j=8。
6.C51復(fù)合賦值運(yùn)算符
C51復(fù)合賦值運(yùn)算符有10種:+=,-=,*=,/=,%=,<<=,>>=,&=,^=,|=。
【例3-7】
X+=Y(jié)相當(dāng)于X=X+Y;
X-=Y(jié)相當(dāng)于X=X-Y;
X*=Y(jié)相當(dāng)于X=X*Y;
X/=Y(jié)相當(dāng)于X=X/Y;
X%=Y(jié)相當(dāng)于X=X%Y;
X<<=Y(jié)相當(dāng)于X=X<<Y;
X>>=Y(jié)相當(dāng)于X=X>>Y;
X&=Y(jié)相當(dāng)于X=X&Y;
X^=Y(jié)相當(dāng)于X=X^Y;
X|=Y(jié)相當(dāng)于X=X|Y。3.3.5C51的指針變量及運(yùn)算操作定義
1.指針和指針變量指針是指存儲(chǔ)單元的地址,變量的指針就是變量的地址。以圖3-2所示存儲(chǔ)圖為例,變量X、Y、Z是三個(gè)在程序中定義了的整型變量(匯編語言中用偽指令DB定義的變量),相應(yīng)各存儲(chǔ)單元的物理地址已經(jīng)標(biāo)明。對(duì)變量X而言,指針就是2100H。圖3-2存儲(chǔ)圖指針變量是指存放有指針內(nèi)容的變量,如存儲(chǔ)圖中的變量A,就是一種指針變量,它的存儲(chǔ)內(nèi)容2100H是變量X的地址(指針)。變量和指針變量在使用之前都需要定義,當(dāng)變量名前出現(xiàn)“*”時(shí),就是在定義指針變量。當(dāng)變量定義后,在變量名前出現(xiàn)“&”,它表示變量的地址,即指針。例如:intX、Y、Z;
/*定義整型變量X、Y、Z*/int*A;
/*定義指針變量A*/X=AB36H; /*賦值語句,變量X的內(nèi)容為AB36H*/X=0×2100; /*將地址2100H賦給變量X*/A=&X; /*將變量X的指針(即變量的地址2100H)送入A,使A的內(nèi)容為2100H*/
2.指針操作運(yùn)算符
*:既可作定義指針變量用,又可作運(yùn)算符號(hào)用。作運(yùn)算符號(hào)表示間接尋址操作。
&:取變量地址運(yùn)算符。而按位“與”的運(yùn)算符也是“&”,注意它們的區(qū)別。
【例3-8】
intx,p,q;
/*定義整型變量x、p、q*/int*A、B;
/*定義指針變量A、B*/x=AB36H; /*給變量x賦值*/A=&x; /*把變量x的地址(指針)(假設(shè)地址為
2100H)存入A*/q=*A; /*以A的內(nèi)容2100H為地址,把該單元的內(nèi)容AB36H賦給q,結(jié)果q=AB36H。q=*A功能相當(dāng)于匯編指令MOVA,@R0*/3.4C51函數(shù)及功能3.4.1函數(shù)的分類與定義
1.函數(shù)的分類
(1)從語言結(jié)構(gòu)劃分,函數(shù)分為主函數(shù)main()和普通函數(shù)兩類。
(2)從使用角度劃分,函數(shù)分為標(biāo)準(zhǔn)庫函數(shù)和用戶自定義函數(shù)兩類。
●庫函數(shù)是C編譯系統(tǒng)提供的一系列標(biāo)準(zhǔn)函數(shù),用戶可直接調(diào)用,如頭文件reg51.h等,其中一些頭文件含一系列函數(shù),要使用它們必須先用#include語句。
●用戶自定義函數(shù)是用戶按照自身需要編寫的函數(shù)。
(3)從參數(shù)形式上劃分,函數(shù)分為無參數(shù)函數(shù)、有參數(shù)函數(shù)和空函數(shù)三類。
●無參數(shù)函數(shù)調(diào)用時(shí)無須輸入?yún)?shù),也無結(jié)果返回。
●有參數(shù)函數(shù)調(diào)用時(shí)要給被調(diào)用函數(shù)提供實(shí)質(zhì)參數(shù),被調(diào)用函數(shù)運(yùn)行后產(chǎn)生的結(jié)果也要返回給調(diào)用函數(shù)使用。
●空函數(shù)是內(nèi)無語句的空白函數(shù),調(diào)用時(shí)不產(chǎn)生任何操作,這種函數(shù)用于功能備用,以便擴(kuò)充。
2.函數(shù)的定義
(1)無參數(shù)函數(shù)的定義形式:
返回值類型標(biāo)識(shí)符函數(shù)名()
{函數(shù)體語句}
無參數(shù)函數(shù)通常不帶返回值,因此標(biāo)識(shí)符可省略或用void。
(2)有參數(shù)函數(shù)的定義形式:返回值類型標(biāo)識(shí)符函數(shù)名(形式參數(shù)表)形式參數(shù)說明{函數(shù)體語句return(返回參數(shù)名)}
(3)空函數(shù)的定義形式:返回值類型說明符函數(shù)名(){}3.4.2函數(shù)的調(diào)用函數(shù)一般調(diào)用形式定義為: 函數(shù)名(實(shí)際參數(shù)表列)無參數(shù)函數(shù)不存在“實(shí)際參數(shù)表列”。有參數(shù)函數(shù)的“實(shí)際參數(shù)表列”的各參數(shù)之間用逗號(hào)隔開,主調(diào)函數(shù)與被調(diào)函數(shù)的形式參數(shù)數(shù)目應(yīng)該相等,實(shí)際參數(shù)按順序依次對(duì)應(yīng)傳遞給形式參數(shù)。函數(shù)調(diào)用有三種方式:
(1)使用函數(shù)調(diào)用語句,被調(diào)函數(shù)名作為主調(diào)函數(shù)中的一個(gè)語句。如:
print_message();/*message()是被調(diào)用函數(shù)*/
(2)被調(diào)函數(shù)作為表達(dá)式的運(yùn)算對(duì)象。如:
result=5*good(x,y)
(3)被調(diào)函數(shù)作為另一個(gè)函數(shù)的實(shí)際參數(shù)。如:
m=min(x,alpha(a,b))3.4.3函數(shù)調(diào)用條件主調(diào)函數(shù)調(diào)用被調(diào)函數(shù),必須滿足如下條件:
(1)被調(diào)函數(shù)必須已經(jīng)存在,是庫函數(shù)或用戶自定義函數(shù)。
(2)如果程序中使用了庫函數(shù),或者使用了不在同一文件中的其它用戶自定義函數(shù),那么需要在程序的開頭用#include包含語句,將所用函數(shù)信息包括到程序中來
(3)如果被調(diào)函數(shù)出現(xiàn)在主調(diào)函數(shù)之后,應(yīng)在主調(diào)函數(shù)前對(duì)被調(diào)函數(shù)的返回值類型予以說明。說明方式為: 返回值類型被調(diào)函數(shù)名(形式參列)
【例3-9】
被調(diào)函數(shù)在主調(diào)函數(shù)后,需要說明。main(){intmax(); /*被調(diào)函數(shù)說明*/intx=70,y=40,m;m=max(X,Y);}intmax(a,b); /*被調(diào)函數(shù),在主調(diào)函數(shù)之后出現(xiàn)*/inta,b;{return(a>b?a:b);}
(4)被調(diào)函數(shù)說明的語句intmax(a,b)也可以移至主調(diào)函數(shù)man()前,可不必說明,見下例。
【例3-10】intmax(a,b); /*被調(diào)函數(shù),在主調(diào)函數(shù)之前出現(xiàn)*/inta,b;{return(a>b?a:b);}main() /*主調(diào)函數(shù),函數(shù)內(nèi)無被調(diào)函數(shù)說明intmax();*/{intx=70,y=40,m;m=max(X,Y);}3.5單片機(jī)C語言程序設(shè)計(jì)3.5.1順序結(jié)構(gòu)設(shè)計(jì)
【例3-11】
完成32×50的編程。#defineSIGNCONST32 /*定義一個(gè)符號(hào)常量SIGNCONST,值為32*/main(){intvariable,mult;/*定義兩個(gè)整型變量variable和mult*/variable=50;/*給變量賦值50*/mult=variable×SIGNCONST;/*變量小寫,符號(hào)常量大寫*/printf("mult=%d\n",mult);}運(yùn)行結(jié)果mult=1600?;蛘呤褂靡韵戮幊蹋簃ain(){unsignedintxdata*a;unsignedintvariable=50;unsignedintconsta=32;unsignedintmult;a=2000H;mult=variable*eonsta;*a=mult; /*積存入2000H單元*/}
【例3-12】將攝氏溫度轉(zhuǎn)換成華氏溫度,攝氏溫度值放在內(nèi)存30H單元中,轉(zhuǎn)換后的華氏溫度放入31H單元內(nèi)。main(){charx,*degc;charcodetempt[6]={32,34,36,37,39,41};
/*設(shè)置數(shù)組*/degc=0×30;x=tempt[*degc];degc++;
/*指向下一單元,好放轉(zhuǎn)換結(jié)果*/*degc=x;}3.5.2分支結(jié)構(gòu)設(shè)計(jì)
C51分支結(jié)構(gòu)使用if語句和switch語句實(shí)現(xiàn)。
1.選擇語句if
if是一種條件選擇判定語句,C語言提供以下3種形式。
(1)?if(表達(dá)式){語句}含義:表達(dá)式為“真”時(shí)執(zhí)行語句,否則執(zhí)行下一條語句。例如:
if(x>y){c=0}當(dāng)x>y成立時(shí)執(zhí)行c=0;否則執(zhí)行下一條。
(2)?if(表達(dá)式){語句1;}else{語句2;}含義:表達(dá)式為“真”時(shí),執(zhí)行語句1;否則執(zhí)行語句2。
(3)?if(表達(dá)式1){語句1;}elseif(表達(dá)式2){語句2;}elseif(表達(dá)式3){語句3;}……elseif(表達(dá)式n){語句n;}else{語句n+1;}含義:表達(dá)式1為“真”時(shí),執(zhí)行語句1;否則看表達(dá)式2。如果表達(dá)式2為“真”,執(zhí)行語句2,否則看表達(dá)式3?!?,直至看表達(dá)式n。如果表達(dá)式n為“真”,執(zhí)行語句n,否則執(zhí)行語句n+1。
if語句允許嵌套。
2.判斷語句switch/caseswitch(表達(dá)式){}case常量表達(dá)式1;{語句1;}break;case常量表達(dá)式2;{語句2;}break;……case常量表達(dá)式n;{語句n;}break;default;{語句n+1;}含義:當(dāng)switch后面括號(hào)中表達(dá)式值與某個(gè)case后面常量表達(dá)式的值相等時(shí),執(zhí)行該常量表達(dá)式后面的語句。執(zhí)行完后遇break退出switch語句。如果switch后面括號(hào)中表達(dá)式的值與所有的case后常量表達(dá)式的值對(duì)不上,那么程序執(zhí)行default后面的語句。
【例3-13】設(shè)x位于片內(nèi)RAM30H單元,y位于片內(nèi)RAM40H單元。編程實(shí)現(xiàn)
y=解:main(){ charx,*R0,*y;
R0=0×30;
y=0×40;
{
x=*R0;
if(x<0) *y=1 if(x==0) *y=x/2 if(x>0) *y=x }}
【例3-14】采用遞歸調(diào)用求正數(shù)n的階乘程序如下:intfactorial(n)intn;{intresult;if(n==0) result=1,else result=n*factorial(n--1);
result(result);}main(){intx;for(x=0;x<b;++x)printf("%d!=%d\n",x,factorial(x));}程序運(yùn)行結(jié)果:0!=11!=12!=23!=34!=245!=120
【例3-15】
使用switch語句的分支程序。switch(n){case0;vr0();break;case1;vr1();break;case2;vr2();break;casemvrm();break;default;break;}相應(yīng)匯編分支程序?yàn)椋?/p>
MOVA,#data MOVDPTR,#TABLE JMP@A+DPTR
;AJMP是2字節(jié)指令,A中內(nèi)容為偶數(shù)TABLE: AJMPV0 ;A=0轉(zhuǎn)
AJMPV1 ;A=2轉(zhuǎn)
AJMPV2 AJMPVn3.5.3循環(huán)結(jié)構(gòu)設(shè)計(jì)
C51提供的循環(huán)語句有三種:while語句、do_while語句和for語句。
1.while語句
while語句的格式為:while(表達(dá)式){語句/*循環(huán)體*/}表達(dá)式是能夠繼續(xù)循環(huán)的條件,用大括號(hào)括起來的語句是循環(huán)體。如果表達(dá)式的值為“真”,就重復(fù)執(zhí)行循環(huán)體語句;如果表達(dá)式的值為“假”,則退出循環(huán)體,執(zhí)行下一條語句。while語句的流程圖如圖3-3所示。圖3-3while語句流程圖
【例3-16】討論下述語句的功能。while((P0&0×02)==0){}
while后面的表達(dá)式是P0和00000010B按位與,如果P0.2為0則結(jié)果為0,循環(huán)條件成立,執(zhí)行循環(huán)體內(nèi)語句。但本例循環(huán)體內(nèi)無語句,因此什么也不執(zhí)行,繼續(xù)將P0.2位是否為0測試下去。只有當(dāng)P0.2=1時(shí)才離開循環(huán)。該語句的功能可用于不斷地測試P0.2的狀態(tài),只要P0.2為低電平,測試將繼續(xù);只有P2.0變?yōu)楦唠娖?,才停止測試。
【例3-17】
求兩個(gè)數(shù)的最大公約數(shù)。#include<stdio.h>intgcd(x,y)intx,y{ inttemper while(y!=0) { temper=x%y;
x=y;
y=temper;
} return(x);}main(){intresult,a=12,b=8;
printf("a=%
d,b=%
d",a,b);
result=gcd(a,b);
printf("Thegcdof%dand%dis%d\n",a,b,result);}運(yùn)行結(jié)果:a=12b=8Thegcdof12and8is4
2.do_while語句do_while語句的格式為:do{語句;/*循環(huán)體*/}while(表達(dá)式)
do_while語句用于先執(zhí)行循環(huán)體語句,再由while后面的表達(dá)式“真”、“假”判斷是否要循環(huán),其示意圖如圖3-4所示。圖3-4do_while語句流程圖
【例3-18】
編程計(jì)算0+1+2+…+10。intsum=0,x;do{sum+=x;
x++;}while(x<=10)
3.for語句
for語句的格式為:
for(表達(dá)式1;表達(dá)式2;表達(dá)式3)
{語句;/*循環(huán)體*/}
for語句的執(zhí)行步驟如下:
(1)對(duì)表達(dá)式進(jìn)行求解,進(jìn)行初始化。
(2)求解表達(dá)式2,判斷表達(dá)式是否滿足給定循環(huán)條件。如果滿足(表達(dá)式2的值為“真”),則進(jìn)行第(3)步;如果不滿足,則進(jìn)行第(5)步。
(3)執(zhí)行for語句中的循環(huán)體語句,執(zhí)行完后,求解表達(dá)式3,按表達(dá)式3修改變量。
(4)轉(zhuǎn)到第(2)步去循環(huán)執(zhí)行。
(5)退出循環(huán),執(zhí)行for語句的下一條語句。
3個(gè)表達(dá)式可省1個(gè)、2個(gè)或3個(gè),但分號(hào)不能省。例如,for(x=10;;x++){語句}表明從10開始進(jìn)入死循環(huán);for(;x>50;){語句}同于while(x>50);f(!!){語句},表明進(jìn)入死循環(huán)。圖3-5是for語句的流程圖。圖3-5for語句流程圖
【例3-19】
for語句中表達(dá)式缺省。
(1)表達(dá)式1缺省。表達(dá)式1用于給變量賦初值,缺省意味著不用初值。例如:for(;x<=50;x++){sum=sum+x;}表示從x某一值開始求和。x的初值已在前面賦給。
(2)表達(dá)式2缺省。表達(dá)式2為循環(huán)判斷條件,如果缺省表示無需判斷,循環(huán)繼續(xù)進(jìn)行。例如:
for(x=10;;x++){語句}表示從x=10開始進(jìn)入死循環(huán)。
(3)表達(dá)式1、3缺省。例如:
for(;x>%;){語句}等同于
while(x>50)
(4)表達(dá)式1、2、3全缺省,無初值、無判斷條件,表明循環(huán)無休止進(jìn)行。例如:
f(;;){語句}表示進(jìn)入死循環(huán),在編程中此條語句可用在調(diào)試中。要退出死循環(huán),可按Ctrl+C鍵。
【例3-20】延時(shí)程序。程序一,利用無循環(huán)體語句的for語句。intx=1000;for(a=0;a<x;a++);程序二,利用while后面的表達(dá)式判斷。voidmsec(unsignedinta){unsignedcharb;
while(a--){for(b=0;b<125;b++)
/*改變b上限值,可以改變延時(shí)時(shí)間*/{;}}}3.5.4C語言和匯編語言混合編程
C語言和匯編語言混合編程的首要問題是參數(shù)傳遞及其傳遞規(guī)則。一般情況下用高級(jí)語言編寫主程序,用匯編語言編寫與硬件有關(guān)的子程序。FranklinC51的編譯過程是將不同語言形式的模塊分別匯編,再連接成一個(gè)可執(zhí)行文件。
1.混合編程匯編程序中要用偽指令在經(jīng)常用到的函數(shù)處使CODE選項(xiàng)有效,確定可以再定位段的類型。被調(diào)函數(shù)要在主函數(shù)中給予說明,就需要轉(zhuǎn)換函數(shù)名,轉(zhuǎn)換表如表3-6所示。
2.參數(shù)傳遞不同的編譯器有不同的參數(shù)傳遞方法,但參數(shù)通常是通過固定的CPU寄存器傳遞給匯編程序的。FranklinC51給匯編提供了一個(gè)簡潔的接口,返回值在CPU寄存器中,入、出口參數(shù)傳遞既可以用寄存器,也可以用存儲(chǔ)單元。有時(shí)雖然也用堆棧傳遞,但8XX51堆棧深度不足,因此用得不多。
CPU寄存器最多能傳遞3個(gè)參數(shù),每個(gè)參數(shù)選擇的寄存器是固定的,如表3-7所示。參數(shù)傳遞規(guī)則能夠用以下一些語句說明:func1(intx); /*x是第一個(gè)參數(shù),在R6、R7中傳遞*/func2(inta,intb,int*c); /*a在R6、R7中傳遞,b在R4、R5中傳遞,第3個(gè)參數(shù)c在R1、R2、R3中傳遞*/如果傳遞參數(shù)的寄存器不夠用,可允許使用存儲(chǔ)器,通過指針取得參數(shù)后再傳遞。匯編程序?qū)?shù)傳遞給C程序,是通過寄存器或存儲(chǔ)器進(jìn)行的,通過寄存器傳遞的返回值如表3-8所示。參數(shù)傳遞段給出了匯編子程序所用存儲(chǔ)區(qū)。參數(shù)傳遞段的首址由名為“?函數(shù)名?BYTE”的PUBLIC符號(hào)確定。傳遞位值的PUBLIC符號(hào)為“?函數(shù)名?BIT”。函數(shù)返回值全在CPU內(nèi)。匯編子程序當(dāng)前所用寄存器組及A、B、DPTR、PSW等都有可能變化,那么調(diào)用C函數(shù)時(shí)不能使用這些不可靠的內(nèi)容。每個(gè)匯編子程序應(yīng)當(dāng)有1個(gè)單獨(dú)程序段,便于在連接/定位程序中使用覆蓋。覆蓋內(nèi)容應(yīng)包含匯編子程序的數(shù)據(jù)區(qū)。覆蓋過程是用各個(gè)子程序自己的段參量計(jì)算出函數(shù)之間的參量。匯
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五版化工危險(xiǎn)品倉庫租賃及消防設(shè)施配備協(xié)議3篇
- 2024校車司機(jī)服務(wù)滿意度調(diào)查聘用合同3篇
- 專業(yè)墻面刷涂料分包合作合同一
- 二零二五年度不銹鋼欄桿設(shè)計(jì)與安裝服務(wù)協(xié)議3篇
- 二零二五年特色街區(qū)攤位租賃經(jīng)營協(xié)議2篇
- 2025賓館客房租賃及酒店旅游咨詢服務(wù)合同范本3篇
- 二零二五年度智能機(jī)器人OEM研發(fā)與生產(chǎn)合作協(xié)議
- 二零二五版影視作品眾籌投資與分成合同3篇
- 2024版工程設(shè)計(jì)協(xié)議終止協(xié)議范本版B版
- 忻州職業(yè)技術(shù)學(xué)院《生物藥物臨床前評(píng)價(jià)》2023-2024學(xué)年第一學(xué)期期末試卷
- 健康中國產(chǎn)業(yè)園規(guī)劃方案
- (2024年)二年級(jí)上冊音樂
- 2024屆高考英語一輪復(fù)習(xí)讀后續(xù)寫脫險(xiǎn)類續(xù)寫講義
- ISO13485內(nèi)部審核檢查表+內(nèi)審記錄
- 2024年《藥物臨床試驗(yàn)質(zhì)量管理規(guī)范》(GCP)網(wǎng)絡(luò)培訓(xùn)題庫
- 新華健康體檢報(bào)告查詢
- 2024版智慧電力解決方案(智能電網(wǎng)解決方案)
- 公司SWOT分析表模板
- 小學(xué)預(yù)防流行性感冒應(yīng)急預(yù)案
- 生物醫(yī)藥大數(shù)據(jù)分析平臺(tái)建設(shè)-第1篇
- 美術(shù)家協(xié)會(huì)會(huì)員申請表
評(píng)論
0/150
提交評(píng)論