版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、第7章 單片機的C語言應(yīng)用程序設(shè)計,7.1 C語言與MCS-51 7.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片外擴展的C語言編程 7.11 頻率量測量的C語言編程 7.12 MCS-51機間通信的C語言編程 7.13 鍵盤和數(shù)碼顯示人機交互的C語言編程,7.1 C語言與MCS51,用匯
2、編程序設(shè)計MCS51系列單片機應(yīng)用程序時,必須要考慮其存儲器結(jié)構(gòu),尤其必須考慮其片內(nèi)數(shù)據(jù)存儲器與特殊功能寄存器正確、合理的使用以及按實際地址處理端口數(shù)據(jù)。用C語言編寫MCS51單片機的應(yīng)用程序,雖然不像用匯編語言那樣具體地組織、分配存儲器資源和處理端口數(shù)據(jù),但在C語言編程中,對數(shù)據(jù)類型與變量的定義,必須要與單片機的存儲結(jié)構(gòu)相關(guān)聯(lián),否則編譯器不能正確地映射定位。用C語言編寫單片機應(yīng)用程序與編寫標(biāo)準(zhǔn)的C語言程序的不同之處就在于根據(jù)單片機存儲結(jié)構(gòu)及內(nèi)部資源定義相應(yīng)的C語言中的數(shù)據(jù)類型和變量,其它的語法規(guī)定、程序結(jié)構(gòu)及程序設(shè)計方法都與標(biāo)準(zhǔn)的C語言程序設(shè)計相同。,用C語言編寫的應(yīng)用程序必須經(jīng)單片機的C語
3、言編譯器(簡稱C51),轉(zhuǎn)換生成單片機可執(zhí)行的代碼程序。支持MCS51系列單片機的C語言編譯器有很多種。如American Automation、Auocet、BSO/TASKING、DUNFIELD SHAREWARE、KEIL/Franklin等。其中KEIL/Franklin以它的代碼緊湊和使用方便等特點優(yōu)于其它編譯器。本章是針對這種編譯器介紹 MCS51單片機C語言程序設(shè)計。,7.2 C51數(shù)據(jù)類型及在MCS-51中的存儲方式,7.2.1 C51的數(shù)據(jù)類型 Franklin C51編譯器具體支持的數(shù)據(jù)類型有:位型(bit)、無符號字符(unsigned char)、有符號字符(sing
4、ed char)、無符號整型(unsigned int )、有符號整型(signed int )、無符號長整型(unsigned long )、有符號長整型(signed long )、浮點型(float)和指針類型等。,表7.1 Franklin C51的數(shù)據(jù)類型,7.2.2 C51數(shù)據(jù)在MCS-51中的存儲方式,位變量(bit):與MCS-51硬件特性操作有關(guān)的可以定義成位變量。位變量必須定位在MCS-51單片機片內(nèi)RAM的位尋址空間中。 字符變量(char):字符變量的長度為1 byte即8位。這很合適MCS-51單片機,因為MCS-51單片機每次可處理8位數(shù)據(jù)。對于無符號變量(unsi
5、gned char)的值域范圍是0255。對于有符號字符變量(signed char),最具有重要意義的位是最高位上的符號標(biāo)志位(msb)。此位為1代表負(fù),為0代表正。有符號字符變量和無符號字符變量在表示0127的數(shù)值時,其含義是一樣的,都是00 x7F。負(fù)數(shù)一般用補碼表示,即用11111111表示-1, 用11111110表示-2。當(dāng)進(jìn)行乘除法運算時,符號問題就變得十分復(fù)雜,而C51編譯器會自動地將相應(yīng)的庫函數(shù)調(diào)入程序中來解決這個問題。,整型變量(int): 整型變量的長度為16位。與8080和8086 CPU系列不同,MCS-51系列單片機將int型變量的高位字節(jié)數(shù)存放在低地址字節(jié)中,低位
6、字節(jié)數(shù)存放在高地址字節(jié)中。有符號整型變量(signed int)也使用msb位作符號標(biāo)志位,并使用二進(jìn)制補碼表示數(shù)值。可直接使用幾種專用的機器指令來完成多字節(jié)的加、減、乘、除運算。整型變量值0 x1234以圖7.1所示的方式存放在內(nèi)存中。,圖7.1 整型數(shù)的存儲結(jié)構(gòu),+0 +1,地址,+0 +1 +2 +3,地址,圖7.2 長整型變量的存儲結(jié)構(gòu),浮點型變量(float): 浮點型變量為32位,占4個字節(jié),許多復(fù)雜的數(shù)學(xué)表達(dá)式都采用浮點變量數(shù)據(jù)類型。應(yīng)用符號位表示數(shù)的符號,用階碼和尾數(shù)表示數(shù)的大小。 用它們進(jìn)行任何數(shù)學(xué)運算都需要使用由編譯器決定的各種不同效率等級的庫函數(shù)。Franklin C51
7、的浮點變量數(shù)據(jù)類型的使用格式與IEEE-754標(biāo)準(zhǔn)有關(guān),具有24位精度,尾數(shù)的高位始終為1,因而不保存,位的分布如下: 1位符號位。 8位指數(shù)位。 23位尾數(shù)。,符號位是最高位,尾數(shù)為低23位,內(nèi)存中按字節(jié)存儲順序如下:,其中,S為符號位,1表示負(fù),0表示正;E為階碼;M為23位尾數(shù),最高位為1。 浮點變量值 -12.5的十進(jìn)制為:0 xC1480000,它按圖7.3所示方式存于內(nèi)存中。,+0 +1 +2 +3,地址,圖7.3 浮點數(shù)的存儲結(jié)構(gòu),在編程時,如果只強調(diào)運算速度而不進(jìn)行負(fù)數(shù)運算時,最好采用無符號(unsigned)格式。 無符號字符類型的使用:無論何時,應(yīng)盡可能使用無符號字符變量,
8、因為它能直接被MCS-51所接受?;谕瑯拥脑?,也應(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存儲空間
9、的對應(yīng)關(guān)系,表7.3 C51存儲類型及其數(shù)據(jù)長度和值域,帶存儲類型的變量的定義的一般格式為 數(shù)據(jù)類型 存儲類型 變量名,帶存儲類型的變量定義舉例: char data var1; bit bdata flags; float idata x,y,z; unsigned int pdata var2; unsigned char vector34;,表 7.4 存儲模式說明,7.4 MCS-51特殊功能寄存器(SFR)的C51定義,MCS-51單片機中,除了程序計數(shù)器PC和4組工作寄存器組外,其它所有的寄存器均為特殊功能寄存器(SFR),分散在片內(nèi)RAM區(qū)的高128字節(jié)中,地址范圍為80H0FF
10、H。SFR中有11個寄存器具有位尋址能力,它們的字節(jié)地址都能被8整除,即字節(jié)地址是以8或0為尾數(shù)的。 為了能直接訪問這些SFR,F(xiàn)ranklin C51提供了一種自主形式的定義方法,這種定義方法與標(biāo)準(zhǔn)C語言不兼容,只適用于對MCS-51系列單片機進(jìn)行C語言編程。特殊功能寄存器C51定義的一般語法格式如下: sfr sfr-name = int constant;,sfr是定義語句的關(guān)鍵字,其后必須跟一個MSC-51單片機真實存在的特殊功能寄存器名,=后面必須是一個整型常數(shù),不允許帶有運算符的表達(dá)式,是特殊功能寄存器sfr-name的字節(jié)地址,這個常數(shù)值的范圍必須在SFR地址范圍內(nèi),位于0 x8
11、00 xFF。 例如: sfr SCON=0 x98; /* 串口控制寄存器地址98H */ sfr TMOD=0 x89;/* 定時器/計數(shù)器方式控制寄存器地址89H */,MCS-51系列單片機的特殊功能寄存器的數(shù)量與類型不盡相同,因此建議將所有特殊的sfr定義放入一個頭文件中,該文件應(yīng)包括MCS-51單片機系列機型中的SFR定義。C51編譯器的reg51.h頭文件就是這樣一個文件。 在新的MCS-51系列產(chǎn)品中,SFR在功能上經(jīng)常組合為16位值,當(dāng)SFR的高字節(jié)地址直接位于低字節(jié)之后時,對16位SFR的值可以直接進(jìn)行訪問。例如52子系列的定時器/計數(shù)器2就是這種情況。為了有效地訪問這類S
12、FR,可使用關(guān)鍵字sfr16來定義,其定義語句的語法格式與8位SFR相同,只是=后面的地址必須用16位SFR的低字節(jié)地址,即低字節(jié)地址作為sfr16的定義地址。,例如: sfr16 T2 = 0 xCC /*定時器/計數(shù)器2:T2低8位地址為0CCH,T2高8位地址為0CDH*/ 這種定義適用于所有新的16位SFR,但不能用于定時器/計數(shù)器0和1。 對于位尋址的SFR中的位,C51的擴充功能支持特殊位的定義,像SFR一樣不與標(biāo)準(zhǔn)C兼容,使用sbit來定義位尋址單元。,第一種格式: sbit bit-name = sfr-nameint constant; sbit是定義語句的關(guān)鍵字,后跟一個尋
13、址位符號名(該位符號名必須是MCS-51單片機中規(guī)定的位名稱),=后的sfr-name必須是已定義過的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為尋址地址位所在的特殊功能寄存器的
14、字節(jié)地址,符號后的int constant為尋址位在特殊功能寄存器中的位號。例如: sbit OV=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 */ 特殊功能位代表了一個獨立的定義類,不能與其它位定義和位域互換。,7.5 MCS-51并行接口的C
15、51定義,MCS-51系列單片機并行I/O接口除了芯片上的4個I/O口(P0 P3)外,還可以在片外擴展I/O口。MCS-51單片機I/O口與數(shù)據(jù)存儲器統(tǒng)一編址,即把一個I/O口當(dāng)作數(shù)據(jù)存儲器中的一個單元來看待。 使用C51進(jìn)行編程時,MCS-51片內(nèi)的I/O口與片外擴展的I/O可以統(tǒng)一在一個頭文件中定義,也可以在程序中(一般在開始的位置)進(jìn)行定義,其定義方法如下: 對于MCS-51片內(nèi)I/O口按特殊功能寄存器方法定義。例如: sfr P0=0 x80 ; /* 定義P0口,地址為80H */ sfr P1=0 x90 ; /* 定義P1口,地址為90H */,對于片外擴展I/O口,則根據(jù)硬件
16、譯碼地址,將其視作為片外數(shù)據(jù)存儲器的一個單元,使用#define語句進(jìn)行定義。例如 #include #define PORTA XBYTE 0 xFFC0 absacc.h是C51中絕對地址訪問函數(shù)的頭文件,將PORTA定義為外部I/O口,地址為 FFC0H,長度為8位。 一旦在頭文件或程序中對這些片外I/O口進(jìn)行定義后,在程序中就可以自由使用變量名與其實際地址的聯(lián)系,以便使程序員能用軟件模擬MCS-51的硬件操作。,(1) 位變量C51定義。使用C51編程時,定義了位變量后,就可以用定義了的變量來表示MCS-51的位尋址單元。 位變量的C51定義的一般語法格式如下: 位類型標(biāo)識符(bit)
17、 位變量名; 例如: bit direction_bit ;/* 把direction_bit定義為位變量 */ 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)
18、 對位變量定義的限制。位變量不能定義成一個指針,如不能定義:bit * bit_pointer。不存在位數(shù)組,如不能定義: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定義可獨立尋址訪問的對象位: sb
19、it mybit0 = ibase0 ;/* mybit0定義為ibase的第0位 */ sbit mybit15 = ibase15;/* 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,否則只
20、有絕對的特殊位定義(sbit)是合法的。操作符后的最大值依賴于指定的基類型,對于char/uchar而言是07,對于int/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存儲器中定義
21、了一個指向字符型(char)的指針變量px。指針自身在默認(rèn)存儲區(qū)(決定于編譯模式),長度為2個字節(jié)(值為00 xFFFF)。 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ù)存儲器(xda
22、ta),指針pxtime具有兩個字節(jié)長度。,struct time idata *ptime ; 這個聲明定義了一個位于默認(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é)偏移地址,即,其中,第
23、一字節(jié)代表了指針的存儲器類型,存儲器類型編碼如下:,例如,以xdata類型的0 x1234地址為指針可以表示如下:,當(dāng)用常數(shù)作指針時,必須注意正確定義存儲器類型和偏移量。 例如,將常數(shù)值0 x41寫入地址為0 x8000的外部數(shù)據(jù)存儲器。 #define XBYTE ( (char *) 0 x20000L) XBYTE0 x8000 = 0 x41 ; 其中,XBYTE被定義為(char *)0 x20000L,0 x20000L為一般指針,其存儲類型為2,偏移量為0000H,這樣XBYTE成為指向xdata零地址的指針。而XBYTE8000則是外部數(shù)據(jù)存儲器的0 x8000絕對地址。,7.
24、8 模塊化程序開發(fā)過程,圖7.4 程序開發(fā)過程,7.8.1 混合編程,1命名規(guī)則,表7.5 函數(shù)名的轉(zhuǎn)換,例2 用匯編語言編寫函數(shù)toupper,參數(shù)傳遞發(fā)生在寄存器R7中。 UPPER SEGMENT CODE ;程序段 PUBLIC _TOUPPER ;入口地址 PSEG UPPER ; 程序段 _TOUPPER: MOV A,R7 ;從R7中取參數(shù) CJNE A,# a,$+3 JC UPPERET CJNE A, # z+1 ,$+3 JNC UPPERET CLR ACC ,5 UPPERET: MOV R7 ,A ;返回值放在R7中 RET ;返回到C,2參數(shù)傳遞規(guī)則,表7.6 參
25、數(shù)傳遞的寄存器選擇,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ù),在R4R7中傳遞;h是第二個參數(shù),必須在參數(shù)傳遞段中傳遞。,表7.7 函數(shù)返回值的寄存器,在匯編子程序中,當(dāng)前選擇的寄存器組及寄存
26、器ACC、B、DPTR和PSW都可能改變。當(dāng)被C調(diào)用時,必須無條件地假設(shè)這些寄存器的內(nèi)容已被破壞。如果已在連接/定位程序時選擇了覆蓋,那么每個匯編子程序包含一個單獨的程序段是必要的,因為在覆蓋過程中,函數(shù)間參量通過子程序各自的段參量計算。匯編子程序的數(shù)據(jù)區(qū)甚至可包含在覆蓋部分中,但應(yīng)注意下面兩點: (1) 所有段名必須以C51類似的方法建立。 (2) 每個有局部變量的匯編程序必須指定自己的數(shù)據(jù)段,這個數(shù)據(jù)段只能為其它函數(shù)訪問作參數(shù)傳遞用。所有參數(shù)一個接一個被傳遞,由其它函數(shù)計算的結(jié)果保存入棧。,7.8.2 覆蓋和共享,1覆蓋 單片機片內(nèi)存儲空間有限,連接器/定位器通常重新啟用程序不再用的位置。
27、這就是說,若一個程序不再調(diào)用,也不由其它程序調(diào)用(甚至間接調(diào)用),那么在其它程序執(zhí)行完之前,這個程序不再運行。這個程序的變量可以放在與其它程序完全相同的RAM空間,很像可重用的寄存器。這種技術(shù)就是覆蓋。在匯編中直接通過手工完成的這些空間分配,C語言中可以由連接器自動管理。若有幾個不相關(guān)聯(lián)的程序時,它可以使RAM單元比手工考慮要用的少。,2共享 1) 共享變量,2) 共享函數(shù)/子程序 C中函數(shù)若是全局的(公用的),可以放在調(diào)用的函數(shù)之后。若函數(shù)是模塊專用的,它可以定義為靜態(tài)函數(shù),這樣它不能被其它模塊調(diào)用。C語言的ANSI標(biāo)準(zhǔn)建議所有函數(shù)在主函數(shù)前要有原型(進(jìn)行說明),然后實際函數(shù)可在主函數(shù)之后或
28、其它模塊中。這符合自頂向下編程的概念。 匯編語言中,子程序使用標(biāo)號可在給定模塊的任何位置。匯編器首先掃描得到所有的符號名,然后值就可填入LCALL或LJMP。一個模塊或另一模塊共享子程序,一個使用PUBLIC而另一個使用EXTERN。當(dāng)指定為EXTERN,符號類型(CODE,DATA,XDATA,IDATA,BIT或NUMBER)必須特別加以指定,以便連接器可以確定放在一起的正確類型。,7.8.3 庫和連接器/定位器 1. 庫,表7.9 Franklin C51的編譯庫,2連接器/定位器 1) 組合程序模塊 將幾個不同程序模塊組合為一個模塊,并自動從庫中挑選模塊嵌入目標(biāo)文件。輸入文件按命令行中
29、出現(xiàn)的順序處理。通常的程序模塊是由C51編譯器或A51宏匯編生成的可重入的目標(biāo)文件。,2) 組合段 將具有相同段名的可重定位段組合成單一的段。在一個程序模塊中定義的一個段成為部分段。一個部分段在源文件中以下列形式指定: (1) 名字 每個重定位段有一個名字,它可與來自其它模塊的同名的可重定位段組合。絕對段沒有名字。 (2) 類型 類型表明段所屬的地址空間CODE,XDATA,DATA或BIT。,(3) 定位方式 可重定位段的定位方式有PAGE,INPAGE,INBLOCK,BITADD RESSABLE或UNIT。INPAGE表明段必須放入一頁(高8位地址相同)中以使用短轉(zhuǎn)移和調(diào)用指令。INB
30、LOCK段應(yīng)使用ACALL,必須放在2048字節(jié)塊中。因為沒有連接器可以靈活地判知調(diào)用和轉(zhuǎn)移是否在塊內(nèi)??芍囟ㄎ坏钠渌拗剖牵篜AGE-不能超過256字節(jié);BITADDRESSABLE-必須放在可位尋址的內(nèi)部RAM空間;UNIT-允許段從任意字節(jié)開始(對位變量是位)。 (4) 長度 一個段的長度。,(5) 基址 段的首址。對于絕對段,地址由匯編器賦予,對于可重定位段,地址由L51決定。在處理程序模塊時,L51自動產(chǎn)生段表(MAP),該表包含了每個段的類型、基址、長度、可重定位性和名字。 L51自動將所具有相同名字的所有部分段組合到單一可重定位段中。例如,三個程序模塊包含字段VAR,在組合時,三
31、個段的長度相加,從而組合段的長度也增加了。對組合段有下列規(guī)則: 所有具有相同名的部分段必須有相同類型(CODE,DATA,IDATA,XDATA或BIT)。 組合段的長度不能超過存儲區(qū)的物理長度。 每個組合的部分段的定位方法也必須相同。 絕對段相互不組合,它們被直接拷貝到輸出文件。,3) 存儲器分配,表7.10 MCS-51系列的物理存儲區(qū),4) 采用覆蓋技術(shù)使用數(shù)據(jù)存儲器 通過采用一定的覆蓋技術(shù),MCS-51系列少量的片內(nèi)數(shù)據(jù)存儲器可由L51有效地使用。由C51編譯器或是A51匯編器生成的參數(shù)和局部變量(若使用它們的函數(shù)不相互調(diào)用)可在存儲器中覆蓋。這樣,所用的存儲器得到相當(dāng)程度地減少。 為
32、完成數(shù)據(jù)覆蓋,L51分析所有不同函數(shù)間的調(diào)用,使用該信息可以確定哪個數(shù)據(jù)和位段可被覆蓋。使用控制參數(shù)OVERLAY和NOOVERLAY可允許或禁止覆蓋。OVERLAY是默認(rèn)值,用它可產(chǎn)生非常緊湊的數(shù)據(jù)區(qū)。,5) 決定外部參考地址 具有相同名的外部符號(EXTERN)和公用符號(PUBLIC)被確定后,外部符號指向其它模塊中的地址。一個已聲明的外部符號用具有相同名字的功用符號確定,外部參考地址由其公共參考地址確定。這還與類型(DATA,IDATA,XDATA,CODE,BIT或NUMBER)有關(guān),如果類型不符或未發(fā)現(xiàn)外部符號參考地址的公用符號,則會產(chǎn)生錯誤。公用符號的絕對地址在段定位后決定。,6
33、) 絕對地址計算 定義絕對地址并計算可重定位段的地址。在段分配和外部公用參考地址處理完后,程序模塊中所有可重定位地址和外部地址要進(jìn)行計算,此時生成的目標(biāo)文件中的符號信息(DEBUG)被改變以反映新的值。,7) 產(chǎn)生絕對目標(biāo)文件 可執(zhí)行程序以絕對目標(biāo)格式產(chǎn)生。該絕對目標(biāo)文件可包含附加的符號信息(DEBUG),從而使符號調(diào)試成為可能。符號信息可用參數(shù)NODEBUGSYMBOLS,NODEBUGPUBLICS和NODEBUGLINES禁止。輸出文件是可執(zhí)行的,并可由仿真器裝入調(diào)試或被OHS51翻譯為Intel HEX格式文件以供EPROM固化。,8) 產(chǎn)生映像文件 產(chǎn)生一個反映每個處理步驟的映像文件
34、,它顯示有關(guān)連接/定位過程的信息和程序符號,并包含一個公用和外部符號的交叉參考報告。映像文件包含下列信息: 文件名和命令行參數(shù)。 模塊的文件名和模塊名。 一個包含段地址、類型、定位方法和名字的存儲器分配表。該表可在命令行中用NOMAP參考禁止。, 段和符號的所有錯誤列表。列表文件末尾顯示出所有出錯的原因。 一個包含輸入文件中符號信息的符號表。該信息由MODULES,SYMBOLS,PUBLICS和LINES名組成,LINES是C編譯器產(chǎn)生的行號。符號信息可用參數(shù)NOSYMBOLS,NOPUBLICS和NOLINES完全或部分禁止。 一個按字母順序排列的有關(guān)所有PUBLIC和EXTERN符號的交
35、叉參考報告,其中顯示出符號類型和模塊名。第一個顯示的模塊名是定義了PUBLIC符號的模塊,后面的模塊名是定義了EXTERN符號的模塊。在命令行輸入?yún)?shù)IXREF可產(chǎn)生此報告。 在連接器/定位器運行期間檢測到的錯誤同時顯示在屏幕和文件尾部。,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)部R
36、AM容量的限制(128256字節(jié),由使用的單片機決定),必須權(quán)衡利弊以解決訪問效率和這些對象的數(shù)量之間的矛盾。,(3) 要考慮操作順序,完成一件事后再做一件事。 (4) 注意程序編寫細(xì)則。例如,若使用for(;)循環(huán),DJNZ指令比CJNE指令更有效,可減少重復(fù)循環(huán)次數(shù)。 (5) 若編譯器不能使用左移和右移完成乘除法,應(yīng)立即修改,例如,左移為乘2。 (6) 用邏輯AND/ void stair(void) uint i ; for ( i=0 ; i=4095 ; i=i+UP ) /* 以階高增量增值,形成梯形波輸出值,最大4095*/ DA7521L= i % 256 ; /* 送低8位數(shù)
37、據(jù)到第一級緩沖器 */ DA7521H= i /256 ; /* 送高4位數(shù)據(jù)到高4位緩沖器,同時送低8位到第二級 /* 緩沖轉(zhuǎn)換 */ dlms ( T ) ; /* 延時 */ ,7.11 頻率量測量的C語言編程,7.11.1 測量頻率法 測量頻率法的最簡單的接口電路,可將頻率脈沖直接連接到MCS-51的T1端,將8031的T/C0用作定時器,T/C1用作計數(shù)器。在T/C0定時時間里,對頻率脈沖進(jìn)行計數(shù)。T/C1的計數(shù)值便是單位定時時間里的脈沖個數(shù)。,例14 帶同步控制的頻率測量。,圖7.14 帶同步控制的頻率測量法接口,控制時,首先P1.0發(fā)一個清零負(fù)脈沖,使U1、U2兩個D觸發(fā)器復(fù)位,
38、其輸出封鎖與門G1和G2。接著由P1.1發(fā)一個啟動正脈沖,其有效上升沿使U1=1,門G1被開放。之后,被測脈沖上升沿通過G2送T1計數(shù);同時U2輸出的高電平使INT0 =1,定時器0的門控GATE有效,啟動T/C0開始定時。直到定時結(jié)束時,從P1.0發(fā)一負(fù)脈沖,清零 U2,封鎖G2,停止T/C1計數(shù),完成一次頻率采樣過程。,測量T/C定時時間為500 ms,這樣長的時間定時,先由T/C0定時100 ms,之后軟件5次中斷后的時間即為5100 ms=500 ms。中斷次數(shù)的計數(shù)值在msn中。 T/C0定時100 ms的計數(shù)初值:03B0H。計數(shù)器1采用16位計數(shù)。設(shè)T/C0為高優(yōu)先級,允許計數(shù)中
39、斷過程定時中斷,即定時時間到就中止計數(shù)。tf為500 ms定時時間到標(biāo)志。程序如下:,#include #define uchar unsigned char #define uint unsigned int #define A 5 /*500 ms 的中斷次數(shù)*/ sbit P1_0=P10; sbit P1_1=P11; uchar msn=A; bit idata tf=0; /*500 ms時間到標(biāo)志*/,uint count(void) P1_0=0 ; P1_0=1; /*產(chǎn)生清零用負(fù)脈沖*/ TMOD=0 x59 ; TH1=0 x00; TL1=0 x00;/* T/C1計數(shù)
40、器 */ TH0=0 x3c ;TL0=0 xb0; /* T/C0定時器100 ms */ TR0=1;TR1=1;PT0=1;ET0=1;ET1=1;EA=1; /*啟動T/C,開中斷*/ P1_1=0 ; P1_1=1 ; /* 產(chǎn)生啟動正脈沖 */ while (tf!=1 ) ; /* 等待500 ms定時到 */ P1_0=0 ; P1_0=1 ; /* 產(chǎn)生負(fù)脈沖,封鎖G2 */ TR0=0 ; TR1=0 ; /* 關(guān)T/C */ return (TH1*256+TL1) ; / 返回計數(shù)值*/ ,void timer0( void ) interrupt 1 using 1
41、/* 100 ms定時中斷服務(wù) */ TH0=0 x3c ; /* 重置初值 */ TL0=-0 xb0 ; msn - - ; if ( msn = = 0) msn=A ; tf=1 ; /* 500 ms定時時間到設(shè)標(biāo)志 */ void timer 1 (void ) interrupt 3 void main ( void ) float rate ; rate=( 10/A )* count( ) ; /* 得每秒的計數(shù)率 */ ,7.11.2 頻率脈沖的測量周期法,圖7.15 周期測量接口,圖7.16 頻率與周期波,例15 測量周期的程序舉例。 設(shè)fosc = 6 MHz,機器周期
42、為2 s,測周期的測量值為計數(shù)值乘以2。用C語言編寫的程序如下: #include #define uint unsigned int sbit P1_0=P10; uint count ,period; bit rflag=0; / * 周期標(biāo)志 */ void control (void) ,TMOD=0 x09; /*定時器/計數(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/C0開中斷*/ void int_0(void)interrupt 0 using 1 /* I
43、NT0 中斷服務(wù)*/ EA=0;TR0=0; count=TL0+TH0*256; /* 取計數(shù)值 */ rflag=1; /* 設(shè)標(biāo)志 */ EA=1; ,void main(void) contro1( ); while(rflag=0); /* 等待一周期 */ period=count*2; /* fosc=6 MHz,2 s計數(shù)增1,周期值單位s */ ,7.12 MCS-51機間通信的C語言編程,7.12.1 點對點的串行異步通信 1通信雙方的硬件連接,圖 7.17 8031間RS232C電平信號的傳,2通信雙方的約定,圖 7.18 點對點通信的程序框圖,3. 點對點通信編程 點對
44、點通信雙方基本等同,只是人為規(guī)定一個為發(fā)送,一個為接收。要求兩機串行口的波特率相同,因而發(fā)送和接收方串行口的初始化相同??删幹坪谐跏蓟瘮?shù)、發(fā)送函數(shù)接收函數(shù)的程序,在主函數(shù)中根據(jù)程序的發(fā)送、接收設(shè)置TR,采用條件判別決定使用發(fā)送函數(shù)還是接收函數(shù)。這樣點對點通信的雙方都可運行此程序,只需在程序運行之前人為設(shè)置選擇TR,一個令TR=0,一個令TR=1,然后分別編譯,在兩機上分別裝入,同時運行。,例16 點對點通信。 點對點通信的程序如下:,#include #define uchar unsigned char #define TR 1 /*發(fā)送接收差別值TR=0發(fā)送*/ uchar idata
45、 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); /*等待B機回答*/ RI=0; while(SBUF0 xb
46、b)!=0); /*B機未準(zhǔn)備好,繼續(xù)聯(lián)絡(luò)*/ do pf=0; /*清校驗和*/ for ( i=0;i16;i+) SBUF=di; /*發(fā)送一個數(shù)據(jù)*/ pf+ =di; /*求校驗和*/ while(TI= =0);TI=0; SBUF=pf; /*發(fā)送校驗和*/,while(TI= =0);TI=0; while(RI= =0);RI=0; /*等待B機回答*/ while(SBUF!=0); /*回答出錯,則重發(fā)*/ void receive (uchar idata *d) uchar i; do while (RI= =0); RI=0; while (SBUF0 xaa)!
47、=0); /*判A機請求否*/ SBUF=0 xbb; /*發(fā)應(yīng)答信號*/,while (TI= =0); TI=0; while (1) pf=0; /*清校驗和*/ for ( i=0;i16;i+) while (RI= =0); RI=0; d i =SBUF; /*接收一個數(shù)據(jù)*/ pf+ =di; /*求校驗和*/ while (RI= =0); RI=0; /*接收A機校驗和*/ if (SBUF pf) = =0) /*比較校驗和*/ SBUF=0 x00; break; /*校驗和相同發(fā)00*/ else SBUF=0 xff; /*出錯發(fā)FF,重新接收*/,while(TI
48、= =0); TI=0; void main (void) init ( ); if(TR= =0) send(buf); else receive(buf); ,7.12.2 多機通信 1通信接口,圖 7.19 總線式主從式多機系統(tǒng),2通信協(xié)議,根據(jù)MCS-51串行口的多機通信能力,多機通信可以按照以下協(xié)議進(jìn)行: (1) 首先使所有從機的SM2位置1處于只接收地址幀的狀態(tài)。 (2) 主機先發(fā)送一幀地址信息,其中8位地址,第9位為地址/數(shù)據(jù)信息的標(biāo)志位,該位置1表示該幀為地址信息。 (3) 從機接收到地址幀后,各自將接收的地址與本機的地址比較。對于地址相符的那個從機,使SM2位清零,以接收主機
49、隨后發(fā)來的所有信息;對于地址不符的從機,仍保持SM2=1,對主機隨后發(fā)來的數(shù)據(jù)不予理睬,直至發(fā)送新的地址幀。,(4) 當(dāng)從機發(fā)送數(shù)據(jù)結(jié)束后,發(fā)送一幀校驗和,并置第9位(TB8)為1,作為從機數(shù)據(jù)傳送結(jié)束標(biāo)志。 (5) 主機接收數(shù)據(jù)時先判斷數(shù)據(jù)結(jié)束標(biāo)志(RB8),若RB8=1,表示數(shù)據(jù)傳送結(jié)束,并比較此幀校驗和,若正確,則會送正確信號00H,此信號令該從機復(fù)位(即重新等待地址幀);若校驗和出錯,則發(fā)送0FFH,令該從機重發(fā)數(shù)據(jù)。若接收幀的RB8=0,則原數(shù)據(jù)到緩沖區(qū),并準(zhǔn)備接收下幀信息。 (6) 若主機向從機發(fā)送數(shù)據(jù),從機在第(3)步中比較地址相符后,從機令SM2=0,同時把本站地址發(fā)回主機。作
50、為應(yīng)答之后才能收到主機發(fā)送來的數(shù)據(jù)。其它從機(SM2=1),無法收到數(shù)據(jù)。,(7) 主機收到從機的應(yīng)答地址后,確認(rèn)地址是否相符。如果地址不符,發(fā)復(fù)位信號(數(shù)據(jù)幀中TB8=1);如果地址相符,則清TB8,開始發(fā)送數(shù)據(jù)。 (8) 從機接收到復(fù)位命令后回到監(jiān)聽地址狀態(tài)(SM2=1)。否則開始接收數(shù)據(jù)和命令。,3. 通信程序 設(shè)主機發(fā)送的地址聯(lián)絡(luò)信號00H,01H,02H為從機設(shè)備地址,地址FFH是命令各從機恢復(fù)SM2為1的狀態(tài),即復(fù)位。主機的命令編碼為: 01H 請求從機接收主機的數(shù)據(jù)命令; 02H 請求從機向主機發(fā)送數(shù)據(jù)命令。 其它都按從機向主機發(fā)送數(shù)據(jù)命令02H對待。,從機的狀態(tài)字節(jié)格式為:,D
51、7 D6 D5 D4 D3 D2 D1 D0,RRDY=1:從機準(zhǔn)備好接收主機的數(shù)據(jù)。 TRDY=1:從機準(zhǔn)備好向主機發(fā)送數(shù)據(jù)。 ERR=1:從機接收到的命令是非法的。 通常從機以中斷方式控制和主機的通信。程序可分成主機程序和從機程序,約定一次傳送的數(shù)據(jù)為16個字節(jié),以02H地址的從機為例。,1) 主機程序,圖7.20 多機通信主機程序流程圖,主機程序如下: #include #define uchar unsigned char #define SLAVE 0 x02 /*從機地址*/ #define BN 16 uchar idata rbuf 16; uchar idata tbuf 1
52、6=master transmit; void err (void) SBUF=0 xff; while(TI!=1);TI=0; ,uchar master (char addr, uchar command) uchar aa, i,p; while(1) SBUF=SLAVE; /* 發(fā)呼叫地址 */ while (TI!=1);TI=0; while (RI!=1);RI=0; /* 等待從機回答 */ if(SBUF!=addr) err( ); /* 若地址錯,發(fā)復(fù)位信號 */ else /* 地址相符 */ TB8=0; /* 清地址標(biāo)志 */ SBUF=command; /*
53、發(fā)命令 */ while (TI!=1);TI=0; while (RI!=1);RI=0;,aa=SBUF; /* 接收狀態(tài) */ if(aa void str ( void ) /* 發(fā)數(shù)據(jù)塊 */ uchar p ,i ; tready =0 ; do p=0 ; /* 清校驗和 */,for ( i= 0; iBN ; i+ ) SBUF= trbuf i ; /* 發(fā)送一數(shù)據(jù) */ p+=trbufi ; while ( TI !=1 ) ; TI =0 ; SUBF= p ; /* 發(fā)送校驗和 */ while ( TI = =0 ) ; TI =0; while ( RI= =0
54、 ); RI =0 ; while ( SBUF !=0 ) ; /* 主機接收不正確,重新發(fā)送 */ SM2=1 ; ES = 1 ; ,void sre ( void ) / * 接收數(shù)據(jù)塊 */ uchar p , i ; rready = 0 ; while ( 1 ) p= 0 ; /* 清校驗和 */ for ( i =0 ; i BN ; i+) while ( RI !=1 );RI =0 ; rebuf i =SBUF ; /* 接收數(shù)據(jù) * / p+=rebuf i ; ,while ( RI !=1 ) ;RI =0 ; if ( SBUF = = p ) SBUF= 0
55、 x00 ; break ; /* 校驗和相同發(fā)00*/ else SBUF=0 xff ; /* 校驗和不同發(fā)0FF,重新接收 */ while ( TI = = 0 ) ;TI=0; SM2 = 1 ; ES = 1 ; ,7.13 鍵盤和數(shù)碼顯示人機交互的C語言編程,7.13.1 行列式鍵盤與8031的接口 鍵盤輸入信息的主要過程是: (1) 單片機判斷是否有鍵按下。 (2) 確定按下的是哪一個鍵。 (3) 把此步驟代表的信息翻譯成計算機所能識別的代碼,如ASCII或其它特征碼。,圖7.22 8031與行列式鍵盤的接口,例17 44鍵盤的掃描程序。 掃描程序查詢的內(nèi)容為: (1) 查詢是
56、否有鍵按下。首先單片機向行掃描P1.0 P1.3輸出全為0掃描碼F0H,然后從列檢查口P1.4 P1.7輸入列掃描信號,只要有一列信號不為1,即P1口不為F0H,則表示有鍵按下。接著要查出按下鍵所在的行、列位置。,(2) 查詢按下鍵所在的行列位置。單片機將得到的信號取反,P1.4P1.7中的為1的位便是鍵所在的列。接下來要確定鍵所在的行,需要進(jìn)行逐行掃描。單片機首先使P1.0為0,P1.1P1.7為1,即向P1口發(fā)送掃描碼FEH,接著輸入列檢查信號,若全為1,表示不在第一行。接著使P1.1接地,其余為1,再讀入列信號這樣逐行發(fā)0掃描碼,直到找到按下鍵所在的行,將該行掃描碼取反保留。當(dāng)各行都掃描
57、以后仍沒有找到,則放棄掃描,認(rèn)為是鍵的誤動作。,(3) 對得到的行號和列號譯碼,得到鍵值。 (4) 鍵的抖動處理。當(dāng)用手按下一個鍵時,往往會出現(xiàn)所按鍵在閉合位置和斷開位置之間跳幾下才穩(wěn)定到閉合狀態(tài)的情況。在釋放一個鍵時,也會出現(xiàn)類似的情況,這就是鍵抖動,抖動的持續(xù)時間不一,通常不會大于10 ms,若抖動問題不解決,就會引起對閉合鍵的多次讀入,對于鍵抖動最方便的解決方法就是當(dāng)發(fā)現(xiàn)有鍵按下后,不是立即進(jìn)行逐行掃描,而是延時10 ms后再進(jìn)行。由于鍵按下的時間持續(xù)上百毫秒,延時后再也不遲。,掃描函數(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 ( ) ; dlm
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 室內(nèi)墻面貼磚施工方案
- 小學(xué)《道德與法治》三年級下冊“我們的公共生活”單元深度學(xué)習(xí)方案設(shè)計
- 年度大型活動籌備方案與分工
- 醫(yī)院儲備工作方案范文
- 開學(xué)季運輸保障工作方案
- 監(jiān)事會換屆工作方案
- 2026年數(shù)字文旅項目分析方案
- 游泳館規(guī)劃建設(shè)方案
- 企業(yè)工作建設(shè)方案怎么寫
- 新店的工作方案怎么寫好
- GB/T 2423.21-2025環(huán)境試驗第2部分:試驗方法試驗M:低氣壓
- 集團(tuán)公司職業(yè)技能等級認(rèn)定管理辦法
- 2024~2025學(xué)年四川省成都市武侯區(qū)九年級上學(xué)期期末語文試卷
- 2025年紫金礦業(yè)ai面試題目及答案
- 吸氧并發(fā)癥及護(hù)理措施
- 復(fù)發(fā)性叢集性頭痛
- 宮頸息肉個案護(hù)理
- 新生兒感染護(hù)理查房
- (二調(diào))武漢市2025屆高中畢業(yè)生二月調(diào)研考試 生物試卷(含標(biāo)準(zhǔn)答案)
- 2024-2025學(xué)年天津市和平區(qū)高三上學(xué)期1月期末英語試題(解析版)
- 管理人員應(yīng)懂財務(wù)知識
評論
0/150
提交評論