第4章-單片機的C51程序設(shè)計_第1頁
第4章-單片機的C51程序設(shè)計_第2頁
第4章-單片機的C51程序設(shè)計_第3頁
第4章-單片機的C51程序設(shè)計_第4頁
第4章-單片機的C51程序設(shè)計_第5頁
已閱讀5頁,還剩115頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第4章單片機的C51程序設(shè)計

吳政江制作

貴州電子信息職業(yè)技術(shù)學(xué)院貴州省人才培養(yǎng)優(yōu)秀單位4.1C51程序的結(jié)構(gòu)特點4.2C51語法基礎(chǔ)4.3C51的數(shù)據(jù)類型、存儲類型及常量與變量4.4C51對單片機主要資源的定義4.5C51的基本運算4.6C51的構(gòu)造數(shù)據(jù)類型4.7C51的流程構(gòu)造語句4.8C51的函數(shù)4.9指針4.10C51程序設(shè)計舉例實訓(xùn)四:單片機控制流水燈(C51程序)實訓(xùn)五:計數(shù)器的C51程序設(shè)計與制作小結(jié)習(xí)題與思考題4.1C51程序的結(jié)構(gòu)特點

4.1.1C語言與匯編語言的比較單片機的C51編程與匯編語言編程相比,具有以下優(yōu)點。(1)對單片機的指令系統(tǒng)不要求有任何的了解,就可以用C語言直接編程操作單片機。(2)寄存器分配、不同存儲器的尋址以及數(shù)據(jù)類型等細節(jié)完全由編譯器自動管理。(3)程序有規(guī)范的結(jié)構(gòu),可分成不同的函數(shù),可使程序結(jié)構(gòu)化。(4)庫中包含許多標(biāo)準(zhǔn)函數(shù),具有較強的數(shù)據(jù)處理能力,使用十分方便。(5)具有方便的模塊化編程技術(shù),使已編好的程序很容易移植。4.1.2C51程序的結(jié)構(gòu)特點

舉例:設(shè)單片機AT89C51的P1.0口接有一個發(fā)光二極管,如圖4-1所示。試用C51編程使該發(fā)光二極管間隔1s亮滅閃動。LEDVccAT89C51P1.0R1圖4-1驅(qū)動發(fā)光二極管#include<reg51.h>//包含51系列單片機頭文件#defineuintunsignedint//宏定義sbitled1=P1^0;//聲明單片機P1口的第一位voiddelayms(uint);//聲明延時子函數(shù)voidmain()//主函數(shù){While(1)//大循環(huán){led1=0;/*點亮接在P1.0引腳上的LED*/delayms(1000);//延時1秒led1=1;/*關(guān)閉接在P1.0引腳上的LED*/delayms(1000);//延時1秒}}voiddelayms(uintxms)//延時x毫秒子函數(shù){uinti,j;for(i=xms;i>0;i--)/*i=xms即延時約xms毫秒*/for(j=110;j>;j--);}由以上例子可看出C51程序結(jié)構(gòu)具有以下特點:(1)C語言程序是由函數(shù)構(gòu)成的。(2)一個函數(shù)由兩部份組成。①函數(shù)首部,即函數(shù)的第一行。②函數(shù)體,即函數(shù)首部下面的大括號“{}”內(nèi)的部分。函數(shù)體一般包括:a.聲明部分:在這部分中定義所用到的變量,如“sbitled1=P1^0;”。b.執(zhí)行部分:由若干個語句組成。(3)一個C語言程序,總是從main()函數(shù)開始執(zhí)行的,而不管物理位置上這個main()放在什么地方。(4)C語言源程序的前面幾行通常是以“#”開頭的預(yù)處理命令。預(yù)處理命令包括文件包含(include)命令、宏(define)命令以及條件編譯命令等。(5)C語言區(qū)分大小寫。如將“include”寫成“INCLUDE”就會編譯出錯。(6)C語言書寫的格式自由,可以在一行寫多個語句,也可以把一個語句寫在多行。(7)每個語句和資料定義的最后必須有一個分號“;”,分號“;”是C語句的必要組成部分,即語句結(jié)束標(biāo)志。但預(yù)處理命令、函數(shù)頭和花括號“}”之后不能加分號“;”。(8)可以用/*……*/的形式為C程序的任何一部分作注釋。C51也支持C++風(fēng)格的注釋,即用“//”引導(dǎo)的后面的語句是注釋。例如:P1_0=!P1_0;//取反P1.0這種風(fēng)格的注釋,只對本行有效,所以不會出現(xiàn)上面的問題,而且書寫也比較方便。因此,程序在只需要一行注釋的時候,建議采用這種格式。(9)一個C語言源程序可以由一個或多個源文件組成。4.2C51語法基礎(chǔ)

4.2.1C語言詞匯(1)標(biāo)識符在程序中使用的變量名、函數(shù)名、標(biāo)號等統(tǒng)稱為標(biāo)識符。C語言規(guī)定,標(biāo)識符只能是字母(A~Z,a~z)、數(shù)字(0~9)、下劃線(_)組成的字符串,并且第一個字符必須是字母或下劃線。①標(biāo)準(zhǔn)C語言不限制標(biāo)識符的長度,但它受各種版本的C語言編譯系統(tǒng)限制,同時也受到具體機器的限制。②在標(biāo)識符中,大小寫是有區(qū)別的。③標(biāo)識符雖然可由程序員隨意定義,但標(biāo)識符是用于標(biāo)識某個量的符號。④標(biāo)識符不能使用系統(tǒng)保留的關(guān)鍵字。(2)關(guān)鍵字(也叫保留字)①數(shù)據(jù)類型關(guān)鍵字。用于定義或說明變量、函數(shù)或其他數(shù)據(jù)結(jié)構(gòu)的類型。主要有char,double,float,int,long,short,signed,struct,union,unsigned,void,enum等12個。②控制語句關(guān)鍵字。用于表示一個語句的功能。主要有break,case,continue,default,do,else,for,goto,if,return,switch,while等12個。③存儲類型關(guān)鍵字。用于說明變量或函數(shù)的存儲類型。主要有auto,extern,register,static等4個。④預(yù)處理命令關(guān)鍵字。用于表示一個處理命令。主要有include、define等2個。⑤其他關(guān)鍵字。主要有const,sizeof,typedef,volatile等4個。(3)運算符C語言中含有相當(dāng)豐富的運算符。如強制類型轉(zhuǎn)換運算符、算術(shù)運算符、關(guān)系運算符、邏輯運算符以及位運算符等。運算符與變量、函數(shù)一起組成表達式,表示各種運算功能。運算符由一個或多個字符組成。(4)分隔符①逗號分隔符。

②空格分隔符。4.2.2編譯預(yù)處理

編譯預(yù)處理命令概念:計算機將C語言編譯為機器語言時進行的預(yù)處理。這些命令只在編譯時有效,不是計算機運行的可執(zhí)行語句。編譯預(yù)處理命令以“#”開頭,末尾不加分號,包括頭宏命令、文件包含命令、條件編譯命令等。

(1)宏命令作用:用標(biāo)識符來代表一個字符串,系統(tǒng)在編譯之前自動將標(biāo)識符替換為字符串。主要用于定義常量。宏定義的標(biāo)識符(常量)一般用大寫字母,以便與變量相區(qū)別。定義形式:#define標(biāo)識符字符串例如:#definePI3.14/*后續(xù)程序中所有的PI都用3.14代替。即凡是出現(xiàn)PI的地方即表示3.14,這樣做有利于閱讀程序和修改程序。*/(2)文件包含

文件包含:指在一個文件中將另一個文件的全部內(nèi)容包含進來,通常用來將程序中用到的系統(tǒng)函數(shù)、宏標(biāo)識符、自定義函數(shù)等的文件包含進來。被包含的文件也叫頭文件(以“.h”為擴展名的文件)。

格式:#include<文件名>或#include“文件名”在KeilC51中常用的包含文件(頭文件)有以下三種:

①reg51.h頭文件。reg51.h是對51子系列單片機的特殊功能寄存器進行定義的頭文件,使用匯編語言中的特殊功能寄存器名稱,將各個特殊功能寄存器定義為該寄存器的直接地址,在C語言中可以通過寄存器名稱直接對這些寄存器進行操作,特殊功能寄存器名稱全部使用大寫。reg51.h沒有對單片機的四個輸入輸出端口進行位定義,如果程序中需要對并行端口進行位操作,可以使用regx51.h。對于52系列單片機,相應(yīng)的頭文件為reg52.h或regx52.h。②stdio.h頭文件。stdio.h是標(biāo)準(zhǔn)輸入輸出庫函數(shù)頭文件。該庫函數(shù)文件是定義計算機鍵盤輸入與計算機屏幕顯示的庫函數(shù),單片機本身無需這些庫函數(shù),但為了方便利用計算機調(diào)試程序,需要包含該頭文件。常用的標(biāo)準(zhǔn)輸入、輸出庫函數(shù)有以下兩種:a.printf(格式控制,輸出列表);。該函數(shù)按指定格式在屏幕上顯示對應(yīng)輸出項的值。b.scanf(格式控制,地址列表);。該函數(shù)接收計算機鍵盤輸入的數(shù)據(jù)并賦值給對應(yīng)的變量。例如:intx=3;chary[3]=“abc”;printf(“x=%d,y=%3s\n”,x,y);scanf(“%d,%c\n”,&x,&y);printf(“x=%d,y=%3s\n”,x,y);其中,格式控制必須包含在一對雙引號內(nèi),包括格式說明符(%d)、普通字符(x=,y=)和轉(zhuǎn)義控制符(\n)三種類型。格式說明符前必須用百分號“%”。常用的格式說明符的含義如表4-1所示。表4-1常用格式字符的含義格式字符說明附加格式字符說明d帶符號的十六進制數(shù)m數(shù)據(jù)長度s字符串n截取字符的個數(shù)c一個字符f小數(shù)形式的實數(shù)nn位小數(shù)常用的轉(zhuǎn)義控制符有兩個:\n:換行。\r:回車。他的前必須用反斜杠“\”。再如,在計算機屏幕上打印99乘法口訣表。參考程序如下所示:/*cfb.c*/#include<reg51.h>//包含51系列單片機頭文件#include<stdio.h>//包含基本輸入、輸出頭文件voidcominit() //設(shè)置定時器、串行通信函數(shù){SCON=0x50;//設(shè)置串行口控制寄存器

TMOD|=0x20;//設(shè)置定時器方式寄存器

TH1=0xf3;//設(shè)置定時器1(T1)高8位的初值

TR1=1;//啟動定時器1TI=1;//置位發(fā)送標(biāo)志位}voidmain(void)//主函數(shù){unsignedinti,j;//定義無符號整型變量i與jcominit();//調(diào)用設(shè)置定時器、串行通信函數(shù)for(i=1;i<=9;i++)//外循環(huán){for(j=1;j<=i;j++)//內(nèi)循環(huán) printf("%dX%d=%d",j,i,i*j);//計算機屏幕上打印一行乘法口訣表 printf("\n");//換行打印}}在keilC51中,為了借助計算機鍵盤與屏幕調(diào)試程序,需要模擬單片機串行口與計算機鍵盤與計算機屏幕進行通信。因而需要設(shè)置定時器/計數(shù)器與串行通信,“voidcominit()”函數(shù)就是為此目的而寫的。程序調(diào)試運行結(jié)果如下所示:1X1=11X2=22X2=41X3=32X3=63X3=91X4=42X4=83X4=124X4=161X5=52X5=103X5=154X5=205X5=251X6=62X6=123X6=184X6=245X6=306X6=361X7=72X7=143X7=214X7=285X7=356X7=427X7=491X8=82X8=163X8=244X8=325X8=406X8=487X8=568X8=641X9=92X9=183X9=274X9=365X9=456X9=547X9=638X9=729X9=81③用戶自定義標(biāo)題文件。用戶將自己常用的宏定義、條件編譯、圖片代碼、數(shù)據(jù)表格等組成一個文件,然后在各個源程序中用“#include”命令包含進來,無需重復(fù)定義。4.3C51的數(shù)據(jù)類型、存儲類型及常量與變量

4.3.1C51的數(shù)據(jù)類型C51的數(shù)據(jù)類型大體上可以分為基本數(shù)據(jù)類型、構(gòu)造數(shù)據(jù)類型和空類型等三種。其中基本數(shù)據(jù)類型又可分為位型、無符號字符型、有符號字符型、無符號整型、有符號整型、無符號長整型、有符號長整型、浮點型及雙精度實型等九種類型。它們的符號、長度、值域等如表4-2所示。表4-2C51的數(shù)據(jù)類型數(shù)據(jù)類型數(shù)據(jù)類型名稱長度/bit長度/Byte表示數(shù)的范圍bit或sbit位型1—0,1unsignedchar無符號字符型810~255signedchar有符號字符型81-128~+127unsignedint無符號整型1620~65535signedint有符號整型162-32768~+32767unsignedlong無符號長整型3240~4294967295(0~232-1)signedlong有符號長整型324-2147483648~+2147483647(-231~231-1)float單精度實型(浮點型)324±3.4e-38~±3.4e+38(相當(dāng)于6位有效數(shù)字)double雙精度實型648±1.7e-38~±1.7e+38(相當(dāng)于10位有效數(shù)字)4.3.2C51的數(shù)據(jù)存儲類型(1)數(shù)據(jù)存儲類型C51允許將變量或常量定義成不同的存儲類型,以使單片機訪問不同的存儲空間。主要包括片內(nèi)直接尋址型、片內(nèi)位尋址型、片內(nèi)間接尋址型、片外分頁尋址型、片外間接尋址型以及代碼型等六種類型,它們和單片機的不同存儲區(qū)相對應(yīng)。如表4-3所示。表4-3C51存儲類型與MCS-51單片機存儲空間的對應(yīng)關(guān)系存儲類型存儲類型名稱長度/bit長度/Byte值域范圍與MCS-51單片機存儲空間的對應(yīng)關(guān)系data片內(nèi)直接尋址型810~255直接尋址片內(nèi)低128字節(jié)數(shù)據(jù)存儲器RAMbdata片內(nèi)位尋址型8132~47按位或字節(jié)尋址片內(nèi)RAM的20H~2FH地址空間idata片內(nèi)間接尋址型810~255間接尋址片內(nèi)RAM的00H~FFH地址空間pdata片外分頁尋址型810~255分頁尋址256字節(jié)片外RAM,對應(yīng)MOVX@Rixdata片外間接尋址型1620~65535尋址64K字節(jié)片外RAM,對應(yīng)MOVX@DPTRcode代碼型1620~65535尋址64K字節(jié)ROM,對應(yīng)MOVC@DPTR(2)變量存儲類型定義舉例變量的存儲類型通常與數(shù)據(jù)類型一起使用。先說明數(shù)據(jù)類型,再說明存儲類型?,F(xiàn)舉例如下:①chardatavar1;//字符型變量var1被定義為data型,被分配在片內(nèi)RAM中的低128字節(jié)中。②bitbdataflags;//位變量flags被定義為bdata型,定位在片內(nèi)RAM中的位尋址區(qū)。③floatidatax,y,z;/*浮點型變量x、y和z被定義為idata存儲類型,定位在片內(nèi)RAM中,并只能用間接尋址方式進行訪問。*/④unsignedintpdatadimension;/*無符號整型變量dimension被定義為pdata型,定位在片外數(shù)據(jù)存儲區(qū),相當(dāng)于用MOVX@Ri訪問。*/⑤unsignedcharxdatavector[10][4][4];/*無符號字符型三維數(shù)組變量vector[10][4][4]被定義為xdata存儲類型,定位在片外RAM中,占據(jù)10×4×4=160個字節(jié),相當(dāng)于用MOVX@DPTR訪問。*/(3)存儲模式如果在變量定義時略去存儲類型標(biāo)志符,則由編譯器(如KeilC51)自動默認(rèn)存儲類型。默認(rèn)的存儲類型進一步由SMALL、COMPACT和LARGE存儲模式指令限制。存儲模式的有關(guān)說明如表4-4所示。表4-4存儲模式及說明存儲模式模式名稱說

明SMALL小模式參數(shù)及局部變量放入可直接尋址的片內(nèi)存儲器(最大128字節(jié),默認(rèn)存儲類型是data),因此訪問十分方便。另外所有對象,包括棧,都必須嵌入片內(nèi)RAM。棧長很關(guān)鍵,因為實際棧長依賴于不同函數(shù)的嵌套層數(shù)。COMPACT一般模式(中模式)參數(shù)及局部變量放入分頁片外存儲區(qū)(最大256字節(jié),默認(rèn)存儲類型是pdata),通過寄存器R0和R1間接尋址,??臻g位于內(nèi)部數(shù)據(jù)存儲器中。LARGE大模式參數(shù)及局部變量直接放入片外數(shù)據(jù)存儲區(qū)(最大64KB字節(jié),默認(rèn)存儲類型是xdata),使用數(shù)據(jù)指針DPTR來進行尋址。用此數(shù)據(jù)指針訪問的效率低,尤其是對二個或多個字節(jié)的變量,這種數(shù)據(jù)類型的訪問機制直接影響代碼的長度,另一個不便之處在于這種數(shù)據(jù)指針不能對稱操作。4.3.3常量與變量(1)常量在程序運行過程中,其值不能被改變的量稱為常量,如數(shù)字、字符等。每種數(shù)據(jù)類型的數(shù)值都有常量。字符型常量用單引號括起來,字符串常量用雙引號括起來,十六進制數(shù)常量用“0x+數(shù)值”表示。①直接常量(也叫字面常量)。如12、0、0xCE、‘A’、“GUIZHOU”等。②符號常量。符號常量即是用一個標(biāo)識符來代替一個常量。符號常量通常用前面介紹的宏命令define來定義。如:#definetscr_init0x40#definetmodh_init0#definetmodl_init250也可通過const關(guān)鍵字來定義的符號常量。定義形式:數(shù)據(jù)類型const標(biāo)識符=數(shù)字如:intconstPI=3;區(qū)別:用define定義的常量不占任何存儲空間,在編譯時直接用對應(yīng)的數(shù)據(jù)代替其常量名稱參與運算。而用const定義的常量則會占去單片機ROM區(qū)的內(nèi)存,占去的空間大小為其定義數(shù)據(jù)類型所占空間的大小,如上面定義的PI常量占2個字節(jié)的空間。(2)變量在程序運行過程中,其值可以被改變的量稱為變量。每個變量都必須有變量名,變量名是標(biāo)識符,必須滿足用戶標(biāo)識符的要求。變量必須先定義后使用,定義變量的目的是說明變量的數(shù)據(jù)類型,以便為變量分配相應(yīng)的存儲單元。在程序使用變量前最好給變量賦初值,不賦初值的數(shù)值型變量其初值為0。變量在定義的同時可以賦初值。如:[static]intx,y=2,j=5;floatsum;以上兩條語句定義了x、y、j三個靜態(tài)整型變量和一個浮點型變量sum,并且給變量y賦初值2,j賦初值5,沒有給變量x賦初值,其初值默認(rèn)為0。其中的存儲類型在需要特別聲明的時候才需要,否則可以省略。同類變量可以共用一個數(shù)據(jù)類型說明符,各個變量之間用逗號隔開,最后以分號結(jié)束。這三個整型變量x、y、j在后面的程序中可以存放整型數(shù)據(jù)。浮點型變量sum可以存放一個浮點型數(shù)據(jù)的值。4.4C51對單片機主要資源的定義

4.4.1使用關(guān)鍵字定義特殊功能寄存器(SFR)SFR及其可位尋址的位是通過關(guān)鍵字sfr和sbit來定義的,這種方法與標(biāo)準(zhǔn)C不兼容,只適用于C51。(1)用sfr定義特殊功能寄存器(SFR)的字節(jié)地址①格式:sfr寄存器變量名稱=地址值;②功能:將右邊的地址賦值給左邊的寄存器變量名稱。③舉例:a.sfrPSW=0xD0;//定義程序狀態(tài)字寄存器PSW的地址為D0Hb.sfrSCON=0x98;//定義串行口控制寄存器SCON的地址為98Hc.sfrP0=0x80;//定義P0口的地址為80Hd.sfrTMOD=0x89;//定義定時器/計數(shù)器方式控制寄存器TMOD的地址為89H(2)用sbit定義特殊功能寄存器(SFR)的位地址①格式:sbit的用法有三種格式,分別介紹如下。a.sbit位變量名稱=位地址值;b.sbit位變量名稱=SFR名稱^變量位地址值;c.sbit位變量名稱=SFR地址值^變量位地址值;②功能:將右邊的位地址賦值給左邊的位變量名稱。③舉例:a.sbitCY=0xD7;//定義進位標(biāo)志CY的地址為D7Hb.sbitAC=PSW^6;//定義輔助進位標(biāo)志AC為PSW的第6位,其中PSW必須先用sfr定義好c.sbitRS0=0xD0^3;//定義RS0的地址為D3H(即D0H單元的第3位)注意:用sfr和sbit定義的SFR必須位于函數(shù)外,一般放在程序的開頭。

4.4.2通過頭文件訪問特殊功能寄存器(SFR)

頭文件:以“.h”為擴展名的文件。C51編譯器給出的頭文件已經(jīng)給出了MCS-51單片機中的SFR及其可位尋址位的定義。并且KeilC51編譯器將這些頭文件按單片機的不同生產(chǎn)公司、不同型號分別存放在KeilC51的INC子目錄下,在程序中只需引用這些頭文件即可實現(xiàn)對SFR的訪問和控制。頭文件通常有reg51.h,reg52.h,math.h,ctype.h,stdio.h,stdlib.h,absacc.h,intrins.h等八個。但常用的卻只有reg51.h或reg52.h,math.h等二個。reg51.h或reg52.h是定義51單片機或52單片機特殊功能寄存器和位寄存器的,這兩個頭文件中大部分內(nèi)容是一樣的,52單片機比51單片機多一個定時器T2,因此,reg52.h中也就比reg51.h多幾行定義T2的內(nèi)容。math.h是定義常用數(shù)學(xué)運算的,比如求絕對值、求方根、求正弦或余弦等,該頭文件中包含有各種數(shù)學(xué)運算函數(shù),當(dāng)我們需要使用時可以直接調(diào)用它的內(nèi)部函數(shù)。在代碼中引用頭文件,其實際意義就是將這個頭文件中的全部內(nèi)容放到引用頭文件的位置,從而免去我們每次編寫同類程序時都要將頭文件中的語句重復(fù)編寫。打開reg51.h,其全部內(nèi)容見教材所示。舉例如下:#include<reg51.h>//使用的單片機為AT89C51main(){TL0=0xb0;//訪問定時器0,設(shè)置時間常數(shù)TH0=0x3c;TR0=1;//啟動定時器0┅}4.4.3擴展I/O端口或片外RAM的直接訪問

擴展的片外RAM或I/O端口需要用戶自己先定義后才能在語句或函數(shù)中使用。現(xiàn)舉例如下:#include<absacc.h>/*包含頭文件absacc.h,其內(nèi)部將XBYTE定義為一個指針,指向外部數(shù)據(jù)存儲器RAM的零地址單元*/#definePAXBYTE[0xffec]//將PA定義為外部I/O口,地址為0xffecmain(){PA=0x3a;//將數(shù)據(jù)3AH寫入地址為0xffec的存儲單元或I/O端口}4.4.4定義和使用位變量

C51使用關(guān)鍵字“bit”來定義位變量。格式:bit變量名稱;功能:將變量名稱定義為位型變量。例:bitlock;//將lock定義為位變量bitdirention;//將dirention定義為位變量函數(shù)既可以有bit類型的參數(shù),也可以有bit類型的返回值。例如:bitfunc(bitb0,bitb1){bita;┅return(a);}4.5C51的基本運算

4.5.1C51的算術(shù)運算(1)基本的算術(shù)運算符①+:加法運算符。②-:減法運算符。③*:乘法運算符。④/:除法或求模運算符。⑤%:取余運算符。(2)自增、自減運算符①++:自增運算符。②--:自減運算符。例如:++j、j++、--j、j--注意:++和--運算符只能用于變量,不能用于常量和表達式。++j表示先加1,再取值;而j++表示先取值,再加1。自減運算也是如此。(3)算術(shù)表達式和運算符的優(yōu)先級與結(jié)合性①算術(shù)表達式就是用算術(shù)運算符和括號將運算對象連接起來的式子。例如:(2a+3b)*c/d。②C51規(guī)定了算術(shù)運算符的優(yōu)先級為先乘除和取模,后加減,括號最優(yōu)先。③C語言中各運算符的結(jié)合性分為兩種,即左結(jié)合性(自左至右)和右結(jié)合性(自右至左)。算術(shù)運算符均為左結(jié)合性,即先左后右。例如表達式x-y+z,則y應(yīng)先與“-”號結(jié)合,執(zhí)行x-y運算,然后再執(zhí)行+z的運算。這種自左至右的結(jié)合方向就稱為“左結(jié)合性”。而自右至左的結(jié)合方向稱為“右結(jié)合性”。最典型的右結(jié)合性運算符是賦值運算符。如x=y=z,由于“=”的右結(jié)合性,應(yīng)先執(zhí)行y=z,再執(zhí)行x=(y=z)運算。④不同數(shù)據(jù)類型間的轉(zhuǎn)換。其一是自動類型轉(zhuǎn)換,即在程序編譯時,由C編譯器自動進行數(shù)據(jù)類型轉(zhuǎn)換。其二是使用強制類型轉(zhuǎn)換運算符。語句形式為:(類型說明符)(表達式)。功能:把表達式的運算結(jié)果強制轉(zhuǎn)換成類型說明符所表示的類型。例如:inta,b;//a、b為整數(shù)(double)(a+b);//將a+b強制轉(zhuǎn)換成double數(shù)據(jù)類型4.5.2C51的關(guān)系運算(1)關(guān)系運算符及其優(yōu)先級關(guān)系運算符也叫比較運算符,C51提供了以下6種關(guān)系運算符。①<:小于運算符。④>=:大于等于運算符。②<=:小于等于運算符。⑤==:等于運算符。③>:大于運算符。⑥!=:不等于運算符。在以上運算符中,<、<=、>、>=這四個運算符的優(yōu)先級相同,處于高優(yōu)先級;==和!=這兩個運算符的優(yōu)先級也相同,處于低優(yōu)先級。此外,關(guān)系運算符的優(yōu)先級低于算術(shù)運算符的優(yōu)先級,而高于賦值運算符的優(yōu)先級。(2)關(guān)系表達式關(guān)系表達式:用關(guān)系運算符將運算對象連接起來的式子。如:a>b、(a=4)<(b=3)等。關(guān)系表達式的值為邏輯值,其結(jié)果只能是真和假兩種值之一。C51中用1表示真,用0表示假。4.5.3C51的邏輯運算(1)邏輯運算符及其優(yōu)先級邏輯運算是對變量進行邏輯與運算、或運算及非運算。①&&:邏輯與運算符。②||:邏輯或運算符。③?。哼壿嫹沁\算符。其中非運算的優(yōu)先級最高,而且高于算術(shù)運算符;或運算的優(yōu)先級最低,低于關(guān)系運算符,但高于賦值運算符。(2)邏輯運算表達式邏輯運算表達式:用邏輯運算符將運算對象連接起來的式子。例如:(a>b)||c&&!d,表示a大于b的值跟c與d非的值相或。邏輯表達式的值與關(guān)系表達式的值一樣,也是邏輯量,即真或假。4.5.4C51的位運算位運算的操作對象只能是整形和字符型數(shù)據(jù),而不能是實型數(shù)據(jù)。①&:按位與運算符,兩個字符或整數(shù)按位進行邏輯與運算。例如:var3=var1&var2。②|:按位或運算符,兩個字符或整數(shù)按位進行邏輯或運算。例如:var3=var1|var2。③^:按位異或運算符,兩個字符或整數(shù)按位進行邏輯異或運算。例如:var3=var1^var2。④~:按位取反運算符,兩個字符或整數(shù)按位進行邏輯非運算。例如:var1=~var2。⑤<<:左移運算符,字符或整數(shù)按位進行邏輯左移運算。例如:var1=var2<<4。⑥>>:右移運算符,字符或整數(shù)按位進行邏輯右移運算。例如:var1=var2>>6。4.5.5C51的賦值運算(1)賦值運算符賦值符號“=”完成的操作即為賦值運算,它是右結(jié)合性,且優(yōu)先級最低。(2)賦值表達式將一個變量與表達式用賦值號連接起來就構(gòu)成賦值表達式。形式如下:變量名=表達式功能:將“=”右邊表達式的值賦給“=”左邊的一個變量。例如:a=(b=4)+(c=6),該表達式的值為10,變量a的值也為10。(3)賦值的類型轉(zhuǎn)換規(guī)則在賦值運算中,當(dāng)賦值運算符“=”兩側(cè)的類型不一致時,系統(tǒng)自動將右邊表達式的值轉(zhuǎn)換成左側(cè)變量的類型,再賦給該變量。轉(zhuǎn)換規(guī)則如下。①實型數(shù)據(jù)賦給整型變量時,舍棄小數(shù)部分。②整型數(shù)據(jù)賦給實型變量時,數(shù)值不變,但以IEEE浮點數(shù)形式存儲在變量中。③長字節(jié)整型數(shù)據(jù)賦給短字節(jié)整形變量時,實行截斷處理。如將long型數(shù)據(jù)賦給int型變量時,將long型數(shù)據(jù)的低兩字節(jié)數(shù)據(jù)賦給int型變量,而將long型數(shù)據(jù)的高兩字節(jié)的數(shù)據(jù)丟棄。④短字節(jié)整型數(shù)據(jù)賦給長字節(jié)整型變量時,進行符號擴展。如將int型數(shù)據(jù)賦給long型變量時,將int型數(shù)據(jù)賦給long型變量的低兩字節(jié),而將long型變量的高兩字節(jié)的每一位都設(shè)為int型數(shù)據(jù)的符號值。(4)復(fù)合賦值運算符賦值符號前加上其它運算符即構(gòu)成復(fù)合運算符。+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=。其功能是先進行加、減、乘、除、取余、與、或、異或、左移以及右移運算后再進行賦值操作。例如:a+=b;//等價于a=(a+b),賦值表達式加上分號即“a+=b;”也叫賦值語句x*=a+b;//等價于x=x*(a+b)a&=b;//等價于a=(a&b)a<<=4;//等價于a=(a<<4)4.6C51的構(gòu)造數(shù)據(jù)類型

4.6.1數(shù)組

數(shù)組是同類型數(shù)據(jù)的一個有序集合。它必須由具有相同數(shù)據(jù)類型的元素構(gòu)成,這些數(shù)據(jù)的類型就是數(shù)組的基本類型。例如,若數(shù)組中的所有元素都是整型,則該數(shù)組稱為整型數(shù)組,若所有元素都是字符型,則該數(shù)組稱為字符型數(shù)組。數(shù)組用一個名字來標(biāo)識,稱為數(shù)組名。數(shù)組中各元素的順序用下標(biāo)來標(biāo)識,下標(biāo)為n的元素可以表示為:數(shù)組名[n]。改變[]中的下標(biāo)就可以訪問數(shù)組中所有的元素。但應(yīng)注意,數(shù)組必須先定義,后使用。根據(jù)下標(biāo)的多少,可將數(shù)組分為一維數(shù)組、二維數(shù)組和多維數(shù)組,它們的定義形式不同。(1)一維數(shù)組一維數(shù)組是指由只具有一個下標(biāo)的數(shù)組元素組成的數(shù)組。定義形式如下:類型說明符數(shù)組名[元素個數(shù)];例如:intdemol[10];//定義一個名為demol的整型數(shù)組,數(shù)組包含10個元素在定義時賦初值的方法:①在定義數(shù)組時對數(shù)組的全部元素賦予初值。例如:inta[5]={1,2,3,4,5};//給全部元素賦值,a[0]=1,a[1]=2,a[2]=3,a[3]=4,a[4]=5。②只對數(shù)組的部分元素初始化。例如:intb[6]={1,2};//給部分元素賦值,b[0]=1,b[1]=2,b[2]=b[3]=b[4]=b[5]=0。③在定義數(shù)組時對數(shù)組的全部元素不賦初值,則數(shù)組元素值均被初始化為0。④可以在定義時不指明數(shù)組元素的個數(shù),而根據(jù)賦值部分由編譯器自動確定。例如:ucharBitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB};這相當(dāng)于定義了一個BitTab[6]這樣一個數(shù)組。⑤可以為數(shù)組指定存儲空間。若未指定空間時,則將數(shù)組定義在內(nèi)部RAM中,而當(dāng)用關(guān)鍵字code定義時,將數(shù)組元素定義在ROM空間中。例如:ucharcodeBitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB};這種方式適用于編程中不需要改變內(nèi)容的場合,如顯示用LED數(shù)碼管的字形碼等是很合適的。⑥C語言并不對越界使用數(shù)組進行檢測。例如上例中數(shù)組的長度是6,其元素應(yīng)該是從BitTab[0]到BitTab[5],但是如果你在程序中寫上BitTab[6],編譯器并不會認(rèn)為這有語法錯誤,也不會給出警告(其他語言如BASCI等則有嚴(yán)格的規(guī)定,這種情況將視為語法錯誤),因此,編程者必須自己小心確認(rèn)這是否是你需要的結(jié)果。(2)二維數(shù)組或多維數(shù)組數(shù)組的下標(biāo)具有兩個或兩個以上,則稱為二維數(shù)組或多維數(shù)組。定義二維數(shù)組的一般形式:類型說明符數(shù)組名[行數(shù)][列數(shù)];例如:floatdemo2[3][4];//demo2數(shù)組有3行4列共12個實型元素。二維數(shù)組既可以在定義時進行整體初始化,也可在定義后單個地進行賦值。例如:inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};//全部初始化結(jié)果為a[0][0]=1,a[0][1]=2,a[0][2]=3,a[0][3]=4,a[1][0]=5,a[1][1]=6,a[1][2]=7,a[1][3]=8,a[2][0]=9,a[2][1]=10,a[2][2]=11,a[2][3]=12。intb[3][4]={{1,2,3,4},{5,6,7,8},{}};//部分初始化(3)字符數(shù)組若一個數(shù)組的元素是字符型的,則該數(shù)組就是一個字符數(shù)組。例如:chara[8]={“JiXie”};//字符數(shù)組charadd[3][6]={“weight”,“height”,“width”};//字符串?dāng)?shù)組4.6.2結(jié)構(gòu)(1)結(jié)構(gòu)類型的定義(有三種方法)①先定義結(jié)構(gòu)類型,再定義結(jié)構(gòu)變量名定義結(jié)構(gòu)類型的一般格式為:struct結(jié)構(gòu)類型名{結(jié)構(gòu)元素表;//與定義基本數(shù)據(jù)類型相似};例如:structdate{intyear;charmonth;charday;};定義好一個結(jié)構(gòu)類型之后,就可以用它來定義結(jié)構(gòu)變量。一般格式為:struct結(jié)構(gòu)名結(jié)構(gòu)變量名1,結(jié)構(gòu)變量名2,…,結(jié)構(gòu)變量名n;例如,可以用結(jié)構(gòu)date來定義兩個結(jié)構(gòu)變量d1和d2。其格式為:structdated1,d2;//結(jié)構(gòu)變量d1和d2都具有structdate的結(jié)構(gòu)。②在定義結(jié)構(gòu)類型的同時定義結(jié)構(gòu)變量名這種方法是將方法1的兩個步驟合在一起,一般格式為:struct結(jié)構(gòu)類型名{結(jié)構(gòu)元素表;//與定義基本數(shù)據(jù)類型相似}結(jié)構(gòu)變量名1,結(jié)構(gòu)變量名2,…,結(jié)構(gòu)變量名n;例如,對于上述日期結(jié)構(gòu)變量也可按以下格式定義:structdate{intyear;charmonth;charday;}d1,d2;③直接定義結(jié)構(gòu)變量這種方法可以省掉結(jié)構(gòu)名,又稱為無名結(jié)構(gòu),一般格式為:struct{結(jié)構(gòu)元素表}結(jié)構(gòu)變量名1,結(jié)構(gòu)變量名2,…,結(jié)構(gòu)變量名n;例如,上述日期結(jié)構(gòu)變量可以按以下格式定義:struct{intyear;charmonth;charday;}d1,d2;

第③種方法與第②種方法十分相似,所不同的只是第③種方法中省略了結(jié)構(gòu)名“date”。這種方法一般只用于定義幾個確定的結(jié)構(gòu)變量的場合。(2)結(jié)構(gòu)類型變量的引用使用成員運算符“.”實現(xiàn)對結(jié)構(gòu)成員的引用。引用格式:結(jié)構(gòu)變量名.結(jié)構(gòu)元素例如,d1.year表示結(jié)構(gòu)變量d1中的元素year,d2.day表示結(jié)構(gòu)變量d2中的元素day等。如果一個結(jié)構(gòu)變量中的結(jié)構(gòu)元素又是另外一個結(jié)構(gòu)變量,即出現(xiàn)結(jié)構(gòu)的嵌套時,則需要采用若干個成員運算符,一級一級地找到最低一級的結(jié)構(gòu)元素,而且只能對這個最低級的結(jié)構(gòu)元素進行訪問。對結(jié)構(gòu)變量中的各個元素可以像普通變量一樣進行賦值、存取和運算。例如:d1.year=2009;sum=d1.day+d2.day;d1.month++;m1.time.hour=0x22;其中成員運算符“.”的優(yōu)先級別最高,因此d1.month++是對d1.month進行自加運算,而不是先對month進行自加運算。m1.time.hour=0x22是對嵌套結(jié)構(gòu)類型中最低一層的結(jié)構(gòu)元素進行訪問。4.6.3聯(lián)合(1)聯(lián)合與結(jié)構(gòu)的比較與結(jié)構(gòu)相似,在一個聯(lián)合中也可以包含多個不同類型的數(shù)據(jù)元素。但在內(nèi)存的分配上,聯(lián)合與結(jié)構(gòu)有著本質(zhì)的區(qū)別。結(jié)構(gòu)變量所占用的內(nèi)存長度是其中各個元素所占內(nèi)存長度的總和,而聯(lián)合變量所占用的內(nèi)存長度是其中最長元素的長度。因為聯(lián)合變量是采用所謂的“覆蓋技術(shù)”對內(nèi)存進行分配的。這種技術(shù)可使不同的變量分時使用同一個內(nèi)存空間,從而提高內(nèi)存的利用效率。即聯(lián)合為程序提供了一個不關(guān)心機器結(jié)構(gòu)而又能在同一存儲區(qū)處理不同數(shù)據(jù)類型的方法。例如,可將一個float型變量、一個int型變量、一個char型變量放在同一個地址開始的內(nèi)存單元中,如圖4-3所示。以上三個變量在內(nèi)存中的字節(jié)數(shù)不同,但卻都從同一地址開始存放,這就是所謂的“覆蓋技術(shù)”。floatiintjchark起始地址圖4-3聯(lián)合中變量的存儲方法(2)聯(lián)合類型的定義(與結(jié)構(gòu)相似,聯(lián)合也有三種定義方法)。①先定義聯(lián)合類型,再定義聯(lián)合變量名定義聯(lián)合類型的一般格式為:union聯(lián)合類型名{聯(lián)合成員說明;//與定義基本數(shù)據(jù)類型相似};其中“聯(lián)合成員說明”為該聯(lián)合中的各個成員(又稱為聯(lián)合的域),由于聯(lián)合可以由不同類型的數(shù)據(jù)組成,因此對聯(lián)合中的各個成員都要進行類型說明。例如,一個名為date的聯(lián)合類型可以定義如下:uniondate{intival;floatfval;

charsval;

};定義好一個聯(lián)合類型之后,就可以用它來定義聯(lián)合變量了。其定義格式為:union聯(lián)合類型名聯(lián)合變量名1,聯(lián)合變量名2,…,聯(lián)合變量名n例如,可以用聯(lián)合date來定義三個結(jié)構(gòu)變量a、b、c。其格式為:uniondatea,b,c;聯(lián)合變量a、b、c都具有uniondate類型的結(jié)構(gòu),即它們都是由一個整型數(shù)據(jù)、一個浮點型數(shù)據(jù)和一個字符型數(shù)據(jù)所組成的。并且,變量a,b,c將足夠大,使其能夠容納這三種類型中的最大者,具體的長度與操作無關(guān)。②在定義聯(lián)合類型的同時定義聯(lián)合變量名這種方法是將方法①的兩個步驟合在一起,一般格式為:union聯(lián)合類型名{聯(lián)合成員說明;//與定義基本數(shù)據(jù)類型相似}變量列表;例如,對于上述date聯(lián)合變量也可按以下格式定義:uniondate{intival;floatfval;charsval;}a,b,c;③直接定義聯(lián)合變量這種方法可以省掉聯(lián)合名,又稱為無名聯(lián)合,一般格式為:union{聯(lián)合成員說明}結(jié)構(gòu)變量名1,結(jié)構(gòu)變量名2,…,結(jié)構(gòu)變量名n;例如,上述a、b、c聯(lián)合變量也可以按以下格式定義:union{intival;floatfval;

charsval;

}a,b,c;第③種方法與第②種方法十分相似,所不同的只是第③種方法中省略了聯(lián)合名“date”。這種方法一般只用于定義幾個確定的聯(lián)合變量的場合。在上例中,如果只需要定義a、b和c而不打算再定義任何別的聯(lián)合變量,則可省掉聯(lián)合名“date”。不過為了便于記憶和以備將來進一步定義其他聯(lián)合變量的需要,一般還是不要省掉聯(lián)合名為好。(2)聯(lián)合類型變量的引用與結(jié)構(gòu)變量類似,對聯(lián)合變量的引用也是通過對其聯(lián)合元素的引用來實現(xiàn)的。格式:聯(lián)合變量名.聯(lián)合元素或聯(lián)合變量名->聯(lián)合元素。例如:對于前面定義的聯(lián)合變量a、b、c,下面的引用方法都是正確的:a.fval/*引用聯(lián)合變量a中float型元素fval*/b.ival/*引用聯(lián)合變量b中int型元素ival*/c->sval/*引用聯(lián)合變量c中char型元素sval*/注意:①在引用聯(lián)合元素時,要注意聯(lián)合變量用法的一致性。因為聯(lián)合類型中定義的各個不同類型的元素都可以分時地賦給變量,而所讀取變量的值是最近放入的某一元素的值,因此在表達式中對它進行處理時,必須注意其類型與表達式所要求的類型保持一致,否則將導(dǎo)致程序運行出錯。不能只引用聯(lián)合變量。例如,下面的寫法就是錯誤的:printf(“%f”,a);因為變量a可能是float、int和char三種類型,分別占用不同長度的內(nèi)存區(qū)域,若在引用時僅寫聯(lián)合變量名a,系統(tǒng)將難以確定究竟應(yīng)該輸出哪一個聯(lián)合元素的值。正確的寫法應(yīng)為:printf(“%f”,a.ival);②聯(lián)合類型的數(shù)據(jù)可以采用同一個內(nèi)存段來存放幾種不同類型元素的值,但是在每一瞬時只能存放其中一種類型的元素,而不能同時存放幾種。換句話說,每一瞬時只有一個元素在起作用。起作用的是聯(lián)合中最后一次存放的元素,如果存入了一個新的元素,則上次存入的元素就自動失去作用。例如,對于下列語句:a.fval=100.25;a.ival=200;a.sval=10;在執(zhí)行以上三條賦值語句之后,只有a.sval是有效的,而a.ival和a.fval都已失去作用。因此在引用聯(lián)合變量時一定要十分注意當(dāng)前在聯(lián)合變量中存放的究竟是哪一個元素。不能直接對聯(lián)合變量進行賦值,也不能在定義聯(lián)合變量時對它進行初始化。4.7C51的流程控制語句

4.7.1選擇控制語句(有if語句和switch/case語句,用于設(shè)計分支結(jié)構(gòu)程序)(1)if語句if語句是用來判定所給定的條件是否滿足,再根據(jù)判定的結(jié)果(真或假)來決定執(zhí)行給出的兩種操作之一。C51提供了三種形式的if語句。①形式1。格式:if(表達式){語句;}功能:如果表達式的結(jié)果為真,則執(zhí)行語句,否則不執(zhí)行。②形式2。格式:if(表達式){語句1;}else{語句2;}功能:如果表達式的結(jié)果為真,則執(zhí)行語句1,否則執(zhí)行語句2。③形式3。格式:if(表達式1){語句1;}elseif(表達式2){語句2;}elseif(表達式3){語句3;}…elseif(表達式m){語句m;}else{語句n;}功能:這是if語句的嵌套,即一個if語句中又包含有一個或多個if語句。主要用于多分支選擇程序。在if語句的嵌套中應(yīng)注意if與else的對應(yīng)關(guān)系,else總是與它前面最近的一個if語句相對應(yīng)?!纠?.1】

某浮點數(shù)的范圍在0.000~9999之間,試編寫一個函數(shù)返回浮點數(shù)的小數(shù)點位置。解:此題的基本思路是根據(jù)浮點數(shù)的4種不同取值范圍給出4種不同的返回值??梢约s定浮點數(shù)的大小在0.000~9.999、10.00~99.99、100.0~999.9、1000~9999之間時,分別返回0、1、2和3。參考程序如下:intftochar(floatvalp){intdotno=0;if(valp<10.00)dotno=0;elseif((valp>=10.0)&&(valp<100.0)dotno=1;elseif((valp>=100.0)&&(valp<1000.0)dotno=2;elseif(valp>=1000.0)dotno=3;returndotno;}根據(jù)小數(shù)點的位置,即可在實際的單片機系統(tǒng)中顯示出浮點數(shù)或小數(shù)。(2)switch/case語句(用于直接處理多分支選擇)switch/case語句的一般形式如下:switch(表達式){case常量表達式1:語句1;break;case常量表達式2:語句2;break;……case常量表達式n:語句n;break;default:語句n+1;}說明:當(dāng)switch后面括號內(nèi)的“表達式”的值與某一個case后面的常量表達式的值相等時,就執(zhí)行此case后面的語句(可以是復(fù)合語句),遇到break語句就退出switch語句。若所有的case中的常量表達式的值都沒有與表達式的值匹配時,就執(zhí)行default后面的語句?!纠?.2】

AT89C51單片機的P1.1和P1.0引腳接有兩只按鍵,其4種邏輯組合分別點亮由P2.0~P2.3控制的4只LED(高電平點亮),試編程實現(xiàn)此功能。解:參考程序如下:#include<at89x51.h>//包含AT89x51系列單片機的頭文件voidmain(){chara;do

{a=P1;

a=a&0x03;//屏蔽掉P1口的高6位

P2=P2&0xf0;//開始4只LED全熄

switch(a){case0:P2=P2|0x01;break;case1:P2=P2|0x02;break;case2:P2=P2|0x04;break;case3:P2=P2|0x08;}}while(1);//循環(huán)繼續(xù)讀取按鍵}4.7.2循環(huán)控制語句循環(huán)程序可分為“當(dāng)型”循環(huán)程序和“直到型”循環(huán)程序兩種類型,這與其它語言的循環(huán)程序一樣。在C51語言中,用來構(gòu)成循環(huán)控制的語句有:while語句、do-while語句、for語句以及if和goto語句等。(1)基于while語句構(gòu)成的循環(huán)采用while語句構(gòu)成循環(huán)結(jié)構(gòu)的一般格式如下:while(條件表達式){內(nèi)部語句;//內(nèi)部語句可以是復(fù)合語句,也可以為空}意義:當(dāng)條件表達式的結(jié)果為真(非0值)時,程序就重復(fù)執(zhí)行后面的內(nèi)部語句,一直執(zhí)行到條件表達式的結(jié)果變?yōu)榧伲?值)時為止。也就是說,這種循環(huán)結(jié)構(gòu)是先檢查條件表達式所給出的條件,再根據(jù)檢查的結(jié)果決定是否執(zhí)行后面的內(nèi)部語句。如果條件表達式的結(jié)果一開始就為假,則后面的內(nèi)部語句一次也不會執(zhí)行。因此屬于“當(dāng)型”循環(huán)。圖4-4為while語句的執(zhí)行過程。

假條件表達式內(nèi)部語句真圖4-4while語句的執(zhí)行過程【例4.3】

使用while語句計算自然數(shù)1~100的累加和,并用printf()函數(shù)通過單片機的串口顯示在終端上。解:參考程序如下:#include<stdio.h>/*包含基本輸入輸出頭文件stdio.h*/真內(nèi)部語句條件表達式假圖4-5do-while語句循環(huán)結(jié)構(gòu)的流程圖voidmain(){inti,sum=0;i=1;while(i<=100){/*復(fù)合語句循環(huán)體開始*/sum=sum+i;i++;}/*復(fù)合語句循環(huán)體結(jié)束*/printf(“1+2+…+100=%d\n”,sum);while(1);}(2)基于do-while語句構(gòu)成的循環(huán)do-while語句只能用來實現(xiàn)“直到型”循環(huán),其一般格式如下:do{內(nèi)部語句;//可以是復(fù)合語句}while(條件表達式);意義:先執(zhí)行給定的循環(huán)體語句,然后再檢查條件表達式的結(jié)果。當(dāng)條件表達式的值為真(非0值)時,則重復(fù)執(zhí)行循環(huán)體語句,直到條件表達式的值變?yōu)榧伲?值)時為止。因此,用do-while語句構(gòu)成的循環(huán)結(jié)構(gòu)在任何條件下,循環(huán)體語句至少會被執(zhí)行一次,這就是“直到型”循環(huán)。圖4-5給出了這種循環(huán)結(jié)構(gòu)的流程圖。真內(nèi)部語句條件表達式假圖4-5do-while語句循環(huán)結(jié)構(gòu)的流程圖【例4.4】實型數(shù)組sample存有10個采樣值,編寫一個函數(shù)返回其平均值(即平均值濾波程序)。解:參考程序如下:floatavg(float*sample){floatsum=0;charno=0;do{sum+=sample[no];no++;}while(no<10);return(sum/10);}假初值設(shè)定表達式內(nèi)部語句更新表達式循環(huán)條件表達式真圖4-6for語句的執(zhí)行過程示意圖(3)基于for語句構(gòu)成的循環(huán)采用for語句構(gòu)成循環(huán)結(jié)構(gòu)的一般格式如下:for([初值設(shè)定表達式];[循環(huán)條件表達式];[更新表達式]){內(nèi)部語句;//可以是復(fù)合語句}意義:先計算出初值設(shè)定表達式的值作為循環(huán)控制變量的初值,再檢查循環(huán)條件表達式的結(jié)果,當(dāng)滿足條件時就執(zhí)行循環(huán)體語句并計算更新表達式,然后再根據(jù)更新表達式的計算結(jié)果來判斷循環(huán)條件是否滿足,只有一直進行到循環(huán)條件表達式的結(jié)果為假(0值)時才退出循環(huán)體。各表達式之間必須用分號“;”進行分隔。for語句的執(zhí)行過程如圖4-6所示。【例4.5】

使用for語句計算自然數(shù)1~100的累加和,并用printf()函數(shù)通過單片機的串口顯示在終端上。解:參考程序如下:#include<aduc812.h>#include<stdio.h>intgetsum(void);voidmain(){SCON=0x50;//如果用KeilC進行模擬調(diào)用或使用printf(),必須初始化SCONTMOD=TMOD|0x20;//定時器T1工作方式2,用做波特率控制TH1=0xfd;//9600bps對應(yīng)T1的時間常數(shù)為0xfdTL1=0xfd;TR1=1;//啟動T1TI=1;//啟動發(fā)送,以發(fā)送第一個字符printf(“%d\n”,getsum());do{}while(1);}intgetsum(void){intsum=0;intn;for(n=1;n<=100;n++){sum=sum+n;}return(sum);}(4)基于if和goto構(gòu)成的循環(huán)①“當(dāng)型”循環(huán)。采用if和goto可以構(gòu)成“當(dāng)型”循環(huán)程序,其格式如下:loop:if(條件表達式){內(nèi)部語句;//可以是復(fù)合語句gotoloop;}說明:loop是語句標(biāo)號,實質(zhì)是帶冒號“:”的標(biāo)識符,原則上任何一條語句都可以有標(biāo)號,標(biāo)號和語句之間用冒號“:”分隔。其執(zhí)行過程是首先判斷條件表達式的值,當(dāng)條件表達式的值為真(非0值)時,則執(zhí)行內(nèi)部語句,遇到gotoloop語句時則無條件返回loop處繼續(xù)判斷條件表達式的值。直到條件表達式的值為假(0值)時才退出循環(huán)。需注意的是,條件表達式中條件變量的值必須在內(nèi)部語句中進行改變,否則就成為死循環(huán)程序。②“直到型”循環(huán)。采用if和goto也可以構(gòu)成“直到型”循環(huán)程序,其格式如下:loop:{內(nèi)部語句;//可以是復(fù)合語句if(條件表達式)gotoloop;}說明:首先執(zhí)行內(nèi)部語句(即循環(huán)體),再判斷條件表達式的值。若條件表達式的值為真(非0值)時,則執(zhí)行g(shù)otoloop語句,無條件返回loop處繼續(xù)執(zhí)行內(nèi)部語句(即循環(huán)體)。當(dāng)條件表達式的值為假(0值)時就退出循環(huán)。顯然,條件表達式的值不能一直為真(非0值),否則就成為死循環(huán)程序。③goto語句。goto語句是一個無條件轉(zhuǎn)向語句,它的一般形式為:goto語句標(biāo)號;前已述及,語句標(biāo)號是一個帶冒號“:”的標(biāo)識符,將goto語句和if語句相結(jié)合使用,就可以構(gòu)成“當(dāng)型”循環(huán)或“直到型”循環(huán)結(jié)構(gòu)。【例4.6】

使用goto語句跳出循環(huán)結(jié)構(gòu)。本程序采用循環(huán)結(jié)構(gòu)來求一個整數(shù)的等差數(shù)列,該數(shù)列滿足條件:頭四個數(shù)的和值為26,積值為880。該數(shù)列的公差應(yīng)為正整數(shù),否則將產(chǎn)生負(fù)的項,此外該數(shù)列的首項數(shù)必須小于5,且其公差也應(yīng)小于5,否則頭四項的和值將大于26。解:參考程序如下:#include<stdio.h>voidmain(){inta,b,c,d,i;for(a=1;a<5;++a){for(d=1;d<5;++d){

b=a+(a+d)+(a+2*d)+(a+3*d);

c=a*(a+d)*(a+2*d)*(a+3*d);if(b==26&&c==880)gotopt;}}pt:for(i=0;i<=10;++i)printf(“%d,”,a+i*d);

printf(“…\n”);while(1);}④continue語句。

在循環(huán)結(jié)構(gòu)中還可以使用一種中斷語句continue,它的功能是結(jié)束本次循環(huán),即跳過循環(huán)體中下面尚未執(zhí)行的語句,把程序流程轉(zhuǎn)移到當(dāng)前循環(huán)語句的下一個循環(huán)周期,并根據(jù)循環(huán)控制條件決定是否重復(fù)執(zhí)行該循環(huán)體。continue語句的一般格式為:continue;

continue語句通常和條件語句一起用在由while、do-while和for語句構(gòu)成的循環(huán)結(jié)構(gòu)中,它也是一種具有特殊功能的無條件轉(zhuǎn)移語句,但與goto、break語句不同,continue語句并不跳出循環(huán)體,而只是根據(jù)循環(huán)控制條件確定是否繼續(xù)執(zhí)行循環(huán)語句。【例4.7】

利用continue語句把10~20之間不能被3整除的數(shù)輸出。解:參考程序如下:#include<stdio.h>voidmain(){intn;for(n=10;a<=20;n++){if(n%3==0)continue;printf(“%d”,n);}while(1);}4.8C51的函數(shù)

4.8.1函數(shù)的分類與定義(1)函數(shù)的分類①主函數(shù)main()。關(guān)于主函數(shù)main(),我們應(yīng)該很熟悉了。下面再簡要介紹其格式和特點。格式:voidmain()/*注意:后面沒有分號*/{總程序從這里開始執(zhí)行;其他語句;……}特點:無返回值,無參數(shù)。

無返回值表示該函數(shù)執(zhí)行完后不返回任何值,上面main前面的void表示“空”,即不返回值的意思。無參數(shù)表示該函數(shù)不帶任何參數(shù),即main后面的括號中沒有任何參數(shù),只寫“()”就可以了,也可以在括號里寫上void,表示空的意思,如voidmain(void)。②普通函數(shù)。a.標(biāo)準(zhǔn)庫函數(shù)。b.用戶自定義函數(shù)。(2)函數(shù)的定義函數(shù)定義的一般形式為:函數(shù)類型函數(shù)名(形式參數(shù)列表)形式參數(shù)說明{局部變量定義;函數(shù)體語句;}其中,“函數(shù)類型”說明了自定義函數(shù)返回值的類型。返回值的類型可以是基本數(shù)據(jù)類型(如int、char、float、double等),也可以是指針類型。當(dāng)函數(shù)沒有返回值時,則使用標(biāo)識符void進行說明。若沒有指定函數(shù)的返回值類型,則默認(rèn)返回值為整型類型。一個函數(shù)只能有一個返回值,該返回值是通過函數(shù)中的return語句獲得的?!昂瘮?shù)名”是用標(biāo)識符表示的自定義函數(shù)的名字,它必須是一個合法的標(biāo)識符。“形式參數(shù)列表”中列出的是在主調(diào)用函數(shù)與被調(diào)用函數(shù)之間傳遞數(shù)據(jù)的形式參數(shù),形式參數(shù)的類型必須加以說明。形式參數(shù)可以是基本數(shù)據(jù)類型的數(shù)據(jù)、指針類型數(shù)據(jù)、數(shù)組等。在沒有調(diào)用函數(shù)時,函數(shù)的形式參數(shù)和函數(shù)內(nèi)部的變量未被分配內(nèi)存單元,即它們是不存在的。如果定義的是無參數(shù)函數(shù),可以沒有形式參數(shù),但圓括號不能省略?!熬植孔兞慷x”是對在函數(shù)內(nèi)部使用的局部變量進行定義。局部變量是定義在函數(shù)內(nèi)部的變量,編譯器只在定義該變量的函數(shù)范圍內(nèi)給其分配存儲空間。一旦調(diào)用結(jié)束,即刻釋放所分配的內(nèi)存單元。不同函數(shù)中的局部變量可以同名,但編譯器會給它們分配不同的存儲空間。形式參數(shù)也是一種局部變量。如果將變量定義在主函數(shù)之前,則成為全局變量。在其他函數(shù)中不加定義即可使用全局變量,各個函數(shù)對全局變量的賦值都會引起全局變量內(nèi)容的變化,因為各個函數(shù)修改的是同一個存儲單元的內(nèi)容。對同一名稱變量,如果在某一函數(shù)中有對該變量的定義(靜態(tài)變量除外),則該變量在這個函數(shù)中成為局部變量,而在該函數(shù)之外是全局變量?!昂瘮?shù)體語句”是為完成該函數(shù)的特定功能而設(shè)置的各種語句。在函數(shù)體中可以根據(jù)用戶自己的需要,設(shè)置各種不同的語句。這些語句應(yīng)能完成所需要的功能。【例4.8】

定義一個計算整數(shù)的正整數(shù)次冪的函數(shù)。解:參考程序如下:intpower(x,n)intx,n;{inti,p;p=1;for(i=1;i<=n;++i)p=p*x;return(p);}這里定義了一個返回值為整型的函數(shù)power(),它有兩個形式參數(shù):x,n。形式參數(shù)的作用是接受從主調(diào)用函數(shù)傳遞過來的實際參數(shù)的值。上例中形式參數(shù)x和n被說明為int類型。大括號以內(nèi)的部分是自定義函數(shù)的函數(shù)體。上例中在函數(shù)體內(nèi)定義了兩個局部變量i和p,它們均為整型數(shù)據(jù)。需要注意的是,形式參數(shù)的說明與函數(shù)體內(nèi)局部變量的定義是完全不同的兩個部分,前者應(yīng)寫在大括號的外面,而后者是函數(shù)體的一個組成部分,必須寫在大括號里面。(3)返回語句return返回語句用于終止函數(shù)的執(zhí)行,并控制程序返回到調(diào)用該函數(shù)時所處的位置。返回語句有兩種格式:return(變量或表達式);或者return;

①如果return語句后邊帶有變量或表達式,則要計算該變量或表達式的值,并將該變量或表達式的值作為該函數(shù)的返回值返回到主調(diào)用函數(shù)中去。函數(shù)返回值的類型就是該函數(shù)的類型,因此在定義一個函數(shù)時,函數(shù)本身的類型應(yīng)與return語句中變量或表達式的值的類型一致。如果函數(shù)的類型與return語句中變量或表達式的值的類型不一致,則以函數(shù)的類型為準(zhǔn)。對于數(shù)值數(shù)據(jù)可以自動進行轉(zhuǎn)換,即函數(shù)的類型決定返回值的類型。

②若使用不帶表達式的第2種形式,則被調(diào)用函數(shù)返回主調(diào)用函數(shù)時,函數(shù)值不確定。一個函數(shù)的內(nèi)部可以含有多個return語句,但程序僅執(zhí)行其中的一個return語句而返回主調(diào)用函數(shù)。

③如果不需要被調(diào)用函數(shù)返回一個確定的值,則可以不要return語句。在這種情況下,當(dāng)程序執(zhí)行到最后一個界限符“}”處時,就自動返回主調(diào)用函數(shù)。對于不需要有返回值的函數(shù),可以將該函數(shù)定義為void類型(空類型)。4.8.2函數(shù)的調(diào)用(1)函數(shù)的調(diào)用形式C語言程序中函數(shù)是可以互相調(diào)用的。所謂函數(shù)調(diào)用就是在一個函數(shù)體中引用另外一個已經(jīng)定義了的函數(shù),前者稱為主調(diào)用函數(shù),后者稱為被調(diào)用函數(shù)。函數(shù)調(diào)用的一般形式如下:函數(shù)名(實際參數(shù)列表);

“函數(shù)名”指出被調(diào)用的函數(shù)?!皩嶋H參數(shù)列表”中可以包含多個實際參數(shù),各個參數(shù)之間必須用逗號隔開。實際參數(shù)的作用是將它的值傳遞給被調(diào)用函數(shù)中的形式參數(shù)。因此,函數(shù)調(diào)用中的實際參數(shù)與函數(shù)定義中的形式參數(shù)必須在數(shù)量、類型以及順序上嚴(yán)格保持一致,以便將實際參數(shù)的值正確地傳遞給形式參數(shù)。否則在函數(shù)調(diào)用中會產(chǎn)生意想不到的結(jié)果。實際參數(shù)可以是常數(shù),也可以是變量或表達式,但要求它們具有確定的值。如果調(diào)用的是無參函數(shù),則可以沒有實際參數(shù)列表,但圓括號不能省略。在C語言中可以采用三種方式完成函數(shù)的調(diào)用:①函數(shù)語句:指在主調(diào)函數(shù)中將函數(shù)調(diào)用作為一條語句使用。例如:fun1();這是無參函數(shù),它不要求被調(diào)用函數(shù)返回一個確定的值,只要求它完成一定的操作。②函數(shù)表達式:指在主調(diào)用函數(shù)中將函數(shù)調(diào)用作為一個運算對象直接出現(xiàn)在表達式中,這種表達式就稱為函數(shù)表達式。例如:c=power(x,n)+power(y,m);實際上,這是一個賦值語句,它包含兩個函數(shù)調(diào)用,每個函數(shù)調(diào)用都有一個返回值,將兩個返回值相加的結(jié)果賦值給變量c。因此這種函數(shù)調(diào)用方式要求被調(diào)用函數(shù)返回一個確定的值。③函數(shù)參數(shù):指在主調(diào)用函數(shù)中將函數(shù)調(diào)用作為另一個函數(shù)調(diào)用的實際參數(shù)。例如:y=power(power(i,j),k);其中,函數(shù)調(diào)用power(i,j)放在另一個函數(shù)調(diào)用power(power(i,j),k)的實際參數(shù)列表中,以其返回值作為另一個函數(shù)調(diào)用的實際參數(shù)。這種在調(diào)用一個函數(shù)的過程中又調(diào)用了另外一個函數(shù)的方式,稱為嵌套函數(shù)調(diào)用。(2)在主調(diào)用函數(shù)中對被調(diào)用函數(shù)的說明與使用變量一樣,在調(diào)用一個函數(shù)之前(包括標(biāo)準(zhǔn)庫函數(shù)),必須對該函數(shù)的類型進行說明,即“先說明,后調(diào)用”。函數(shù)說明的一般形式:類型標(biāo)識符被調(diào)用的函數(shù)名(形式參數(shù)列表);其中,“類型標(biāo)識符”說明了函數(shù)返回值的類型?!靶问絽?shù)列表”中說明各個形式參數(shù)的類型。

注意:

①函數(shù)的說明與函數(shù)的定義是完全不同的。

②如果被調(diào)用函數(shù)是在主調(diào)用函數(shù)的前面定義的,或者已經(jīng)在程序文件的開始處說明了所有被調(diào)用函數(shù)的類型,在這兩種情況下不必再對被用函數(shù)進行說明。

③可以將所有用戶自定義函數(shù)的說明另存為一個專門的頭文件,需要時用#i

溫馨提示

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

評論

0/150

提交評論