單片機(jī)的C語言應(yīng)用程序設(shè)計(jì)_第1頁
單片機(jī)的C語言應(yīng)用程序設(shè)計(jì)_第2頁
單片機(jī)的C語言應(yīng)用程序設(shè)計(jì)_第3頁
單片機(jī)的C語言應(yīng)用程序設(shè)計(jì)_第4頁
單片機(jī)的C語言應(yīng)用程序設(shè)計(jì)_第5頁
已閱讀5頁,還剩98頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、單片機(jī)的C語言應(yīng)用程序設(shè)計(jì) 7.1 C語言與MCS-517.2 C51數(shù)據(jù)類型及在MCS-51中的存儲方式7.3 C51數(shù)據(jù)的存儲類型與MCS-51存儲結(jié)構(gòu)7.4 MCS-51特殊功能存放器(SFR)的C51定義7.5 MCS-51并行接口的C51定義7.6 位變量的C51定義7.7 C51構(gòu)造數(shù)據(jù)類型7.8 模塊化程序開發(fā)過程7.9 MCS-51內(nèi)部資源使用的C語言編程7.10 MCS-51片外擴(kuò)展的C語言編程7.11 頻率量測量的C語言編程7.12 MCS-51機(jī)間通信的C語言編程7.13 鍵盤和數(shù)碼顯示人機(jī)交互的C語言編程在之前的單片機(jī)原理課程中,主要學(xué)習(xí)的是匯編語言。特點(diǎn)是:面向硬件,

2、直接操作存放器和存儲器,指令多,結(jié)構(gòu)復(fù)雜,難于維護(hù)。但對于我們掌握整個單片機(jī)來說,這是一個不可或缺的過程,能讓我們比較徹底的了解其硬件結(jié)構(gòu)。BASIC, PL/M,C,匯編。7.1 C語言與MCS51 對指令系統(tǒng)無需了解,僅對8051 的存儲器有初步了解。存放器的分配,不同存儲器的尋址和數(shù)據(jù)類型等細(xì)節(jié)由編譯器來進(jìn)行管理。函數(shù)更容易使程序結(jié)構(gòu)化。增強(qiáng)程序的可讀性。關(guān)鍵字和運(yùn)算函數(shù)可用近似人的思維過程方式使用。編程和調(diào)試時間縮短,提高效率。具有標(biāo)準(zhǔn)子程序,方便使用。移植性強(qiáng),模塊化編程技術(shù)。 用匯編程序設(shè)計(jì)MCS51系列單片機(jī)應(yīng)用程序時,必須要考慮其存儲器結(jié)構(gòu),尤其必須考慮其片內(nèi)數(shù)據(jù)存儲器與特殊功

3、能存放器正確、合理的使用以及按實(shí)際地址處理端口數(shù)據(jù)。用C語言編寫MCS51單片機(jī)的應(yīng)用程序,雖然不像用匯編語言那樣具體地組織、分配存儲器資源和處理端口數(shù)據(jù),但在C語言編程中,對數(shù)據(jù)類型與變量的定義,必須要與單片機(jī)的存儲結(jié)構(gòu)相關(guān)聯(lián),否那么編譯器不能正確地映射定位。用C語言編寫單片機(jī)應(yīng)用程序與編寫標(biāo)準(zhǔn)的C語言程序的不同之處就在于根據(jù)單片機(jī)存儲結(jié)構(gòu)及內(nèi)部資源定義相應(yīng)的C語言中的數(shù)據(jù)類型和變量,其它的語法規(guī)定、程序結(jié)構(gòu)及程序設(shè)計(jì)方法都與標(biāo)準(zhǔn)的C語言程序設(shè)計(jì)相同。 用C語言編寫的應(yīng)用程序必須經(jīng)單片機(jī)的C語言編譯器(簡稱C51),轉(zhuǎn)換生成單片機(jī)可執(zhí)行的代碼程序。支持MCS51系列單片機(jī)的C語言編譯器有很多

4、種。如IAR、American Automation、Auocet、BSO/TASKING、DUNFIELD SHAREWARE、KEIL等。其中KEIL以它的代碼緊湊和使用方便等特點(diǎn)優(yōu)于其它編譯器。本章是針對這種編譯器介紹 MCS51單片機(jī)C語言程序設(shè)計(jì)。 國內(nèi)廣州周立功有正版銷售。7.2 C51數(shù)據(jù)類型及在MCS-51中的存儲方式7.2.1 C51的數(shù)據(jù)類型 Franklin C51編譯器具體支持的數(shù)據(jù)類型有:位型(bit)、無符號字符(unsigned char)、有符號字符(singed char)、無符號整型(unsigned int )、有符號整型(signed int )、無符號

5、長整型(unsigned long )、有符號長整型(signed long )、浮點(diǎn)型(float)和指針類型等。表7.1 Franklin C51的數(shù)據(jù)類型數(shù)據(jù)類型長度(bit)長度(byte)值域bit110,1unsigned char810255signed char81128127unsigned int 162065535signed int 1623276832767unsigned long32404294967295signed long 32421474836482147483647float 3241.176E383.40E+38(6位數(shù)字)double6481.176

6、E383.40E+38(10位數(shù)字)一般指針243存儲空間0655357.2.2 C51數(shù)據(jù)在MCS-51中的存儲方式 位變量(bit):與MCS-51硬件特性操作有關(guān)的可以定義成位變量。位變量必須定位在MCS-51單片機(jī)片內(nèi)RAM的位尋址空間中。 字符變量(char):字符變量的長度為1 byte即8位。這很適宜MCS-51單片機(jī),因?yàn)镸CS-51單片機(jī)每次可處理8位數(shù)據(jù)。對于無符號變量(unsigned char)的值域范圍是0255。對于有符號字符變量(signed char),最具有重要意義的位是最高位上的符號標(biāo)志位(msb)。此位為1代表負(fù),為0代表正。有符號字符變量和無符號字符變量

7、在表示0127的數(shù)值時,其含義是一樣的,都是00 x7F。負(fù)數(shù)一般用補(bǔ)碼表示,即用11111111表示-1, 用11111110表示-2。當(dāng)進(jìn)行乘除法運(yùn)算時,符號問題就變得十分復(fù)雜,而C51編譯器會自動地將相應(yīng)的庫函數(shù)調(diào)入程序中來解決這個問題。 整型變量(int): 整型變量的長度為16位。與8080和8086 CPU系列不同,MCS-51系列單片機(jī)將int型變量的高位字節(jié)數(shù)存放在低地址字節(jié)中,低位字節(jié)數(shù)存放在高地址字節(jié)中。有符號整型變量(signed int)也使用msb位作符號標(biāo)志位,并使用二進(jìn)制補(bǔ)碼表示數(shù)值??芍苯邮褂脦追N專用的機(jī)器指令來完成多字節(jié)的加、減、乘、除運(yùn)算。整型變量值0 x1

8、234以圖7.1所示的方式存放在內(nèi)存中。圖7.1 整型數(shù)的存儲結(jié)構(gòu) 0 x120 x34+0+1地址 0 x120 x340 x560 x78.+0+1+2+3地址 圖7.2 長整型變量的存儲結(jié)構(gòu) 浮點(diǎn)型變量(float): 浮點(diǎn)型變量為32位,占4個字節(jié),許多復(fù)雜的數(shù)學(xué)表達(dá)式都采用浮點(diǎn)變量數(shù)據(jù)類型。應(yīng)用符號位表示數(shù)的符號,用階碼和尾數(shù)表示數(shù)的大小。 用它們進(jìn)行任何數(shù)學(xué)運(yùn)算都需要使用由編譯器決定的各種不同效率等級的庫函數(shù)。Franklin C51的浮點(diǎn)變量數(shù)據(jù)類型的使用格式與IEEE-754標(biāo)準(zhǔn)有關(guān),具有24位精度,尾數(shù)的高位始終為1,因而不保存,位的分布如下: 1位符號位。 8位指數(shù)位。 2

9、3位尾數(shù)。 符號位是最高位,尾數(shù)為低23位,內(nèi)存中按字節(jié)存儲順序如下:地址+0+1+2+3內(nèi)容MMMMMMMMMMMMMMMMEMMMMMMMSEEEEEEE 其中,S為符號位,1表示負(fù),0表示正;E為階碼;M為23位尾數(shù),最高位為1。 浮點(diǎn)變量值 -12.5的十進(jìn)制為:0 xC1480000,它按圖7.3所示方式存于內(nèi)存中。0 x000 x000 x480 xC1.+0+1+2+3地址 圖7.3 浮點(diǎn)數(shù)的存儲結(jié)構(gòu) 在編程時,如果只強(qiáng)調(diào)運(yùn)算速度而不進(jìn)行負(fù)數(shù)運(yùn)算時,最好采用無符號(unsigned)格式。 無符號字符類型的使用:無論何時,應(yīng)盡可能使用無符號字符變量,因?yàn)樗苤苯颖籑CS-51所接

10、受?;谕瑯拥脑?,也應(yīng)盡量使用位變量。有符號字符變量雖然也只占用一個字節(jié),但需要進(jìn)行額外的操作來進(jìn)行測試代碼的符號位。這無疑會降低代碼效率。 使用簡化形式定義數(shù)據(jù)類型。其方法是在源程序開頭使用#define語句自定義簡化的類型標(biāo)識符。例如:#define uchar unsigned char #define uint unsigned int 這樣,在編程中,就可以用uchar代替unsigned char,用uint代替unsigned int來定義變量。7.3 C51數(shù)據(jù)的存儲類型與MCS-51存儲結(jié)構(gòu)表 7.2 C51存儲類型與MCS-51存儲空間的對應(yīng)關(guān)系存儲類型與存儲空間的對應(yīng)關(guān)

11、系 data 直接尋址片內(nèi)數(shù)據(jù)存儲區(qū),訪問速度快(128字節(jié)) bdata 可位尋址片內(nèi)數(shù)據(jù)存儲區(qū),允許位與字節(jié)混合訪問(16字節(jié)) idata 間接尋址片內(nèi)數(shù)據(jù)存儲區(qū),可訪問片內(nèi)全部RAM地址空間(256字節(jié)) pdata 分頁尋址片外數(shù)據(jù)存儲區(qū)(256字節(jié))由MOV Ri訪問(i=0,1) xdata 片外數(shù)據(jù)存儲區(qū)(64 KB)由MOVX DPTR訪問 code 程序存儲器64 KB空間,由MOVC DPTR訪問表7.3 C51存儲類型及其數(shù)據(jù)長度和值域存儲類型長度(bit)長度(byte)值域范圍data810255idata810255pdata810255xdata162065 5

12、35code162065 535帶存儲類型的變量的定義的一般格式為 數(shù)據(jù)類型 存儲類型 變量名帶存儲類型的變量定義舉例:char data var1;bit bdata flags;float idata x,y,z;unsigned int pdata var2;unsigned char vector34;表 7.4 存儲模式說明存儲模式說 明SMALL默認(rèn)的存儲類型是data,參數(shù)及局部變量放入可直接尋址片內(nèi)RAM的用戶區(qū)中(最大128字節(jié))。另外所有對象(包括堆棧),都必須嵌入片內(nèi)RAM。棧長很關(guān)鍵,因?yàn)閷?shí)際棧長依賴于函數(shù)嵌套調(diào)用層數(shù)COMPACT默認(rèn)的存儲類型是pdata,參數(shù)及局部

13、變量放入分頁的外部數(shù)據(jù)存儲區(qū),通過R0或R1間接訪問,??臻g位于片內(nèi)數(shù)據(jù)存儲區(qū)中LARGE默認(rèn)的存儲類型是xdata,參數(shù)及局部變量直接放入片外數(shù)據(jù)存儲區(qū),使用數(shù)據(jù)指針DPTR來進(jìn)行尋址。用此數(shù)據(jù)指針進(jìn)行訪問效率較低,尤其對兩個或多個字節(jié)的變量,這種數(shù)據(jù)類型的訪問機(jī)制直接影響代碼的長度7.4 MCS-51特殊功能存放器(SFR)的C51定義 MCS-51單片機(jī)中,除了程序計(jì)數(shù)器PC和4組工作存放器組外,其它所有的存放器均為特殊功能存放器(SFR),分散在片內(nèi)RAM區(qū)的高128字節(jié)中,地址范圍為80H0FFH。SFR中有11個存放器具有位尋址能力,它們的字節(jié)地址都能被8整除,即字節(jié)地址是以8或0

14、為尾數(shù)的。 為了能直接訪問這些SFR,F(xiàn)ranklin C51提供了一種自主形式的定義方法,這種定義方法與標(biāo)準(zhǔn)C語言不兼容,只適用于對MCS-51系列單片機(jī)進(jìn)行C語言編程。特殊功能存放器C51定義的一般語法格式如下:sfr sfr-name = int constant; sfr是定義語句的關(guān)鍵字,其后必須跟一個MSC-51單片機(jī)真實(shí)存在的特殊功能存放器名,=后面必須是一個整型常數(shù),不允許帶有運(yùn)算符的表達(dá)式,是特殊功能存放器sfr-name的字節(jié)地址,這個常數(shù)值的范圍必須在SFR地址范圍內(nèi),位于0 x800 xFF。例如:sfr SCON=0 x98; /* 串口控制存放器地址98H */sf

15、r TMOD=0 x89;/* 定時器/計(jì)數(shù)器方式控制存放器地址89H */ MCS-51系列單片機(jī)的特殊功能存放器的數(shù)量與類型不盡相同,因此建議將所有特殊的sfr定義放入一個頭文件中,該文件應(yīng)包括MCS-51單片機(jī)系列機(jī)型中的SFR定義。C51編譯器的reg51.h頭文件就是這樣一個文件。 在新的MCS-51系列產(chǎn)品中,SFR在功能上經(jīng)常組合為16位值,當(dāng)SFR的高字節(jié)地址直接位于低字節(jié)之后時,對16位SFR的值可以直接進(jìn)行訪問。例如52子系列的定時器/計(jì)數(shù)器2就是這種情況。為了有效地訪問這類SFR,可使用關(guān)鍵字sfr16來定義,其定義語句的語法格式與8位SFR相同,只是=后面的地址必須用1

16、6位SFR的低字節(jié)地址,即低字節(jié)地址作為sfr16的定義地址。例如: sfr16 T2 = 0 xCC /*定時器/計(jì)數(shù)器2:T2低8位地址為0CCH,T2高8位地址為0CDH*/ 這種定義適用于所有新的16位SFR,但不能用于定時器/計(jì)數(shù)器0和1。 對于位尋址的SFR中的位,C51的擴(kuò)充功能支持特殊位的定義,像SFR一樣不與標(biāo)準(zhǔn)C兼容,使用sbit來定義位尋址單元。 第一種格式: sbit bit-name = sfr-nameint constant; sbit是定義語句的關(guān)鍵字,后跟一個尋址位符號名(該位符號名必須是MCS-51單片機(jī)中規(guī)定的位名稱),=后的sfr-name必須是已定義過

17、的SFR的名字,后的整常數(shù)是尋址位在特殊功能存放器sfr-name中的位號,必須是07范圍中的數(shù)。例如: sfr PSW=0 xD0 ; /* 定義PSW存放器地址為D0H */ sbit OV=PSW2 ; /* 定義OV位為PSW.2,地址為D2H */ sbit CY=PSW7 ; /* 定義CY位為PSW.7,地址為D7H */ 第二種格式:sbit bit-name = int constantint constant; =后的int constant為尋址地址位所在的特殊功能存放器的字節(jié)地址,符號后的int constant為尋址位在特殊功能存放器中的位號。例如: sbit OV=

18、0XD02 ;/* 定義OV位地址是D0H字節(jié)中的第2位 */ sbit CY=0XD07 ;/* 定義CY位地址是D0H字節(jié)中的第7位 */ 第三種格式:sbit bit-name = int constant; =后的int constant為尋址位的絕對位地址。例如: sbit OV=0XD2 ;/* 定義OV位地址為D2H */ sbit CY=0XD7 ;/* 定義CY位地址為D7H */ 特殊功能位代表了一個獨(dú)立的定義類,不能與其它位定義和位域互換。7.5 MCS-51并行接口的C51定義 MCS-51系列單片機(jī)并行I/O接口除了芯片上的4個I/O口(P0 P3)外,還可以在片外擴(kuò)

19、展I/O口。MCS-51單片機(jī)I/O口與數(shù)據(jù)存儲器統(tǒng)一編址,即把一個I/O口當(dāng)作數(shù)據(jù)存儲器中的一個單元來看待。 使用C51進(jìn)行編程時,MCS-51片內(nèi)的I/O口與片外擴(kuò)展的I/O可以統(tǒng)一在一個頭文件中定義,也可以在程序中(一般在開始的位置)進(jìn)行定義,其定義方法如下: 對于MCS-51片內(nèi)I/O口按特殊功能存放器方法定義。例如:sfr P0=0 x80 ; /* 定義P0口,地址為80H */sfr P1=0 x90 ; /* 定義P1口,地址為90H */ 對于片外擴(kuò)展I/O口,那么根據(jù)硬件譯碼地址,將其視作為片外數(shù)據(jù)存儲器的一個單元,使用#define語句進(jìn)行定義。例如#include #d

20、efine PORTA XBYTE 0 xFFC0 absacc.h是C51中絕對地址訪問函數(shù)的頭文件,將PORTA定義為外部I/O口,地址為 FFC0H,長度為8位。 一旦在頭文件或程序中對這些片外I/O口進(jìn)行定義后,在程序中就可以自由使用變量名與其實(shí)際地址的聯(lián)系,以便使程序員能用軟件模擬MCS-51的硬件操作。 (1) 位變量C51定義。使用C51編程時,定義了位變量后,就可以用定義了的變量來表示MCS-51的位尋址單元。 位變量的C51定義的一般語法格式如下: 位類型標(biāo)識符(bit) 位變量名; 例如:bit direction_bit ;/* 把direction_bit定義為位變量

21、*/bit look_pointer ;/* 把look_pointer定義為位變量 */7.6 位變量的C51定義 (2) 函數(shù)可包含類型為bit的參數(shù),也可以將其作為返回值。例如: bit func(bit b0, bit b1) /* 變量b0,b1作為函數(shù)的參數(shù) */ return (b1); /* 變量b1作為函數(shù)的返回值 */ 注意,使用(#pragma disable)或包含明確的存放器組切換(using n)的函數(shù)不能返回位值,否那么編輯器將會給出一個錯誤信息。 (3) 對位變量定義的限制。位變量不能定義成一個指針,如不能定義:bit * bit_pointer。不存在位數(shù)組,

22、如不能定義:bit b_array 。 在位定義中,允許定義存儲類型,位變量都被放入一個位段,此段總位于MCS-51片內(nèi)的RAM區(qū)中。因此,存儲類型限制為data和idata,如果將位變量的存儲類型定義成其它存儲類型都將編譯出錯。例1 先定義變量的數(shù)據(jù)類型和存儲類型:bdata int ibase; /* 定義ibase為bdata整型變量 */bdata char bary4;/* bary4定義為bdata字符型數(shù)組 */然后可使用sbit定義可獨(dú)立尋址訪問的對象位:sbit mybit0 = ibase0 ;/* mybit0定義為ibase的第0位 */sbit mybit15 = i

23、base15;/* mybit0定義為ibase的第15位 */sbit Ary07 = bary07 ;/* Ary07定義為abry0的第7位 */sbit Ary37 = bary37 ;/* Ary37定義為abry3的第7位 */ 對象ibase和bary也可以字節(jié)尋址: ary37=0; /* bary3的第7位賦值為0 */ bary3=a; /* 字節(jié)尋址,bary3 賦值為a */ sbit定義要位尋址對象所在字節(jié)基址對象的存儲類型為bdata,否那么只有絕對的特殊位定義(sbit)是合法的。操作符后的最大值依賴于指定的基類型,對于char/uchar而言是07,對于int/

24、uint而言是015,對于long/ulong而言是031。7.7 C51構(gòu)造數(shù)據(jù)類型 1基于存儲器的指針 基于存儲器的指針以存儲器類型為參量,它在編譯時才被確定。因此,為指針選擇存儲器的方法可以省掉,以便這些指針的長度為一個字節(jié)(idata *,data *,pdata *)或2個字節(jié)(code *,xdata *)。編譯時,這類操作一般被行內(nèi)(inline)編碼,而無需進(jìn)行庫調(diào)用。 基于存儲器的指針定義舉例: char xdata *px; 在xdata存儲器中定義了一個指向字符型(char)的指針變量px。指針自身在默認(rèn)存儲區(qū)(決定于編譯模式),長度為2個字節(jié)(值為00 xFFFF)。

25、char xdata *data pdx; 除了明確定義指針位于MCS-51內(nèi)部存儲區(qū)(data)外,其它與上例相同,它與編譯模式無關(guān)。 data char xdata *pdx;也可以struct time char hour ; char min; char sec; struct time xdata *pxtime; 在結(jié)構(gòu)struct time中,除了其它結(jié)構(gòu)成員外,還包含有一個具有和struct time相同的指針pxtime,time位于外部數(shù)據(jù)存儲器(xdata),指針pxtime具有兩個字節(jié)長度。 struct time idata *ptime ; 這個聲明定義了一個位于默

26、認(rèn)存儲器中的指針,它指向結(jié)構(gòu)time,time位于idata存儲器中,結(jié)構(gòu)成員可以通過MCS-51的R0或R1 進(jìn)行間接訪問,指針ptime為1個字節(jié)長。 ptimepxtimehour = 12; 使用上面的關(guān)于struct time和struct idata *ptime的定義,指針pxtime被從結(jié)構(gòu)中間接調(diào)用,它指向位于xdata存儲器中的time結(jié)構(gòu)。結(jié)構(gòu)成員hour被賦值為12。 2一般指針 一般指針包括3個字節(jié):1個字節(jié)存儲類型和2個字節(jié)偏移地址,即地址+0+1+2內(nèi)容存儲器類型偏移地址高位字節(jié)偏移地址低位字節(jié)其中,第一字節(jié)代表了指針的存儲器類型,存儲器類型編碼如下:存儲器類型i

27、dataxdatapdatadatacode值0 x000 x010 xFE0 x000 xFF例如,以xdata類型的0 x1234地址為指針可以表示如下:地址+0+1+2內(nèi)容0 x010 x120 x34 當(dāng)用常數(shù)作指針時,必須注意正確定義存儲器類型和偏移量。 例如,將常數(shù)值0 x41寫入地址為0 x8000的外部數(shù)據(jù)存儲器。 #define XBYTE ( (char *) 0 x10000L) XBYTE0 x8000 = 0 x41 ; 其中,XBYTE被定義為(char *)0 x10000L,0 x10000L為一般指針,其存儲類型為1,偏移量為0000H,這樣XBYTE成為指向

28、xdata零地址的指針。而XBYTE8000那么是外部數(shù)據(jù)存儲器的0 x8000絕對地址。編程示范1。指定指針的存儲類型和指向變量的類型的示范。特別存儲類型為Code的時候,要注意其指向變量是否具有可讀寫性。2。常數(shù)做指針時的示范。注意應(yīng)包含頭文件,具體定義方式。7.8 模塊化程序開發(fā)過程圖7.4 程序開發(fā)過程 有關(guān)函數(shù)的簡介有關(guān)程序的組成:主函數(shù)和假設(shè)干被調(diào)用的函數(shù)。其中主函數(shù)是必不可少的。從用戶使用的角度函數(shù)分為兩種:1.標(biāo)準(zhǔn)庫函數(shù);2.用戶自定義的函數(shù)。列舉出一些常用的系統(tǒng)函數(shù)庫。在使用的時候,只要包含其頭文件就可以了。常用的函數(shù)庫:intrins.h 頭文件包含可控制編譯器生成在線嵌入

29、內(nèi)部代碼的函數(shù)原型,比方_nop_,演示其用法。stdio.h 頭文件包含流I/O函數(shù)的定義和原型,如printf函數(shù)。string.h 頭文件包含字符串和緩沖區(qū)操作的原型。如trcmp,strlen,memset,memcpy.用戶自定義的函數(shù)和標(biāo)準(zhǔn)C語言的用法是一樣的,不過多一個位的數(shù)據(jù)類型。如果用戶函數(shù)定義在主函數(shù)之前,可以不用申明;否那么,應(yīng)該在程序的開頭進(jìn)行聲明。搞清楚形參和實(shí)參的根本概念,區(qū)別。調(diào)用的時候,由實(shí)參傳遞給形參,注意傳遞方向是單向的。而且特別注意形參和實(shí)參的類型一定要匹配。1參數(shù)傳遞規(guī)那么表7.6 參數(shù)傳遞的存放器選擇參數(shù)類型charintlong ,double一般指

30、針第1個參數(shù)R7R6, R7R4R7R1,R2,R3第2個參數(shù)R5R4, R5R4R7R1,R2,R3第3個參數(shù)R3R2, R3無R1,R2,R3 func1(int a) “a是第一個參數(shù),在R6,R7中傳遞。 func2 (int b, int c, int *d ) b是第一個參數(shù),在R6,R7中傳遞;c是第二個參數(shù),在R4,R5中傳遞;d是第三個參數(shù),在R1,R2,R3中傳遞。 func3(long e , long f ) e是第一個參數(shù),在R4R7中傳遞;f是第二個參數(shù),不能在存放器中傳遞,只能在參數(shù)傳遞段中傳遞。 func4(float g , char h ) g是第一個參數(shù),

31、在R4R7中傳遞;h是第二個參數(shù),必須在參數(shù)傳遞段中傳遞。編程示范有關(guān)參數(shù)傳遞時使用的存儲單元。1。單個形參為整型時,傳遞細(xì)節(jié)。2。第一個為double類型時,第二個參數(shù)為uchar類型時,傳遞的細(xì)節(jié)。3。同時觀察被調(diào)函數(shù)返回值的存放單元。表7.7 函數(shù)返回值的存放器返 回 值寄 存 器說 明bitC進(jìn)位標(biāo)位(unsigned) charR7(unsigned) intR6,R7高位字節(jié)在R6,低位字節(jié)在R7(unsigned) longR4R7高位字節(jié)在R4,低位字節(jié)在R7floatR4R732位IEEE格式,指數(shù)和符號位在R7指針R1,R2,R3R3放存儲器類型,高位在R2,低位在R1 在

32、匯編子程序中,當(dāng)前選擇的存放器組及存放器ACC、B、DPTR和PSW都可能改變。當(dāng)被C調(diào)用時,必須無條件地假設(shè)這些存放器的內(nèi)容已被破壞。2、 庫和連接器/定位器表7.9 Franklin C51的編譯庫庫說 明C51S.LIBSMALL模式,無浮點(diǎn)運(yùn)算C51FPS.LIB浮點(diǎn)數(shù)學(xué)運(yùn)算庫(SMALL模式)C51C.LIBCOMPACT模式,無浮點(diǎn)運(yùn)算C51FPC.LIB浮點(diǎn)運(yùn)算庫(COMPACT模式)C51L.LIBLARGE模式,無浮點(diǎn)運(yùn)算C51FPL.LIB浮點(diǎn)運(yùn)算庫(LARGE模式)3、 存儲器分配物理存儲區(qū)最大長度地址區(qū)段類型程序64 KB00FFFFHCODE外部數(shù)據(jù)64 KB00FF

33、FFHXDATA直接尋址片內(nèi)數(shù)據(jù)128字節(jié)07FHDATA間接尋址片內(nèi)數(shù)據(jù)256字節(jié)00FFHIDATA片內(nèi)數(shù)據(jù)的位空間128位07FHBIT表7.10 MCS-51系列的物理存儲區(qū)7.8.4 程序優(yōu)化 以下選擇對提高程序效率有很大影響: (1) 盡量選擇小存儲模式以防止使用MOVX指令。 (2) 使用大模式(COMPACT/LARGE)應(yīng)仔細(xì)考慮要放在內(nèi)部數(shù)據(jù)存儲器的變量要求是經(jīng)常用的或是用于中間結(jié)果的。訪問內(nèi)部數(shù)據(jù)存儲器要比訪問外部數(shù)據(jù)存儲器快得多。內(nèi)部RAM由存放器組、位數(shù)據(jù)區(qū)和其它用戶用“data類型定義的變量共享。由于內(nèi)部RAM容量的限制(128256字節(jié),由使用的單片機(jī)決定),必須

34、權(quán)衡利弊以解決訪問效率和這些對象的數(shù)量之間的矛盾。 (3) 要考慮操作順序,完成一件事后再做一件事。 (4) 注意程序編寫細(xì)那么。例如,假設(shè)使用for(;)循環(huán),DJNZ指令比CJNE指令更有效,可減少重復(fù)循環(huán)次數(shù)。 (5) 假設(shè)編譯器不能使用左移和右移完成乘除法,應(yīng)立即修改,例如,左移為乘2。 (6) 用邏輯AND/&取模比用MOD / %操作更有效。 (7) 因計(jì)算機(jī)基于二進(jìn)制,仔細(xì)選擇數(shù)據(jù)存儲器和數(shù)組大小可節(jié)省操作。 (8) 盡可能使用最小的數(shù)據(jù)類型,MCS-51系列是8位機(jī),顯然對具有char類型的對象的操作比int或long類型的對象的操作要方便得多。 (9) 盡可能使用unsign

35、ed數(shù)據(jù)類型。MCS-51系列CPU并不直接支持有符號數(shù)的運(yùn)算。因而C51編譯器必須產(chǎn)生與之相關(guān)的更多的程序代碼以解決這個問題。 (10) 盡可能使用局部函數(shù)變量。編譯器總是嘗試在存放器里保持局部變量。這樣,將循環(huán)變量(如for和while循環(huán)中的計(jì)數(shù)變量)說明為局部變量是最好的。使用unsigned char/int的對象通常能獲得最好的結(jié)果。Cx51運(yùn)算符、表達(dá)式及其規(guī)那么+、-、*、/,%、=、=、!=&、|、!&、|、?、?編程示范:主要演示邏輯運(yùn)算類的運(yùn)算符。7.9 MCS-51內(nèi)部資源使用的C語言編程7.9.1 中斷應(yīng)用的C語言編程 C51編譯器支持在C源程序中直接開發(fā)中斷程序。中

36、斷效勞程序是通過按規(guī)定語法格式定義的一個函數(shù)。 中斷效勞程序的函數(shù)定義的語法格式如下: 返回值 函數(shù)名(參數(shù)) interrupt musing n 表7.11 MCS-51中斷源編號編 號中 斷 源入 口 地 址0外部中斷00003H1定時器/計(jì)數(shù)器0000BH2外部中斷10013H3定時器/計(jì)數(shù)器1001BH4串行口中斷0023H using n 選項(xiàng)用于實(shí)現(xiàn)工作存放器組的切換,n是中斷效勞子程序中選用的工作存放器組號(0 3)。在許多情況下,響應(yīng)中斷時需保護(hù)有關(guān)現(xiàn)場信息,以便中斷返回后,能使中斷前的源程序從斷點(diǎn)處繼續(xù)正確地執(zhí)行下去。這在MCS-51單片機(jī)中,能很方便地利用工作存放器組的切

37、換來實(shí)現(xiàn)。即在進(jìn)入中斷效勞程序前的程序中使用一組工作存放器,進(jìn)入中斷效勞程序后,由using n切換到另一組存放器,中斷返回后又恢復(fù)到原存放器組。這樣互相切換的兩組存放器中的內(nèi)容彼此都沒有被破壞。圖 7.5 擴(kuò)展多個中斷源 例3 圖7.5所示是利用優(yōu)先權(quán)解碼芯片,在單片機(jī)8031的一個外部中斷INT1上擴(kuò)展多個中斷源的原理電路圖。圖中是以開關(guān)閉合來模擬中斷請求信號。當(dāng)有任一中斷源產(chǎn)生中斷請求,能給8031的INT1引腳送一個有效中斷信號,由P1的低3位可得對應(yīng)中斷源的中斷號。 在中斷效勞程序中僅設(shè)置標(biāo)志,并保存I/O口輸入狀態(tài)。Franklin C51編譯器提供定義特定MCS-51系列成員的存

38、放器頭文件。MCS-51頭文件為reg51.h。C51程序如下: # include unsigned char status; bit flag; void service_int1( ) interrupt 2 using 2 /* INT1中斷效勞程序,使用第2組工作存放器 */ flag=1; /* 設(shè)置標(biāo)志 */ status=p1; /* 存輸入口狀態(tài) */ void main(void) IP=0 x04 ; /* 置INT1為高優(yōu)先級中斷 */ IE=0 x84 ; /* INT1開中斷,CPU開中斷 */for(; ;) if(flag) /* 有中斷 */ switch(s

39、tatus) /* 根據(jù)中斷源分支 */ case 0 : break ; /* 處理IN0 */ case 1 : break ; /* 處理IN1 */ case 2 : break; /* 處理IN2 */ case 3 : break; /* 處理IN3 */ default : ; flag=0 ; /* 處理完成清標(biāo)志 */ 7.9.2 定時器/計(jì)數(shù)器(T/C)應(yīng)用的C語言編程 例4 設(shè)單片機(jī)的fosc=12 MHz晶振,要求在P1.0腳上輸出周期為2 ms的方波。 周期為2 ms的方波要求定時時間隔1 ms,每次時間到P1.0取反。 機(jī)器周期=12/fosc=1 s 需計(jì)數(shù)次數(shù)=

40、1000/(12/fosc)=1000/1=1000 由于計(jì)數(shù)器是加1計(jì)數(shù),為得到1000個計(jì)數(shù)之后的定時器溢出,必須給定時器置初值為-1000(即1000的補(bǔ)數(shù))。(1) 用定時器0的方式1編程,采用查詢方式,程序如下: # include sbit P1_0=P10 ; void main(void) TMOD=0 x01 ; /* 設(shè)置定時器1為非門控制方式1*/ TR0=1 ; /* 啟動 T/C0 */ for( ; ;) TH0= -(1000/256) ; /* 裝載計(jì)數(shù)器初值 */ TL0= -(1000%256) ; do while (!TF0) ; /* 查詢等待TF0置

41、位 */ P1_0=!P1_0; /* 定時時間到P1.0反相 */ TF0=0; /* 軟件清 TF0 */ (2) 用定時器0的方式1編程,采用中斷方式。程序如下: # include sbit P1_0=P10 ; void time (void) interrupt 1 using 1 /* T/C0中斷效勞程序入口 */ P1_0=!P1_0 ; /* P1.0取反 */ TH0= -(1000/256); / * 重新裝載計(jì)數(shù)初值 */ TL0= -(1000%256) ; void main( void ) TMOD=0 x01 ; /* T/C0工作在定時器非門控制方式1 */

42、 P1_0=0; TH0= -(1000/256 ); /* 預(yù)置計(jì)數(shù)初值 */ TL0= -(1000%256) ; EA=1 ; /* CPU中斷開放 */ ET0= 1 ; /* T/C0中斷開放 */ TR0=1 ; /* 啟動T/C0開始定時 */ do while(1) ; /* 等待中斷 */ 例5 采用10 MHz晶振,在P1.0腳上輸出周期為2.5 s,占空比20%的脈沖信號。 10 MHz晶振,使用定時器最大定時幾十毫秒。取10 ms定時,周期2.5 s需250次中斷,占空比20%,高電平應(yīng)為50次中斷。 10 ms定時,晶振fosc=10 MHz。 需定時器計(jì)數(shù)次數(shù)=10

43、10310/12=8333# include # define uchar unsigned charuchar period=250;uchar high=50;uchar time = 0; timer0( )interrupt 1 using 1 /* T/C0中斷效勞程序 */TH0= - 8333/256 ; /* 重置計(jì)數(shù)值 */TL0= - 8333%256 ; if(+time=high)P1=0; /* 高電平時間到變低 */else if (time=period) /* 周期時間到變高 */time=0 ;P1=1 ; main( ) TMOD=0 x01 ; /* 定時

44、器0方式1 */ TH0= - 8333/256 ;/* 預(yù)置計(jì)數(shù)初值 */ TL0= - 8333%256 ; EA=1; /* 開CPU中斷 */ ET0=1 ; /* 開T/C0中斷 */ TR0=1 ; /* 啟動T/C0 */ do while(1) ; 圖7.6 中斷效勞程序流程圖 7.10.2 MCS-51數(shù)據(jù)采集的C語言編程例9 ADC0809與8031接口的數(shù)據(jù)采集程序舉例。圖7.8 ADC0809與8031的接口電路程序如下: # include # include # define uchar unsigned char # define IN0 XBYTE 0 x7ff

45、8 /* 設(shè)置AD0809的通道0地址 */ sbit ad_busy =P33 ; /* 即EOC狀態(tài) */ void ad0809 ( uchar idata *x ) /* 采樣結(jié)果放指針中的A/D采集函數(shù) */ uchar i ; uchar xdata *ad_adr ; ad_adr= & IN0 ; for ( i=0 ; i8 ;i+ ) /* 處理8通道 */ *ad_adr=0 ; /* 寫操作,啟動轉(zhuǎn)換 */ i=i ; /* 延時等待EOC變低 */ i=i ; while (ad_busy = =0 ) ; /* 查詢等待轉(zhuǎn)換結(jié)束 */ xi = * ad_adr ;

46、 /* 讀操作,存轉(zhuǎn)換結(jié)果 */ ad_adr + ; /* 下一通道 */ void main ( void ) static uchar idata ad 10 ; ad0809 ( ad ) ; /* 采樣AD0809通道的值 */ 7.11 頻率量測量的C語言編程7.11.1 測量頻率法 測量頻率法的最簡單的接口電路,可將頻率脈沖直接連接到MCS-51的T1端,將8031的T/C0用作定時器,T/C1用作計(jì)數(shù)器。在T/C0定時時間里,對頻率脈沖進(jìn)行計(jì)數(shù)。T/C1的計(jì)數(shù)值便是單位定時時間里的脈沖個數(shù)。定時輸入脈沖 T圖7.13測量頻率中的脈沖丟失7.11.2 頻率脈沖的測量周期法圖7.1

47、5 周期測量接口 圖7.16 頻率與周期波 例15 測量周期的程序舉例。 設(shè)fosc = 6 MHz,機(jī)器周期為2 s,測周期的測量值為計(jì)數(shù)值乘以2。用C語言編寫的程序如下:#include#define uint unsigned intsbit P1_0=P10;uint count ,period;bit rflag=0; / * 周期標(biāo)志 */void control (void)TMOD=0 x09; /*定時器/計(jì)數(shù)器0為方式1*/ IT0=1;TR0=1; TH0=0;TL0=0; P1_0=0;P1_0=1; /*觸發(fā)器清零*/ TR0=1;ET0=1;EA=1;/*啟動T/C

48、0開中斷*/ void int_0(void)interrupt 0 using 1 /* INT0 中斷效勞*/ EA=0;TR0=0; count=TL0+TH0*256; /* 取計(jì)數(shù)值 */ rflag=1; /* 設(shè)標(biāo)志 */ EA=1;void main(void) contro1( ); while(rflag=0); /* 等待一周期 */ period=count*2; /* fosc=6 MHz,2 s計(jì)數(shù)增1,周期值單位s */7.12 MCS-51機(jī)間通信的C語言編程7.12.1 點(diǎn)對點(diǎn)的串行異步通信1通信雙方的硬件連接 圖 7.17 8031間RS232C電平信號的傳

49、 2通信雙方的約定圖 7.18 點(diǎn)對點(diǎn)通信的程序框圖 3. 點(diǎn)對點(diǎn)通信編程 點(diǎn)對點(diǎn)通信雙方根本等同,只是人為規(guī)定一個為發(fā)送,一個為接收。要求兩機(jī)串行口的波特率相同,因而發(fā)送和接收方串行口的初始化相同??删幹坪谐跏蓟瘮?shù)、發(fā)送函數(shù)接收函數(shù)的程序,在主函數(shù)中根據(jù)程序的發(fā)送、接收設(shè)置TR,采用條件判別決定使用發(fā)送函數(shù)還是接收函數(shù)。這樣點(diǎn)對點(diǎn)通信的雙方都可運(yùn)行此程序,只需在程序運(yùn)行之前人為設(shè)置選擇TR,一個令TR=0,一個令TR=1,然后分別編譯,在兩機(jī)上分別裝入,同時運(yùn)行。例16 點(diǎn)對點(diǎn)通信。點(diǎn)對點(diǎn)通信的程序如下:#include#define uchar unsigned char#define

50、 TR 1 /*發(fā)送接收差異值TR=0發(fā)送*/uchar idata buf10;uchar pf;void init(void) /*串行口初始化*/ TMOD=0 x20; /*設(shè)T/C1為定時方式2*/ TH1=0 xe8; /*設(shè)定波特率*/ TL1=0 xe8; PCON=0 x00; TR1=1; /*啟動T/C1*/ SCON=0 x50; /*串行口工作在方式1*/ void send(uchar idata *d) uchar i; do SBUF=0 xaa; /*發(fā)送聯(lián)絡(luò)信號*/ while(TI= =0); /*等待發(fā)送出去*/ TI=0; while(RI= =0);

51、 /*等待B機(jī)答復(fù)*/ RI=0; while(SBUF0 xbb)!=0); /*B機(jī)未準(zhǔn)備好,繼續(xù)聯(lián)絡(luò)*/ do pf=0; /*清校驗(yàn)和*/ for ( i=0;i16;i+) SBUF=di; /*發(fā)送一個數(shù)據(jù)*/ pf+ =di; /*求校驗(yàn)和*/ while(TI= =0);TI=0; SBUF=pf; /*發(fā)送校驗(yàn)和*/ while(TI= =0);TI=0; while(RI= =0);RI=0; /*等待B機(jī)答復(fù)*/ while(SBUF!=0); /*答復(fù)出錯,那么重發(fā)*/ void receive (uchar idata *d) uchar i; do while (R

52、I= =0); RI=0; while (SBUF0 xaa)! =0); /*判A機(jī)請求否*/ SBUF=0 xbb; /*發(fā)應(yīng)答信號*/while (TI= =0); TI=0; while (1) pf=0; /*清校驗(yàn)和*/ for ( i=0;i16;i+) while (RI= =0); RI=0; d i =SBUF; /*接收一個數(shù)據(jù)*/ pf+ =di; /*求校驗(yàn)和*/ while (RI= =0); RI=0; /*接收A機(jī)校驗(yàn)和*/ if (SBUF pf) = =0) /*比較校驗(yàn)和*/ SBUF=0 x00; break; /*校驗(yàn)和相同發(fā)00*/ else SBU

53、F=0 xff; /*出錯發(fā)FF,重新接收*/ while(TI= =0); TI=0; void main (void) init ( ); if(TR= =0) send(buf); else receive(buf); 7.13 鍵盤和數(shù)碼顯示人機(jī)交互的C語言編程7.13.1 行列式鍵盤與8031的接口 鍵盤輸入信息的主要過程是: (1) 單片機(jī)判斷是否有鍵按下。 (2) 確定按下的是哪一個鍵。 (3) 把此步驟代表的信息翻譯成計(jì)算機(jī)所能識別的代碼,如ASCII或其它特征碼。圖7.22 8031與行列式鍵盤的接口 例17 44鍵盤的掃描程序。 掃描程序查詢的內(nèi)容為: (1) 查詢是否有鍵

54、按下。首先單片機(jī)向行掃描P1.0 P1.3輸出全為0掃描碼F0H,然后從列檢查口P1.4 P1.7輸入列掃描信號,只要有一列信號不為1,即P1口不為F0H,那么表示有鍵按下。接著要查出按下鍵所在的行、列位置。 (2) 查詢按下鍵所在的行列位置。單片機(jī)將得到的信號取反,P1.4P1.7中的為1的位便是鍵所在的列。接下來要確定鍵所在的行,需要進(jìn)行逐行掃描。單片機(jī)首先使P1.0為0,P1.1P1.7為1,即向P1口發(fā)送掃描碼FEH,接著輸入列檢查信號,假設(shè)全為1,表示不在第一行。接著使P1.1接地,其余為1,再讀入列信號這樣逐行發(fā)0掃描碼,直到找到按下鍵所在的行,將該行掃描碼取反保存。當(dāng)各行都掃描以

55、后仍沒有找到,那么放棄掃描,認(rèn)為是鍵的誤動作。 (3) 對得到的行號和列號譯碼,得到鍵值。 (4) 鍵的抖動處理。當(dāng)用手按下一個鍵時,往往會出現(xiàn)所按鍵在閉合位置和斷開位置之間跳幾下才穩(wěn)定到閉合狀態(tài)的情況。在釋放一個鍵時,也會出現(xiàn)類似的情況,這就是鍵抖動,抖動的持續(xù)時間不一,通常不會大于10 ms,假設(shè)抖動問題不解決,就會引起對閉合鍵的屢次讀入,對于鍵抖動最方便的解決方法就是當(dāng)發(fā)現(xiàn)有鍵按下后,不是立即進(jìn)行逐行掃描,而是延時10 ms后再進(jìn)行。由于鍵按下的時間持續(xù)上百毫秒,延時后再也不遲。掃描函數(shù)的返回值為鍵特征碼,假設(shè)無鍵按下,返回值為0。程序如下:# include # define uchar unsigned char # define uint unsigned int void dlms( void )void kbscan( void ) ;void main ( void ) uchar key ;while( 1 ) key =kbscan ( ) ; dlms( ) ; void dlms( void ) uchar i ; for ( 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論