單片機(jī)原理和應(yīng)用基于匯編C51和混合編程單片機(jī)C51程序設(shè)計(jì)_第1頁
單片機(jī)原理和應(yīng)用基于匯編C51和混合編程單片機(jī)C51程序設(shè)計(jì)_第2頁
單片機(jī)原理和應(yīng)用基于匯編C51和混合編程單片機(jī)C51程序設(shè)計(jì)_第3頁
單片機(jī)原理和應(yīng)用基于匯編C51和混合編程單片機(jī)C51程序設(shè)計(jì)_第4頁
單片機(jī)原理和應(yīng)用基于匯編C51和混合編程單片機(jī)C51程序設(shè)計(jì)_第5頁
已閱讀5頁,還剩111頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1第五章單片機(jī)C51程序設(shè)計(jì)5.1、C51程序設(shè)計(jì)基礎(chǔ)5.2、C51的數(shù)據(jù)類型及其在51單片機(jī)中的存儲方式5.3、硬件資源訪問5.4、C51的運(yùn)算符5.5、C51的指針5.6、C51的函數(shù)5.7、C51的流程控制5.8、C51編程實(shí)例25.1C51程序設(shè)計(jì)基礎(chǔ)

匯編語言程序可以高效率利用計(jì)算機(jī)資源,目標(biāo)程序占用內(nèi)存少,執(zhí)行速度快,適合于自動測控系統(tǒng)反應(yīng)快速、結(jié)構(gòu)緊湊的要求。

C語言程序容易掌握,通用性好,但編譯程序系統(tǒng)開銷大,目標(biāo)程序占用內(nèi)存多,且執(zhí)行時(shí)間比較長,多用于科學(xué)計(jì)算、工業(yè)設(shè)計(jì)、企業(yè)管理。實(shí)際應(yīng)用中,匯編語言常與C語言配合使用。使用C語言來進(jìn)行51內(nèi)核單片機(jī)的程序設(shè)計(jì),即C51程序設(shè)計(jì)。35.1.1C51語言特點(diǎn)用C51編程需要根據(jù)單片機(jī)存儲器結(jié)構(gòu)及內(nèi)部資源,定義相應(yīng)的數(shù)據(jù)類型和變量,按照C51所包含的數(shù)據(jù)類型、變量存儲模式、輸入/輸出處理、函數(shù)等方面的格式來編寫C語言應(yīng)用程序。其它的語法規(guī)定、程序結(jié)構(gòu)及程序設(shè)計(jì)方法,都與ANSIC相同。用C51語言編寫的應(yīng)用程序必須經(jīng)單片機(jī)的C語言編譯器,轉(zhuǎn)換生成單片機(jī)可執(zhí)行的代碼程序。本章是針對德國KEIL公司的C51編譯器介紹C51程序設(shè)計(jì)。4C51與匯編語言相比,有如下優(yōu)點(diǎn):C51語言程序具有規(guī)范的結(jié)構(gòu),可由不同的函數(shù)組成,用這種方式編寫的程序很容易被移植;運(yùn)算符和關(guān)鍵字用接近于自然語言的方式表示,改善了程序的可讀性;提供了包含很多數(shù)學(xué)函數(shù)及其他大量標(biāo)準(zhǔn)子程序的函數(shù)庫,具有較強(qiáng)的數(shù)據(jù)處理能力,開發(fā)效率高;C語言程序基本上不作修改或者進(jìn)行簡單的修改,就可方便地移植到其他類型的單片機(jī)上;總之,用C語言進(jìn)行單片機(jī)程序設(shè)計(jì)是單片機(jī)開發(fā)和應(yīng)用的必然趨勢,在進(jìn)行大型、復(fù)雜的單片機(jī)應(yīng)用系統(tǒng)開發(fā)時(shí)都通過C語言來設(shè)計(jì)程序。55.1.2C51程序結(jié)構(gòu)C51源程序由一個(gè)或者多個(gè)源文件組成,每個(gè)源文件擴(kuò)展名都命名為“*.c”。每個(gè)C51程序都由一個(gè)或多個(gè)函數(shù)組成,其中有且只有一個(gè)main()函數(shù)。程序從main()函數(shù)開始執(zhí)行,在main()函數(shù)中可以調(diào)用庫函數(shù)和用戶定義的函數(shù)。C51中還有中斷函數(shù),運(yùn)行每一個(gè)函數(shù)都執(zhí)行一個(gè)特定的任務(wù)來實(shí)現(xiàn)整個(gè)程序的功能。C51源程序中含有預(yù)處理命令、語句、說明等,說明和語句以分號(;)結(jié)尾,預(yù)處理命令后不加分號。程序中可以用“/*…注釋…..*/”或“//…注釋…”的形式對C程序中的任何部分進(jìn)行注釋,用于說明程序段的功能,增加程序的可讀性。6C51程序的結(jié)構(gòu)一般如下:#include<STC12C5A.h>intfun1(形參);//函數(shù)聲明charfun2(形參);unsignedcharx,y,z;//定義全局變量……voidmain()//主函數(shù)定義{

主函數(shù)體……}intfun1(形參)//功能函數(shù)定義{函數(shù)體……}charfun2(形參)//功能函數(shù)定義{函數(shù)體……}75.1.3C51的字符集、標(biāo)識符與關(guān)鍵字1.C51的字符集C51語言的字符集由大小寫英文字母、數(shù)字、下劃線和空格等特殊字符構(gòu)成。2.C51標(biāo)識符標(biāo)識符在源程序中用來標(biāo)識某個(gè)對象的名字,由程序員定義,用做變量名、函數(shù)名和類型名等。標(biāo)識符可以由字母、數(shù)字和下劃線組成,但必須由字母或者下劃線開頭。標(biāo)識符的定義不能與關(guān)鍵字及系統(tǒng)預(yù)先定義的標(biāo)準(zhǔn)標(biāo)識符(如標(biāo)準(zhǔn)函數(shù))同名,最好“見名知意”。C51程序中標(biāo)識符區(qū)分字母的大小寫。83.關(guān)鍵字關(guān)鍵字是C51已定義的具有固定名稱和特定含義的特殊標(biāo)識符,又稱保留字。標(biāo)準(zhǔn)C語言中規(guī)定的關(guān)鍵字有32個(gè)。C51編譯器除了支持ANSIC標(biāo)準(zhǔn)的關(guān)鍵字外,還擴(kuò)展了適應(yīng)51內(nèi)核單片機(jī)要求的關(guān)鍵字。C51擴(kuò)展關(guān)鍵字如下:bdatadataidatapdataxdatacodebitsbitsfrsfr16_at_reentrantinterruptusingvolatile

95.2C51的數(shù)據(jù)類型及其在51單片機(jī)中的存儲方式數(shù)據(jù)類型是指數(shù)據(jù)的存儲格式。無論哪種數(shù)據(jù)都存放在存儲單元中,每一個(gè)數(shù)據(jù)究竟要占用幾個(gè)單元,在編譯時(shí)都要提供給編譯系統(tǒng)。C51的數(shù)據(jù)類型與標(biāo)準(zhǔn)C語言的數(shù)據(jù)類型基本相同,但其中char型與short型相同,float型與double型相同。C51中還有專門針對51內(nèi)核單片機(jī)的特殊功能寄存器型和位類型。5.2.1C51的數(shù)據(jù)類型10

C51具體支持的基本數(shù)據(jù)類型及其長度、值域如表所示:變量名稱符號類型數(shù)據(jù)長度值域字符型有符號signedchar8位-128-+127無符號unsignedchar8位0-255整數(shù)型有符號signedint16位-32768-+32767無符號unsignedint16位0-65535長整型有符號signedlong32位-231-231-1無符號unsignedlong32位0-232-1浮點(diǎn)型有符號float32位±1.175494E-38-±3.402823E+38位類型bit1位0或1特殊位類型sbit1位0或18位特殊功能寄存器型sfr8位0-25516位特殊功能寄存器型sfr1616位0-65535111、字符型char長度為1個(gè)字節(jié)。默認(rèn)為signedchar。

對于signedchar,其字節(jié)的最高位為符號位,“0”表示正數(shù),“1”表示負(fù)數(shù),補(bǔ)碼表示,所能表示的數(shù)值范圍是-128~+127。

對于unsignedchar,其取值范圍為0~255。也可以存放西文字符,在計(jì)算機(jī)內(nèi)部用ASCII碼存放。

2、整型int長度為2個(gè)字節(jié),默認(rèn)為signedint。對于signedint,用于存放2字節(jié)帶符號數(shù),補(bǔ)碼表示,數(shù)的范疇為-32768~+32767。對于unsignedint,用于存放2字節(jié)無符號數(shù),數(shù)的范圍為0~65535。123、長整型long長度為4個(gè)字節(jié),默認(rèn)為signedlong;對于signedlong,用于存放4字節(jié)帶符號數(shù),補(bǔ)碼表示,數(shù)的范疇為-2147483648~+2147483647。

對于unsignedlong,用于存放4字節(jié)無符號數(shù),數(shù)的范圍為0~4294967295。

長整型數(shù)據(jù)與整型數(shù)據(jù)的存儲結(jié)構(gòu)都是高位字節(jié)數(shù)存放在低地址單元中,低位字節(jié)數(shù)存放在高地址單元中。例如,長整型變量的值為0x12345678時(shí),在內(nèi)存中的存放形式如右圖所示。地址0+1+2+30x120x340x780x56…….134、浮點(diǎn)型float長度為4個(gè)字節(jié)。用浮點(diǎn)型變量進(jìn)行任何數(shù)學(xué)運(yùn)算都需要使用由編譯器決定的各種不同效率等級的庫函數(shù)。KeilC51的浮點(diǎn)型變量數(shù)據(jù)類型是IEEE-754標(biāo)準(zhǔn)的單精度浮點(diǎn)型數(shù)據(jù),轉(zhuǎn)換成十進(jìn)制數(shù)后最多具有7位有效數(shù)字。

4個(gè)字節(jié)中包含指數(shù)和尾數(shù)兩部分,尾數(shù)的最高位始終為1,因而不保存。具體分布為:1位符號位,8位階碼位,23位尾數(shù),如下圖所示。字節(jié)地址0123浮點(diǎn)數(shù)內(nèi)容SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM符號和階碼尾數(shù)高位尾數(shù)低位14

符號位S:1表示負(fù)數(shù),0表示正數(shù)。

階碼E:共8位,是以2為底的指數(shù)再加上127,這樣可以避免出現(xiàn)負(fù)的階碼值。如,實(shí)際階碼-126用1表示,實(shí)際階碼0用127表示,即實(shí)際階碼數(shù)加上127得到階碼的值。階碼E的正常取值范圍是1~254,而對應(yīng)的指數(shù)實(shí)際取值范圍為-126~+127。

尾數(shù):M為其小數(shù)部分,共23位,其整數(shù)部分隱含為“1”。

一個(gè)浮點(diǎn)數(shù)的取值范圍:字節(jié)地址0123浮點(diǎn)數(shù)內(nèi)容SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM符號和階碼尾數(shù)高位尾數(shù)低位15例如:浮點(diǎn)數(shù)123.25其二進(jìn)制數(shù)01111011.01B=1.11101101×2+110;8位階碼E為6+127=133=10000101B;23位尾數(shù)值為11101101000000000000000B;32位浮點(diǎn)數(shù)表示形式為:

0100

0010

11110110

10000000

00000000B;在內(nèi)存中的存放格式如下表所示:字節(jié)地址0123浮點(diǎn)數(shù)內(nèi)容01000010111101101000000000000000165.位類型位類型是C51中擴(kuò)充的數(shù)據(jù)類型,用于訪問51內(nèi)核單片機(jī)中的可位尋址單元;包括bit型和sbit型,它們在內(nèi)存中只占1個(gè)二進(jìn)制位,其值可以為“0”或者“1”。利用它們可以定義一個(gè)位變量,但不能定義位指針,也不能定義位數(shù)組。兩種位類型變量的區(qū)別在于,用bit定義的位變量,其地址由C51編譯器編譯時(shí)予以安排,而用sbit定義位變量時(shí)必須同時(shí)定義其位地址,在C51編譯器編譯時(shí),其位地址不可變化。176.特殊功能寄存器型也是C51中擴(kuò)充的數(shù)據(jù)類型,用于訪問51內(nèi)核單片機(jī)中的特殊功能寄存器中的數(shù)據(jù);包括sfr和sfr16兩種類型;sfr為字節(jié)型特殊功能寄存器類型,占用1字節(jié)單元,利用它可以訪問51內(nèi)核單片機(jī)中所有的特殊功能寄存器;sfr16為雙字節(jié)型特殊功能寄存器類型,占用2字節(jié)單元,利用它可以訪問單片機(jī)中2字節(jié)的特殊功能寄存器。185.2.2數(shù)據(jù)的存儲器類型C51應(yīng)用程序中使用的任何數(shù)據(jù)必須以一定的存儲器類型定位于單片機(jī)的相應(yīng)存儲區(qū)域中。51內(nèi)核單片機(jī)中程序存儲器與數(shù)據(jù)存儲器嚴(yán)格分開。數(shù)據(jù)存儲器又分為片內(nèi)、片外兩個(gè)獨(dú)立的尋址空間,特殊功能寄存器與片內(nèi)RAM統(tǒng)一編址。使用匯編指令訪問這些存儲器時(shí),通常使用不同的指令即可。而在C51中訪問這些存儲器時(shí),是通過定義不同存儲類型的變量,以說明該變量的存儲器位置。

19C51編譯器支持的存儲器類型如下表所示:存儲器類型與硬件存儲器空間的對應(yīng)關(guān)系

data直接尋址的片內(nèi)RAM低128B,訪問速度最快

bdata片內(nèi)RAM可位尋址區(qū)(20H-2FH),允許字節(jié)和位混合訪問

idata用Ri間接尋址的片內(nèi)RAM全部地址空間(256B)

pdata用Ri間接訪問的片內(nèi)擴(kuò)展RAM或片外擴(kuò)展RAM低256B

xdata用DPTR間接訪問的片內(nèi)擴(kuò)展RAM或片外擴(kuò)展RAM(64KB)

code程序存儲器ROM空間(64KB)205.2.3常量和變量數(shù)據(jù)有常量和變量之分。1.常量常量就是在程序運(yùn)行過程中其值不能被改變的量,可以為字符,字符串,轉(zhuǎn)義字符,十進(jìn)制數(shù)或十六進(jìn)制數(shù)(用0x打頭表示)、浮點(diǎn)數(shù)等直接常量,也可以定義符號型常量,定義方式如下:

用宏定義語句定義常量,例如:#definePI3.1415926//定義PI為常量3.1415926

用const語句定義常量,例如:constunsignedcharxx=0x98;//定義xx為無符號char型常量0x9821表5-5常用的轉(zhuǎn)義字符轉(zhuǎn)義字符含義ASCII碼\0空字符0x00\n換行符0x0a\r回車符0x0d\t水平制表0x09\b退格符0x08\f換頁符0x0c\’單引號0x27\”雙引號0x22\\反斜杠0x5c222.變量在程序運(yùn)行過程中其數(shù)值可以改變的量叫變量;變量由變量名和變量值構(gòu)成;變量名是存儲單元地址的符號表示;變量的值是該地址單元存放的內(nèi)容;一個(gè)變量一旦被定義,編譯系統(tǒng)就會自動為它安排存儲單元;要在程序中使用變量必須先用標(biāo)識符作為變量名,并指出所用的數(shù)據(jù)類型和存儲器類型,這樣編譯系統(tǒng)才能為變量分配相應(yīng)的存儲空間。變量的定義格式如下:

[存儲種類]數(shù)據(jù)類型

[存儲器類型]變量名表;23舉例說明變量定義相關(guān)情況:chardatavarl;/*在片內(nèi)RAM低128B范圍內(nèi)定義用直接尋址方式訪問的字符型變量var1*/intidatavar2;//在片內(nèi)RAM256B范圍內(nèi)定義用間接尋址方式訪問的整型變量var2autounsignedlongdatavar3;/*在片內(nèi)RAM128B范圍內(nèi)定義用直接尋址方式訪問的自動無符號長整型變量var3*/externfloatxdatavar4;/*在擴(kuò)展RAM空間范圍內(nèi)定義用間接尋址方式訪問的外部實(shí)型變量var4*/intcodevar5;//在ROM空間定義整型變量var5unsignedcharbdatavar6;/*在片內(nèi)RAM位尋址區(qū)20H-2FH單元范圍內(nèi)定義無符號字符型變量var6*/245.2.4存儲模式存儲模式?jīng)Q定變量的默認(rèn)存儲器類型和參數(shù)傳遞區(qū)。若定義變量時(shí)指定了存儲器類型,編譯程序按要求為其分配存儲空間,這種情況可以不必再指定存儲模式;若未指定存儲器類型,編譯程序按照存儲模式為變量選擇默認(rèn)的存儲器類型和參數(shù)傳遞區(qū)。C51有三種存儲模式:SMALL、COMPACT和LARGE,以適應(yīng)不同規(guī)模的程序。如果沒有說明,編譯程序默認(rèn)使用SMALL模式。C51的數(shù)據(jù)存儲模式見表5-6。25表5-6C51的存儲模式存儲模式說明SMALL參數(shù)和局部變量存于可直接尋址的片內(nèi)RAM(最大128B,默認(rèn)存儲器類型為data)COMPACT參數(shù)及局部變量存于片內(nèi)擴(kuò)展RAM或片外擴(kuò)展RAM區(qū)低256B中(默認(rèn)存儲器類型為pdata)LARGE參數(shù)和局部變量直接存于片內(nèi)擴(kuò)展RAM或片外擴(kuò)展RAM中(最大64KB,默認(rèn)存儲器類型為xdata)261.C51編譯器3種存儲模式的優(yōu)缺點(diǎn)SMALL:所有變量默認(rèn)存放于片內(nèi)RAM中,這時(shí)的變量訪問速度最快、效率最高,但由于空間有限,只適用于小程序。COMPACT:所有變量默認(rèn)存放于片內(nèi)擴(kuò)展RAM或片外RAM區(qū)低256B中,對于片外RAM,具體哪一頁可由P2口指定。優(yōu)點(diǎn)是空間比SMALL大,但由于必須使用間接尋址方式訪問變量,所以速度較SMALL慢,但比LARGE模式快。LARGE:所有變量默認(rèn)存放于片內(nèi)擴(kuò)展RAM或片外RAM中,最多可有64KB??臻g最大,但用數(shù)據(jù)指針DPTR來尋址變量,速度較慢。產(chǎn)生的機(jī)器碼比SMALL和COMPACT模式都多。由于各種存儲模式在訪問效率、代碼長度、變量總長度等方面各有優(yōu)缺點(diǎn),現(xiàn)在常用的C51編譯程序通常支持混合模式。即不管存儲模式如何,把經(jīng)常使用的變量存放于片內(nèi)RAM,大塊數(shù)據(jù)則存放于擴(kuò)展RAM而將其指針存放于片內(nèi)RAM中。272.?dāng)?shù)據(jù)存儲模式設(shè)定 數(shù)據(jù)存儲模式的設(shè)定有兩種方式,即使用預(yù)處理命令或使用編譯控制命令。使用預(yù)處理命令設(shè)定數(shù)據(jù)存儲模式 使用預(yù)處理命令設(shè)定數(shù)據(jù)存儲模式時(shí),只需要在程序的開頭處加預(yù)處理命令即可。例如: #pragmacompact//設(shè)定數(shù)據(jù)存儲模式為緊湊編譯模式使用編譯控制命令設(shè)定數(shù)據(jù)存儲模式 使用編譯控制命令設(shè)定數(shù)據(jù)存儲模式,是在用C51編譯程序?qū)51源程序進(jìn)行編譯時(shí),使用編譯控制命令。例如: C51file1.CLARGE//設(shè)定源程序file1.c中的數(shù)據(jù)存儲模式為大編譯模式函數(shù)的存儲模式可通過在函數(shù)定義時(shí)后面帶存儲模式說明。28#pragmasmall//變量的存儲模式為SMALLcharx,y; //兩個(gè)變量x,y的存儲器類型為datastaticcharm,n;//兩個(gè)靜態(tài)變量m,n的存儲器類型為data#pragmacompact//變量的存儲模式為COMPACTchark; //變量k的存儲器類型為pdataintxdataz; //變量z的存儲器類型為xdataintfunc1(intx1,inty1)large//函數(shù)的存儲模式為LARGE{return(x1+y1); //形參x1和y1的存儲器類型為xdata型}intfunc2(intx2,inty2)//函數(shù)的存儲模式默認(rèn)為SMALL{return(x2-y2); //形參x2和y2的存儲器類型為data}【例5-1】變量和函數(shù)的存儲模式設(shè)置。295.3硬件資源訪問51內(nèi)核單片機(jī)中,除了程序計(jì)數(shù)器PC和8個(gè)通用工作寄存器之外,其它所有的寄存器均為特殊功能寄存器(SFR)。它們分散在片內(nèi)RAM區(qū)的高128B(0x80-0xFF),為了對它們進(jìn)行直接訪問,C51編譯器利用擴(kuò)展數(shù)據(jù)類型sfr和sfr16對這些特殊功能寄存器進(jìn)行定義。5.3.1C51對特殊功能寄存器的定義30例如:sfr PSW=0xd0; //程序狀態(tài)字寄存器地址0D0Hsfr SCON=0x98; //串行口控制寄存器地址98Hsfr TMOD=0x89; //定時(shí)/計(jì)數(shù)器模式寄存器地址89Hsfr P1=0x90; //P1端口地址90H1.用sfr定義8位特殊功能寄存器sfr

特殊功能寄存器名=特殊功能寄存器地址常數(shù)定義之后,在程序中就可以直接引用寄存器名。31sfrPORT_ZERO=0X80; sfrACC=0XE0; sfrNEW_CON=0XFF; sfrC_REG=0X22; 【例5-2】在基于STC12C5A60S2單片機(jī)的C51語言編程中,使用了下面特殊功能寄存器定義的語句,指出哪些是合法的,哪些是有效的,哪些是非法的。//合法有效,PORT_ZERO相當(dāng)于P0口的別名//合法有效,A寄存器的定義//合法無效,該地址無實(shí)際SFR//不合法,地址不在允許范圍內(nèi)322.用sfr16定義16位特殊功能寄存器當(dāng)16位寄存器的高8位地址緊排在低8位地址之后時(shí),就可以定義一個(gè)16位特殊功能寄存器變量。定義格式為: sfr16

特殊功能寄存器名=16位特殊功能寄存器中低8位的地址例如: sfr16DPTR=0x82;/*指定DPTR寄存器地址為0x82,其中DPL的地址為0x82,DPH的地址為0x83*/注意:這種定義適用于所有新的16位SFR,但不能用于定時(shí)/計(jì)數(shù)器T0和定時(shí)/計(jì)數(shù)器T1的定義。333.說明

定義特殊功能寄存器中的地址必須在0x80-0xff范圍內(nèi);定義特殊功能寄存器,必須放在函數(shù)外面作為全局變量;用sfr或sfr16每次只能定義一個(gè)特殊功能寄存器;用sfr或sfr16定義的變量必須是真實(shí)的特殊功能寄存器,其地址是固定的,不能像一般變量那樣隨便定義。34

5.3.2C51對位變量的定義1.特殊功能寄存器中特定位的定義 如果特殊功能寄存器的字節(jié)地址能被8整除,則這樣的特殊功能寄存器具有位尋址功能,可以用關(guān)鍵字sbit來定義特定位。定義方法有多種,分別如下:用寄存器名位定義 sfr PSW=0xd0;//定義PSW地址為D0H sbit CY=PSW^7;//CY為PSW.7用字節(jié)地址位表示 sbit CY=0xd0^7;//定義CY為字節(jié)地址0xd0單元的第7位,即PSW.7直接用位地址表示 sbit CY=0xd7;//定義CY位地址為0xd7,即PSW.735使用頭文件,再直接用位名稱 #include<STC12C5A.h> TR0=1;EA=1;TF0=0;//在文件中已定義了TR0、EA、 TF0……等位使用頭文件及sbit定義符,用于無位名稱的可位尋址位。 #include<STC12C5A.h> sbit P1_0=P1^0; sbit a_7=ACC^7;

由于在51內(nèi)核單片機(jī)產(chǎn)品中特殊功能寄存器的數(shù)量和類型不盡相同,C51建立了一個(gè)頭文件reg51.h(增強(qiáng)型為reg52.h),STC系列單片機(jī)的頭文件有STC90.h、STC10.h、STC11.h、STC12C5A.h、STC12C52.h、STC12C54.h、STC12C56.h、STC15.h、STC89.h等。36 在這些頭文件中對相應(yīng)系列的所有特殊功能寄存器進(jìn)行了sfr定義,對特殊功能寄存器中有位名稱并且可位尋址位進(jìn)行了sbit定義,只要使用了#include<STC12C5A.h>或#include<reg52.h>等包含語句,就可以直接引用該文件中已經(jīng)定義過的特殊功能寄存器名及位名稱。注意:在引用特殊功能寄存器名及位名稱時(shí)必須大寫。我們也可以用自己喜歡的名字寫定義文件,使用時(shí)只要用包含語句#include“****.h”就可以直接引用已定義的特殊功能寄存器名和位名稱。37程序如下:#include<STC12C5A.h>sbitP1_0=P1^0;voidmain(){ P1_0=0;while(1);}【例5-3】利用STC12C5A60S2單片機(jī)P1口的P1.0引腳接一只LED燈,如圖5-2所示。要求一直點(diǎn)亮。

382.對一般位變量的定義

在C51中,經(jīng)常用位變量標(biāo)記某些事件的狀態(tài),如標(biāo)記某電機(jī)的停與轉(zhuǎn)等。位變量的地址位于片內(nèi)RAM的可位尋址區(qū)(20H-2FH單元),用戶通過位類型符定義位變量。

格式如下:

bit

位變量名[=初值];//其地址可由C51編譯器編譯時(shí)自動分配

sbit

位變量名=位地址;//定義時(shí)直接確定其地址在格式中可以加上各種修飾,但注意存儲器類型只能是bdata、data、idata。只能是片內(nèi)RAM的可位尋址區(qū),嚴(yán)格來說只能是bdata。39bitdataa1;bitbdataa2;bitxdataa4; 【例5-4】判斷以下定義是否正確。

//正確,a1的位地址由C51編譯器自行安排在bdata區(qū)//正確,a2的位地址由C51編譯器自行安排在bdata區(qū)//錯(cuò)誤【例5-5】用sbit定義一般位變量。

charbdatatemp;//在位尋址區(qū)定義一個(gè)字符型變量tempsbitbit7=temp^7;//bit7定義為temp的第7位bit7=0; //位尋址,將temp的第7位置0403.說明bit型位變量與其它變量一樣,可以作為函數(shù)的形參,也可以作為函數(shù)的返回值;位變量不能定義指針,不能定義數(shù)組。用sbit定義的位變量,必須能夠按位操作,而不能夠?qū)o位操作功能的位定義位變量。用sbit定義位變量,必須放在函數(shù)外面作為全局位變量,而不能在函數(shù)內(nèi)部定義。用sbit每次只能定義一個(gè)位變量。對其它模塊定義的位變量(bit型或sbit型)的引用聲明,都使用bit。41【例5-6】指出下面程序中各語句的作用。

#include<STC12C5A.h>unsignedcharbdatadata1;//在位尋址區(qū)定義字節(jié)變量data1sbitlsb=data1^0; //定義位變量lsb為data1的最低位sbitmsb=data1^7;//定義位變量msb為data1的最高位voidmain(void){bitflag=1; //定義局部位變量flag,并賦初值為1data1=‘A’; //給字節(jié)變量data1賦值while(1){flag=!flag; //位變量flag取反msb=flag; //將flag的值賦給msblsb=flag; //將flag的值賦給lsbP1=data1; //將data1變量通過P1口輸出}}425.3.3C51對存儲器和外部I/O接口的絕對地址訪問在具有外部I/O接口電路的應(yīng)用中,外部接口電路的地址是由硬件電路確定的,以變量形式對其訪問時(shí),必須事先指定變量在系統(tǒng)中的絕對地址;也有一些變量需要明確在存儲器中的具體地址,而不是讓編譯程序自行分配。對這些變量的訪問就是對絕對地址訪問。下面介紹使用宏定義、關(guān)鍵字_at_以及指針來訪問絕對地址。431.使用宏定義訪問絕對地址這些宏定義的函數(shù)原型所在頭文件為absacc.h。定義絕對地址變量的格式如下: #include<absacc.h> #define變量名

CBYTE[絕對地址] #define變量名DBYTE[絕對地址] #define變量名PBYTE[絕對地址] #define變量名XBYTE[絕對地址] #define變量名

CWORD[絕對地址] #define變量名

DWORD[絕對地址] #define變量名PWORD[絕對地址] #define變量名

XWORD[絕對地址]441.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址]CBYTE指定絕對地址在單片機(jī)程序存儲器中的字節(jié)變量;451.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址]

#define變量名DBYTE[絕對地址]DBYTE指定絕對地址在單片機(jī)片內(nèi)RAM中字節(jié)變量;461.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址] #define變量名DBYTE[絕對地址]

#define變量名PBYTE[絕對地址]

PBYTE指定絕對地址在單片機(jī)片內(nèi)擴(kuò)展RAM或片外RAM低256B中的字節(jié)變量;471.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址] #define變量名DBYTE[絕對地址] #define變量名PBYTE[絕對地址]

#define變量名XBYTE[絕對地址]

XBYTE指定絕對地址在單片機(jī)片內(nèi)擴(kuò)展RAM或片外RAM中的字節(jié)變量;481.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址] #define變量名DBYTE[絕對地址] #define變量名PBYTE[絕對地址] #define變量名XBYTE[絕對地址]

#define變量名CWORD[絕對地址]

CWORD指定絕對地址在單片機(jī)程序存儲器中的字變量,該字變量的低地址為中括號中的數(shù)乘2;491.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址] #define變量名DBYTE[絕對地址] #define變量名PBYTE[絕對地址] #define變量名XBYTE[絕對地址] #define變量名

CWORD[絕對地址]

#define變量名DWORD[絕對地址]

DWORD指定絕對地址在單片機(jī)片內(nèi)RAM中的字變量,該字變量的低地址為中括號中的數(shù)乘2;501.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址] #define變量名DBYTE[絕對地址] #define變量名PBYTE[絕對地址] #define變量名XBYTE[絕對地址] #define變量名

CWORD[絕對地址] #define變量名

DWORD[絕對地址]

#define變量名PWORD[絕對地址]

PWORD指定絕對地址在單片機(jī)片內(nèi)擴(kuò)展RAM或片外RAM低256B中的字變量,該字變量的低地址為中括號中的數(shù)乘2;511.使用宏定義訪問絕對地址 #define變量名

CBYTE[絕對地址] #define變量名DBYTE[絕對地址] #define變量名PBYTE[絕對地址] #define變量名XBYTE[絕對地址] #define變量名

CWORD[絕對地址] #define變量名

DWORD[絕對地址] #define變量名PWORD[絕對地址]

#define變量名XWORD[絕對地址]

XWORD指定絕對地址在單片機(jī)片內(nèi)擴(kuò)展RAM或片外RAM中的字變量,該字變量的低地址為中括號中的數(shù)乘2;52CBYTE、DBYTE、PBYTE、XBYTE、CWORD、DWORD、PWORD和XWORD為8個(gè)宏名。也可以不使用宏定義的方法,直接使用這些宏名進(jìn)行絕對地址的訪問。訪問形式如下:

宏名[絕對地址]【例5-7】使用宏定義的方法訪問片外并行I/O口或存儲單元。

#include<absacc.h>#definePAXBYTE[0xfffe]/*PA定義為地址為0xfffe的字節(jié)變量*/voidmain(){PA=0xFF;/*將數(shù)據(jù)FFH寫入地址為0xfffe的I/O端口或存儲單元*/}53【例5-8】使用宏名訪問存儲器。#include<absacc.h>//將絕對地址頭文件包含在文件中#defineucharunsignedchar#defineuintunsignedintvoidmain(void){ ucharvar1; uintvar2; var1=XBYTE[0x0003]; var2=XWORD[0x0002];/*讀片內(nèi)擴(kuò)展RAM的0004H-0005H字單元的數(shù)據(jù)賦給變量var2*/ XBYTE[0x0003]=0x7f; XWORD[0x0002]=0x7fff;/*將數(shù)據(jù)0x7fff寫入片內(nèi)擴(kuò)展RAM的0004H-0005H地址中*/while(1);}542.使用關(guān)鍵字_at_訪問絕對地址 [存儲器類型]數(shù)據(jù)類型變量名_at_地址常數(shù);存儲器類型為data、bdata、idata、pdata等;地址常數(shù)用于指定變量的絕對地址,必須位于有效的存儲器空間之內(nèi);這種變量定義時(shí)不能初始化。55說明:不能對code型變量絕對定位;絕對地址變量必須是全局變量,不能在函數(shù)中對變量絕對定位;絕對地址變量多用于I/O端口,一般情況下不對變量作絕對定位;函數(shù)和bit型變量不能使用_at_絕對定位?!纠?-9】使用關(guān)鍵字_at_實(shí)現(xiàn)絕對地址的訪問

。

#defineucharunsignedchar#defineuintunsignedintdataucharx1_at_0x40;xdatauintx2_at_0x2000;voidmain(void){x1=0xff;

x2=0x1234;

......}563.使用指針訪問絕對地址【例5-10】通過指針實(shí)現(xiàn)絕對地址的訪問。 #defineucharunsignedchar #defineuintunsignedint voidfunc( ) { uchardatavar1; ucharpdata*dp1; uintxdata*dp2; uchardata*dp3; dp1=0x30;

dp2=0x1000; *dp1=0xff;

*dp2=0x1234;

dp3=&var1; *dp3=0x20; }575.4C51的運(yùn)算符1.賦值運(yùn)算符 賦值運(yùn)算符的作用是將“=”右邊的數(shù)據(jù)(常量或表達(dá)式)賦給左邊的變量。2.算術(shù)運(yùn)算符 基本算術(shù)運(yùn)算符有:+(加或正號)、-(減或負(fù)號)、*(乘號)、/(除號)、%(求余)。 優(yōu)先級為:先乘除,后加減,先括號內(nèi),再括號外。3.關(guān)系運(yùn)算符 關(guān)系運(yùn)算符有:<(小于)、<=(小于等于)、>(大于)、>=(大于等于)、==(相等)、!=(不相等) 優(yōu)先級:前四個(gè)高,后兩個(gè)低。584.邏輯運(yùn)算符 邏輯運(yùn)算符共有三種:!(邏輯非)、&&(邏輯與)、||(邏輯或),邏輯表達(dá)式和關(guān)系表達(dá)式都是以0代表假,以1代表真。5.位操作運(yùn)算符 C51支持的位操作運(yùn)算符有:&(按位與)、|(按位或)、^(按位異或)、~(按位取反)、<<(位左移)、>>(位右移)

需要說明的是:無符號數(shù)的右移運(yùn)算是高端移入0,低端移出舍掉。有符號數(shù)的右移運(yùn)算是高端移入操作數(shù)的符號位,低端移出位被舍掉。

例如:signedchara=-2,b; b=a>>1; 執(zhí)行結(jié)果為b=0xff。因?yàn)閍為負(fù)數(shù),以其補(bǔ)碼形式出現(xiàn),即a=0xfe,右移一位,各位依次右移一位,最高位移入符號位1,最低位移出舍掉,則b為0xff。596.自增、自減運(yùn)算符自增(++)、自減(--)運(yùn)算符的作用是使變量值加1或減1。包括前置和后置兩種形式:前置++i,--i(先執(zhí)行i+1或i-1,再使用i值)后置i++,i--(先使用i值,再執(zhí)行i+1或i-1)例如:j=3;k=++j; //執(zhí)行后k=4,j=4 j=3;k=j++; //執(zhí)行后k=3,j=4607.復(fù)合賦值運(yùn)算符 復(fù)合賦值運(yùn)算符有+=-=*=/=%=<<=>>=&=^=|= 例如:a+=3相當(dāng)于a=a+3,a*=b相當(dāng)于a=a*b;8.條件運(yùn)算符 一般形式:表達(dá)式1?表達(dá)式2:表達(dá)式3 功能:首先判斷表達(dá)式1是否成立,如果表達(dá)式1成立,則整個(gè)表達(dá)式的值為表達(dá)式2的值,否則為表達(dá)式3的值。 例如:(x%2==1)?1:0; //首先判斷x%2==1是否成立,即x如果是奇數(shù)則結(jié)果為1,否則結(jié)果為09.逗號運(yùn)算符 形式:表達(dá)式1,表達(dá)式2,……表達(dá)式n 逗號表達(dá)式的值等于表達(dá)式n的值6110.對指針操作的運(yùn)算符

&――取地址運(yùn)算符,*――取內(nèi)容運(yùn)算符例如:

unsignedchara,b,*p; p=&b;//取變量b的地址賦給指針變量p a=*p;//取指針變量p所指向的地址中的內(nèi)容(即變量b的內(nèi)容)賦給變量a表5-7列出了C語言中運(yùn)算符的優(yōu)先級及結(jié)合規(guī)則。62優(yōu)先級運(yùn)算符名稱或含義使用形式結(jié)合規(guī)則1[]數(shù)組下標(biāo)數(shù)組名[常量表達(dá)式]自左向右()圓括號(表達(dá)式)/函數(shù)名(形參表).成員選擇(對象)對象.成員名→成員選擇(指針)對象指針→成員名2-負(fù)號運(yùn)算符-表達(dá)式自右向左(類型)強(qiáng)制類型轉(zhuǎn)換(數(shù)據(jù)類型)表達(dá)式++自增運(yùn)算符++變量名/變量名++--自減運(yùn)算符--變量名/變量名--*取值運(yùn)算符*指針變量&取地址運(yùn)算符&變量名!邏輯非運(yùn)算符!表達(dá)式~按位取反運(yùn)算符~表達(dá)式sizeof長度運(yùn)算符sizeof(表達(dá)式)3*乘表達(dá)式*表達(dá)式自左向右/除表達(dá)式/表達(dá)式%取余整型表達(dá)式%整型表達(dá)式4+加表達(dá)式+表達(dá)式自左向右-減表達(dá)式-表達(dá)式5<<左移變量<<表達(dá)式自左向右>>右移變量>>表達(dá)式6>大于表達(dá)式>表達(dá)式自左向右>=大于等于表達(dá)式>=表達(dá)式<小于表達(dá)式<表達(dá)式<=小于等于表達(dá)式<=表達(dá)式7==等于表達(dá)式==表達(dá)式自左向右!=不等于表達(dá)式!=表達(dá)式8&按位與表達(dá)式&表達(dá)式自左向右9^按位異或表達(dá)式^表達(dá)式自左向右10|按位或表達(dá)式|表達(dá)式自左向右11&&邏輯與表達(dá)式&&表達(dá)式自左向右12||邏輯或表達(dá)式||表達(dá)式自左向右13?:條件運(yùn)算符表達(dá)式1?表達(dá)式2:表達(dá)式3自左向右14=賦值運(yùn)算符變量=表達(dá)式自右向左*=乘后賦值變量*=表達(dá)式/=除后賦值變量/=表達(dá)式%=取余后賦值變量%=表達(dá)式+=加后賦值變量+=表達(dá)式-=減后賦值變量-=表達(dá)式<<=左移后賦值變量<<=表達(dá)式>>=右移后賦值變量>>=表達(dá)式&=按位與后賦值變量&=表達(dá)式^=按位異或后賦值變量^=表達(dá)式|=按位或后賦值變量|=表達(dá)式15,逗號運(yùn)算符表達(dá)式,表達(dá)式…自左向右635.5

C51的指針指針是C語言中的一個(gè)重要概念。正確地使用指針類型數(shù)據(jù),可以有效地表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu),可以動態(tài)地分配存儲器,直接處理內(nèi)存地址,使程序精簡、靈活、高效。這里介紹指針的基本概念,以及C51相對標(biāo)準(zhǔn)C語言對指針的擴(kuò)展。變量的指針就是該變量的地址,專門用于提供另一個(gè)變量地址的變量就是指針變量。指針變量必須先定義后使用。指針變量定義的一般形式為:

數(shù)據(jù)類型[存儲器類型1]*[存儲器類型2]標(biāo)識符;64“數(shù)據(jù)類型”是指該指針變量所指向?qū)ο蟮臄?shù)據(jù)類型;“存儲器類型1”和“存儲器類型2”是可選項(xiàng),“存儲器類型1”是指針變量所指向的數(shù)據(jù)存儲空間區(qū)域,“存儲器類型2”是指針變量本身所在的存儲器的空間區(qū)域?!皹?biāo)識符”是所定義的指針變量名。根據(jù)是否有“存儲器類型1”選項(xiàng),C51中指針變量可以分為通用指針變量和存儲器專用指針變量。數(shù)據(jù)類型[存儲器類型1]*[存儲器類型2]標(biāo)識符;651.通用指針變量

不選用“存儲器類型1”選項(xiàng)的指針變量稱為通用指針變量;其聲明和標(biāo)準(zhǔn)C語言一樣。例如: char*s; //s為指向char型數(shù)據(jù)的指針變量

int*xdatap; //p為指向int型數(shù)據(jù)的指針變量,而p本 身放于xdata區(qū)通過它可以很方便地訪問存儲空間任何位置的變量,因而許多庫函數(shù)都使用通用指針變量。它的缺點(diǎn)是速度慢。通用指針變量需要3個(gè)字節(jié)來存儲。第一個(gè)字節(jié)用來表示存儲器類型,存儲器類型的編碼值如表5-8所示。第二個(gè)字節(jié)是指針的高字節(jié),第三個(gè)字節(jié)是指針的低字節(jié)。表5-8存儲器類型的編碼值存儲器類型idata/bdata/dataxdatapdatacode編碼值0x000x010xfe0xff662.存儲器專用指針變量選用“存儲器類型1”選項(xiàng)的指針變量稱為存儲器專用指針變量。通過該類指針變量,只能夠訪問規(guī)定的存儲空間區(qū)域。當(dāng)存儲器類型為idata、data、pdata時(shí)指針變量長度為1個(gè)字節(jié),當(dāng)存儲器類型為xdata或code時(shí)指針變量長度為2個(gè)字節(jié)。使用存儲器專用指針變量比通用指針變量的效率高,速度快,但必須保證指針變量不指向所聲明的存儲區(qū)以外的地方,否則會產(chǎn)生錯(cuò)誤。67【例5-11】指出下列指針定義的作用。chardata*p1;/*p1指向data區(qū)的字符型數(shù)據(jù),p1本身存放于默認(rèn)存儲區(qū),該指針變量在內(nèi)存中占1個(gè)字節(jié)*/unsignedcharpdata*xdatap2;/*p2指向pdata區(qū)的無符號字符型數(shù)據(jù),p2本身存放于xdata區(qū),該指針變量在內(nèi)存中占1個(gè)字節(jié)*/unsignedintcode*datap3;/*p3指向code區(qū)的無符號整型數(shù)據(jù),p3本身存放于data區(qū),該指針變量在內(nèi)存中占2個(gè)字節(jié)*/685.6C51的函數(shù)1.C51函數(shù)的定義

一般定義格式如下:

返回值類型函數(shù)名(形參表)[reentrant][interruptm][usingn]

{ 局部變量定義 執(zhí)行語句 }reentrant:表示該函數(shù)為可重入函數(shù)。所謂可重入函數(shù),就是允許被遞歸調(diào)用的函數(shù)。是C51定義的關(guān)鍵字。interrupt:是C51定義的關(guān)鍵字,中斷函數(shù)必須通過它進(jìn)行修飾。m代表中斷號。using:是定義工作寄存器組所用的關(guān)鍵字。n為工作寄存器組號。692.函數(shù)的調(diào)用函數(shù)調(diào)用的一般形式如下:

函數(shù)名(實(shí)參列表)對于有參數(shù)的函數(shù)調(diào)用,若實(shí)參列表包含多個(gè)實(shí)參,則各個(gè)實(shí)參之間用逗號隔開。按照函數(shù)調(diào)用在主調(diào)函數(shù)中出現(xiàn)的位置,函數(shù)調(diào)用方式有以下三種: (1)函數(shù)語句。把被調(diào)用函數(shù)作為主調(diào)用函數(shù)的一個(gè)語句(2)函數(shù)表達(dá)式。函數(shù)被放在一個(gè)表達(dá)式中,以一個(gè)運(yùn)算對象的方式出現(xiàn)。這時(shí)的被調(diào)用函數(shù)要求帶有返回語句,以返回一個(gè)明確的數(shù)值參加表達(dá)式的運(yùn)算。 (3)函數(shù)參數(shù)。被調(diào)用函數(shù)作為另一個(gè)函數(shù)的參數(shù)。703.自定義函數(shù)的聲明函數(shù)必須先定義后使用,如果函數(shù)的定義在調(diào)用語句之后或調(diào)用的函數(shù)不在本文件內(nèi)部而在其他文件中,則在調(diào)用之前需對函數(shù)進(jìn)行聲明。在C51中,函數(shù)原型一般形式如下:

[extern]函數(shù)類型函數(shù)名(形式參數(shù)表);函數(shù)的聲明是把函數(shù)的名字、函數(shù)類型以及形參的類型、個(gè)數(shù)和順序通知編譯系統(tǒng),以便調(diào)用函數(shù)時(shí)系統(tǒng)進(jìn)行對照檢查。函數(shù)的聲明后面要加分號。如果聲明的函數(shù)在文件內(nèi)部,則聲明時(shí)不用extern,如果聲明的函數(shù)不在文件內(nèi)部,而在另一個(gè)文件中,聲明時(shí)須帶extern,指明使用的函數(shù)在另一個(gè)文件中。714.可重入函數(shù)可重入函數(shù)是一種可以在函數(shù)體內(nèi)間接調(diào)用其自身的函數(shù)。對于一個(gè)函數(shù),如果需要遞歸調(diào)用,應(yīng)將它定義為可重入函數(shù);非中斷服務(wù)程序和中斷服務(wù)程序中都要調(diào)用,同樣應(yīng)將它定義為可重入函數(shù)。一般的函數(shù)不能這樣做。使用reentrant修飾符時(shí)需注意以下幾點(diǎn):(1)用reentrant修飾的可重入函數(shù)被調(diào)用時(shí),實(shí)參表內(nèi)不允許使用bit類型的參數(shù)。函數(shù)體內(nèi)也不允許出現(xiàn)任何關(guān)于位變量的操作,更不能返回bit類型的值。(2)編譯時(shí),系統(tǒng)為重入函數(shù)在內(nèi)部或擴(kuò)展存儲器中建立一個(gè)模擬堆棧區(qū),稱為重入棧。重入函數(shù)的局部變量及參數(shù)被放在重入棧中,使重入函數(shù)可以實(shí)現(xiàn)遞歸調(diào)用。725.寄存器組的定義修飾符usingn用于指定本函數(shù)內(nèi)部使用的工作寄存器組,其中n的取值為0-3,表示寄存器組號,對應(yīng)第0組到第3組。當(dāng)函數(shù)有返回值時(shí),不能使用該屬性,因?yàn)榉祷刂凳谴嬗诩拇嫫髦?,函?shù)返回時(shí)要恢復(fù)原來的寄存器組,導(dǎo)致返回值錯(cuò)誤?!纠?-12】有一個(gè)延時(shí)函數(shù),在程序中多處被調(diào)用,包括中斷服務(wù)程序。請將其定義為可重入函數(shù)。

voiddelay()reentrant { inti; for(i=0;i<20000;i++); }736.中斷函數(shù)中斷函數(shù)也稱作中斷服務(wù)程序,是CPU在響應(yīng)中斷后要執(zhí)行的一段程序。編寫中斷函數(shù)時(shí),只需關(guān)心中斷類型號和寄存器組的選擇,編譯程序會自動安排中斷函數(shù)在存儲器中的位置及中斷返回地址的入棧及出棧任務(wù)。C51支持32個(gè)中斷源,即m的取值為0-31,中斷入口地址與中斷號m的關(guān)系:

中斷入口地址=3+8×m74編寫51中斷函數(shù)注意如下:中斷函數(shù)不能進(jìn)行參數(shù)傳遞。中斷函數(shù)沒有返回值,返回值類型應(yīng)為void類型。在任何情況下都不能直接調(diào)用中斷函數(shù)。如果在中斷函數(shù)中調(diào)用了其它函數(shù),則被調(diào)用函數(shù)所使用的寄存器必須與中斷函數(shù)相同。在中斷函數(shù)中調(diào)用其它函數(shù),被調(diào)函數(shù)最好設(shè)置為可重入的。C51編譯器對中斷函數(shù)編譯時(shí)會自動在程序開始和結(jié)束處加上相應(yīng)的內(nèi)容,具體如下:在程序開始處對ACC、B、DPH、DPL和PSW入棧,結(jié)束時(shí)出棧。中斷函數(shù)未加usingn修飾符的,開始時(shí)還要將R0-R1入棧,結(jié)束時(shí)出棧。如中斷函數(shù)加usingn修飾符,則在開始將PSW入棧后還要修改PSW中的工作寄存器組選擇位。中斷函數(shù)最好寫在文件的尾部,并且禁止使用extern存儲類型說明。75【例5-13】編寫統(tǒng)計(jì)定時(shí)/計(jì)數(shù)器T1中斷次數(shù)的函數(shù)。

unsignedintinterruptcnt; //中斷次數(shù)計(jì)數(shù)器voidtimer1()interrupt3

using2{ interruptcnt++;}7.內(nèi)部函數(shù)C51軟件包的庫包含許多標(biāo)準(zhǔn)的應(yīng)用程序,也稱為庫函數(shù),如果要使用某一庫函數(shù),必須在源程序中用預(yù)處理命令定義與該函數(shù)相關(guān)的頭文件。下面介紹頭文件為intrins.h的內(nèi)部函數(shù)。內(nèi)部函數(shù)也稱為本征函數(shù),共有9種函數(shù),數(shù)目雖少,但都常用。76(1)循環(huán)左移內(nèi)部函數(shù)函數(shù)名:_crol_

函數(shù)原型:unsignedchar_crol_(unsignedchara,unsignedcharn);

函數(shù)功能:將無符號字符型變量a,循環(huán)左移n位。函數(shù)名:_irol_

函數(shù)原型:unsignedint_irol_(unsignedinta,unsignedintn);

函數(shù)功能:將無符號整型變量a,循環(huán)左移n位。函數(shù)名:_lrol_

函數(shù)原型:unsignedlong_lrol_(unsignedlonga,unsignedlongn);

函數(shù)功能:將無符號長整型變量a,循環(huán)左移n位。77以上三種函數(shù)的不同之處在于變量的類型和返回值的類型不一樣。它們在執(zhí)行循環(huán)左移時(shí)都是最高位循環(huán)到最低位,與匯編指令RLA相似。例如:

P1=0xEE;

P1=_crol_(P1,1);

P1的初始狀態(tài)為11101110,執(zhí)行1次循環(huán)左移語句之后P1的狀態(tài)為11011101,執(zhí)行2次后P1變成10111011。78(2)循環(huán)右移內(nèi)部函數(shù)函數(shù)名:_cror_

函數(shù)原型:unsignedchar_cror_(unsignedchara,unsignedcharn);

函數(shù)功能:將無符號字符型變量a,循環(huán)右移n位。函數(shù)名:_iror_

函數(shù)原型:unsignedint_iror_(unsignedinta,unsignedintn);

函數(shù)功能:將無符號整型變量a,循環(huán)右移n位。函數(shù)名:_lror_

函數(shù)原型:unsignedlong_lror_(unsignedlonga,unsignedlongn);

函數(shù)功能:將無符號長整型變量a,循環(huán)右移n位。79以上三種函數(shù)的不同之處在于變量的類型和返回值的類型不一樣。它們在執(zhí)行循環(huán)右移時(shí)都是最低位循環(huán)到最高位,與匯編指令RRA相似。例如:

P1=0xEE;

P1=_cror_(P1,1);

P1的初始狀態(tài)為11101110,執(zhí)行1次循環(huán)右移語句之后P1的狀態(tài)為01110111,執(zhí)行2次后P1變成10111011(3)其他內(nèi)部函數(shù)函數(shù)名:_nop_

函數(shù)原型:void_nop_(void);

函數(shù)功能:產(chǎn)生一條NOP空指令,執(zhí)行一次空操作。80函數(shù)名:_testbit_

函數(shù)原型:bit_testbit_(bitx);

函數(shù)功能:產(chǎn)生一條JBC指令。該函數(shù)測試一個(gè)位,如果該位為1,則將該位清0,并且返回值為1,否則返回值為0。例如:

if(_testbit_(RI))a=SBUF;//若RI=1,則清0,并讀SBUF函數(shù)名:_chkfloat_

函數(shù)原型:unsignedchar_chkfloat_(floatx);

函數(shù)功能:檢查浮點(diǎn)型變量x的狀態(tài),返回值為無符號字符型數(shù)據(jù),其值可以為0,1,2,3,4。81返回值意義:0——標(biāo)準(zhǔn)浮點(diǎn)數(shù);1——浮點(diǎn)數(shù)0;2——+INF正溢出;3——-INF負(fù)溢出;4——NaN該數(shù)為非法數(shù)據(jù)的錯(cuò)誤狀態(tài)。【例5-14】編寫程序段,若位變量flag值為1,則8位數(shù)據(jù)data8右移兩位并將flag清0;否則左移3位。

程序段如下:

if(_testbit_(flag)) data8=_cror_(data8,2); else data8=_crol_(data8,3);82【例5-15】_chkfloat_函數(shù)的應(yīng)用舉例。

#include<intrins.h>voidexm(floatf1,floatf2){ floatf3; f3=f2*f1; switch(_chkfloat_(f3)) { case0:printf(“resultisanumber\n”);break; case1:printf(“resultisazero\n”);break; case2:printf(“resultis+INF\n”);break; case3:printf(“resultis-INF\n”);break; case4:printf(“resultisNaN\n”);break; }}838.C51的輸入/輸出函數(shù)C51語言本身未提供輸入和輸出語句,輸入和輸出操作是通過函數(shù)實(shí)現(xiàn)的。在C51的函數(shù)庫中提供了一個(gè)名為“stdio.h”的標(biāo)準(zhǔn)I/O函數(shù)庫,其中包含了輸入輸出函數(shù)。當(dāng)使用輸入和輸出函數(shù)時(shí),需先用預(yù)處理命令“#include<stdio.h>”將該函數(shù)包含到文件中。本小節(jié)主要介紹格式輸入及輸出函數(shù)scanf()和printf(),其它函數(shù)說明見附錄B。84格式輸出函數(shù)printf

函數(shù)功能:通過單片機(jī)的串行口輸出若干任意類型的數(shù)據(jù)。格式: printf(格式控制,輸出參數(shù)表) 格式控制是用雙引號括起來的字符串,它包括三種信息:格式說明符、普通字符、轉(zhuǎn)義字符。 1)格式說明符:由百分號“%”和格式字符組成,其作用是指明輸出數(shù)據(jù)的格式,如%d、%c、%s等,詳細(xì)情況見表5-9。85表5-9printf()函數(shù)的格式字符格式字符數(shù)據(jù)類型輸出格式dint有符號十進(jìn)制數(shù)uint無符號十進(jìn)制數(shù)oint無符號八進(jìn)制數(shù)x,Xint無符號十六進(jìn)制數(shù)ffloat十進(jìn)制浮點(diǎn)數(shù)e,Efloat科學(xué)計(jì)數(shù)法的十進(jìn)制浮點(diǎn)數(shù)g,Gfloat自動選擇e或f格式cchar單個(gè)字符s指針帶結(jié)束符的字符串86格式輸出函數(shù)printf

函數(shù)功能:通過單片機(jī)的串行口輸出若干任意類型的數(shù)據(jù)。格式: printf(格式控制,輸出參數(shù)表) 格式控制是用雙引號括起來的字符串,它包括三種信息:格式說明符、普通字符、轉(zhuǎn)義字符。 1)格式說明符:由百分號“%”和格式字符組成,其作用是指明輸出數(shù)據(jù)的格式,如%d、%c、%s等,詳細(xì)情況見表5-9。 2)普通字符:這些字符按原樣輸出,主要用來輸出一些提示信息。 3)轉(zhuǎn)義字符:由“\”和字母或字符組成,它的作用是輸出特定的控制符,如轉(zhuǎn)義字符\n的含義是輸出換行,詳細(xì)情況見表5-5。87表5-5常用的轉(zhuǎn)義字符轉(zhuǎn)義字符含義ASCII碼\0空字符0x00\n換行符0x0a\r回車符0x0d\t水平制表0x09\b退格符0x08\f換頁符0x0c\’單引號0x27\”雙引號0x22\\反斜杠0x5c88舉例用printf函數(shù)輸出(假設(shè)y已經(jīng)定義并賦值):printf(“x=%d”,36)

;//從串行口輸出x=36printf(“y=%d”,y)

;//從串行口輸出y=y變量的值printf(“c1=%c,c2=%c”,‘A’,‘B’); //從串行口輸出 //c1=A,c2=Bprintf(“%s\n”,“OK,Senddatabegin!”)

;//從串行口輸出 //

OK,Senddatabegin!換行89格式輸入函數(shù)scanf函數(shù)功能:通過單片機(jī)串行口實(shí)現(xiàn)各種數(shù)據(jù)輸入。格式: scanf(格式控制,地址列表) 格式控制與printf函數(shù)類似,也是用雙引號括起來的一些字符,包括三種信息:格式說明符、普通字符和空白字符。 1)格式說明符:由百分號“%”和格式字符組成,其作用是指明輸入數(shù)據(jù)的格式,見表5-9。 2)普通字符:在輸入時(shí),要求這些字符按原樣輸入。 3)空白字符:包括空格、制表符和換行符等,這些字符在輸入時(shí)可被忽略。地址列表:接收到的數(shù)據(jù)應(yīng)保存在存儲器中的位置,是由若干個(gè)地址組成,它可以是指針變量、變量的地址、數(shù)組名、數(shù)組元素地址或字符串首地址等。90用scanf函數(shù)輸入舉例(假設(shè)x、y、z、c1、c2是定義過的變量,str1是定義過的指針變量):scanf(“%d%d”,&y,&z);//以十進(jìn)制形式分別輸入變量y和z的值scanf(“%c%c”,&c1,&c2);//以字符形式分別輸入變量c1和c2的值scanf(“%s”,str1);/*輸入字符串,該字符串存入以指針變量str1所指向的位置為首地址的內(nèi)存單元*/注意:在C51的I/O函數(shù)庫中定義的I/O函數(shù),都是通過串行口實(shí)現(xiàn)的。如果使用I/O函數(shù),必需對串行口初始化,如初始化串行口的工作方式、波特率等。91假設(shè)單片機(jī)的系統(tǒng)時(shí)鐘頻率為11.0592MHz,波特率為9600bps,則初始化程序段為:

SCON=0x50; //設(shè)置串行口工作在方式1,允許接收

PCON&=0x7f

; //PCON寄存器中的SMOD位清0,即波 //特率不加倍

AUXR&=0xbf

; //定時(shí)/計(jì)數(shù)器T1的計(jì)數(shù)脈沖為系統(tǒng)時(shí)鐘 //的12分頻

TMOD=0x20; //定時(shí)/計(jì)數(shù)器T1工作在方式2,作為波 特率發(fā)生器

TL1=0xfd; //寫入T1低8位初值

TH1=0xfd; //寫入T1自動重裝初值

TR1=1; //T1開始工作92【例5-16】說明以下程序段的運(yùn)行結(jié)果。#include<STC12C5A.h> #include<stdio.h> voidmain(void) { intx,y

;

SCON=0x50

;

PCON&=0x7f

;

AUXR&=0xbf

;

TMOD&=0xef

TMOD

|=0x20

; TH1=0xfd

;

TR1=1

;

while(1){scanf(“%d%d

”,&x,&y);printf(“x=%04X,y=%04X\n

”,x,y);}//域?qū)挒?

}該程序的功能是接收用戶輸入的十進(jìn)制數(shù)值,然后從串行口以十六進(jìn)制格式輸出。

935.7

C51流程控制5.7.1分支語句1.if語句if語句用來判定所給的條件是否滿足決定執(zhí)行的順序。if語句有以下3種形式。(1)if(表達(dá)式){語句;}(2)if(表達(dá)式){語句1;} else{語句2;}(3)if(表達(dá)式1){語句1;} elseif(表達(dá)式2){語句2;} elseif(表達(dá)式3){語句3;} …… elseif(表達(dá)式n-1){語句n-1;}else{語句n;}94【例5-17】片內(nèi)RAM的20H單元存放一個(gè)帶符號變量X,變量Y與X有如下關(guān)系式:

由X求出Y并存放于21H單元。

voidread_x(){ charx,*p1,*p2; p1=0x20; p2=0x21; x=*p1; if(x>0)*p2=x; //如果x>0,則y=x elseif(x==0)*p2=0x05;//如果x=0,則y=0x05 else*p2=x+5; //其它情況,即x<0,則y=x+5}952.switch語句switch語句是直接處理多分支的選擇語句,一般格式為:

switch(表達(dá)式)

{ case常量表達(dá)式1:語句組1;break;

case常量表達(dá)式2:語句組2;break;

…… case常量表達(dá)式n:語句組n;break;

default: 語句組n+1;break; }switch后的表達(dá)式可以是整型、字符型或枚舉型數(shù)據(jù),case后的各常量表達(dá)式需與其類型相同或者可以相互轉(zhuǎn)換。96【例5-18】有兩個(gè)變量x和y,根據(jù)寄存器R3的內(nèi)容轉(zhuǎn)向運(yùn)行不同的處理函數(shù):

R3=0,執(zhí)行函數(shù)opr0(完成兩數(shù)相加);

R3=1,執(zhí)行函數(shù)opr1(完成兩數(shù)相減);

R3=2,執(zhí)行函數(shù)opr2(完成兩數(shù)相乘);

R3=3,執(zhí)行函數(shù)opr3(完成兩數(shù)相除)。分析:(1)需要4個(gè)函數(shù)分別實(shí)現(xiàn)4種功能;(2)在C51編譯器中,通過頭文件STC12C5A.h等可以識別特殊功能寄存器,但不能識別通用寄存器,因此R0-R7只有通過絕對地址訪問識別。97程序如下: #include<absacc.h> #definer3DBYTE[0x03] intx,y,z; voidopr0() {z=x+y;} voidopr1() {z=x-y;} voidopr2() {z=x*y;} voidopr3() {z=x/y;}voidopr(){ x=34

;y=26

; switch(r3) {

case0

:op

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論