《單片機(jī)原理及應(yīng)用》課件第8章_第1頁
《單片機(jī)原理及應(yīng)用》課件第8章_第2頁
《單片機(jī)原理及應(yīng)用》課件第8章_第3頁
《單片機(jī)原理及應(yīng)用》課件第8章_第4頁
《單片機(jī)原理及應(yīng)用》課件第8章_第5頁
已閱讀5頁,還剩233頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第8章單片機(jī)C語言應(yīng)用程序設(shè)計(jì)18.1C語言與51單片機(jī)8.2C51數(shù)據(jù)類型及其在51單片機(jī)中的存儲(chǔ)方式8.3C51數(shù)據(jù)的存儲(chǔ)類型與51單片機(jī)存儲(chǔ)結(jié)構(gòu)8.451單片機(jī)特殊功能寄存器的C51定義8.551單片機(jī)并行接口的C51定義8.6位變量的C51定義8.7C51的指針8.8與使用51單片機(jī)內(nèi)部資源有關(guān)的頭文件8.951單片機(jī)內(nèi)部資源應(yīng)用的C語言編程8.1051單片機(jī)片外擴(kuò)展的C語言編程8.11頻率、周期測量的C語言編程8.1251單片機(jī)間通信的C語言編程8.13鍵盤和數(shù)碼顯示人機(jī)交互的C語言編程在單片機(jī)應(yīng)用系統(tǒng)開發(fā)中,應(yīng)用程序設(shè)計(jì)是整個(gè)系統(tǒng)設(shè)計(jì)的主要工作,直接決定應(yīng)用系統(tǒng)開發(fā)周期的長短。在過去,單片機(jī)應(yīng)用程序設(shè)計(jì)都采用匯編語言。采用匯編語言編寫應(yīng)用程序,可直接操縱系統(tǒng)的硬件資源,編寫出高質(zhì)量的程序代碼。但是,采用匯編語言編寫比較復(fù)雜的數(shù)值計(jì)算程序非常困難,又因匯編語言源程序的可讀性遠(yuǎn)不如高級(jí)語言源程序,若要修改一下程序的功能,得花費(fèi)心思重頭閱讀程序。隨著計(jì)算機(jī)應(yīng)用技術(shù)的發(fā)展,軟件開發(fā)工具日益豐富,出現(xiàn)了眾多支持高級(jí)語言編程的單片機(jī)開發(fā)工具。利用C語言設(shè)計(jì)單片機(jī)應(yīng)用程序已經(jīng)成為單片機(jī)應(yīng)用系統(tǒng)開發(fā)設(shè)計(jì)的一種趨勢。使用C語言編程更符合人的思維方式和思考習(xí)慣,編寫代碼效率高、維護(hù)方便。采用C語言,易于開發(fā)復(fù)雜的單片機(jī)應(yīng)用程序,有利于進(jìn)行單片機(jī)產(chǎn)品的重新選型和應(yīng)用程序的移植,大大提高了單片機(jī)應(yīng)用程序的開發(fā)速度?,F(xiàn)在,單片機(jī)仿真器普遍支持C語言程序調(diào)試,為使用C語言進(jìn)行單片機(jī)程序開發(fā)提供了便利的條件。世界上許多軟件公司都致力于51系列單片機(jī)高級(jí)語言編譯器的開發(fā)研究,給用戶采用高級(jí)語言編程提供了強(qiáng)有力的支持。本章從單片機(jī)應(yīng)用特點(diǎn)的角度出發(fā),結(jié)合Keil公司的C51編譯器,介紹51單片機(jī)C語言應(yīng)用程序開發(fā)設(shè)計(jì)的技術(shù)方法。8.1

C語言與51單片機(jī)8.1.1

51單片機(jī)C語言編程簡介

C語言是高級(jí)程序設(shè)計(jì)語言。用高級(jí)語言編程時(shí),不必太多考慮計(jì)算機(jī)的硬件特性和接口結(jié)構(gòu)。事實(shí)上,任何高級(jí)語言程序最終必須要轉(zhuǎn)換成計(jì)算機(jī)可識(shí)別、并能執(zhí)行的機(jī)器指令代碼,定位于存儲(chǔ)器。程序中的數(shù)據(jù)也必須以一定的存儲(chǔ)結(jié)構(gòu)定位于存儲(chǔ)器中。這種轉(zhuǎn)換、定位是由高級(jí)語言編譯器來實(shí)現(xiàn)的。在高級(jí)語言程序中,對不同類型數(shù)據(jù)的存儲(chǔ)及引用是通過不同類型的變量來實(shí)現(xiàn)的。也可以說,高級(jí)語言的變量就代表存儲(chǔ)單元,變量的類型結(jié)構(gòu)就表示了數(shù)據(jù)的存儲(chǔ)、引用結(jié)構(gòu)。用匯編語言設(shè)計(jì)51單片機(jī)應(yīng)用程序時(shí),必須考慮存儲(chǔ)器結(jié)構(gòu),尤其要考慮其片內(nèi)數(shù)據(jù)存儲(chǔ)器與特殊功能寄存器的正確、合理使用以及按實(shí)際地址處理端口數(shù)據(jù)。盡管采用C語言編寫51單片機(jī)應(yīng)用程序時(shí),不像用匯編語言那樣具體地組織、分配存儲(chǔ)器資源和處理端口數(shù)據(jù),甚至可以在對單片機(jī)內(nèi)部結(jié)構(gòu)和存儲(chǔ)器結(jié)構(gòu)不太熟悉、對處理器的指令集沒有深入了解的情況下編寫應(yīng)用程序,但要使編譯器產(chǎn)生充分利用單片機(jī)資源、執(zhí)行效率高、適合51單片機(jī)目標(biāo)硬件的程序代碼,對數(shù)據(jù)類型和變量的定義就必須與單片機(jī)的存儲(chǔ)結(jié)構(gòu)相關(guān)聯(lián),否則編譯器就不能正確地映射定位。

同時(shí),在C語言編程中,必須注意到單片機(jī)內(nèi)部資源的寶貴性和控制實(shí)時(shí)性的應(yīng)用特點(diǎn),考慮產(chǎn)生的可執(zhí)行代碼運(yùn)行時(shí)所占用的系統(tǒng)資源。因此,使用C語言編寫單片機(jī)應(yīng)用程序和編寫標(biāo)準(zhǔn)的C語言程序的主要不同之處就在于它是根據(jù)單片機(jī)存儲(chǔ)結(jié)構(gòu)及內(nèi)部資源定義相應(yīng)的C語言數(shù)據(jù)和變量,而其他的語法規(guī)定、程序結(jié)構(gòu)及程序設(shè)計(jì)方法都與標(biāo)準(zhǔn)的C語言程序相似。從這個(gè)角度來說,沒有對單片機(jī)硬件資源、體系結(jié)構(gòu)和指令系統(tǒng)的充分了解,就不能設(shè)計(jì)出非常實(shí)用、高質(zhì)量的單片機(jī)應(yīng)用程序。用C語言編寫的應(yīng)用程序必須經(jīng)過單片機(jī)C語言編譯器(簡稱C51)轉(zhuǎn)換成51單片機(jī)可執(zhí)行的代碼程序。所以,C語言編譯器是C語言應(yīng)用程序開發(fā)設(shè)計(jì)中必不可少的開發(fā)工具,C語言編譯器的好壞直接影響到生成代碼的效率、大小和可靠性。8.1.2

C51開發(fā)工具與單片機(jī)C語言編譯器下面對一些主要工具作簡要說明。

μVision項(xiàng)目管理器和編輯器:一個(gè)集成開發(fā)環(huán)境,它將項(xiàng)目管理、源代碼編輯、連接和程序調(diào)試等組合在一個(gè)功能強(qiáng)大的環(huán)境中。

C51國際標(biāo)準(zhǔn)優(yōu)化C交叉編譯器:從C源代碼產(chǎn)生可重定位的目標(biāo)模塊。

A51宏匯編器:從8051匯編源代碼產(chǎn)生目標(biāo)模塊。

BL51連接器/定位器:組合由C51和A51產(chǎn)生的可重定位的目標(biāo)模塊,生成絕對目標(biāo)模塊。

LIB51庫管理器:從目標(biāo)模塊生成連接器可以使用的庫文件。

OH51Object-HEX轉(zhuǎn)換器:從絕對目標(biāo)模塊生成IntelHEX文件。

RTX51實(shí)時(shí)操作系統(tǒng):簡化了復(fù)雜的實(shí)時(shí)應(yīng)用軟件項(xiàng)目的設(shè)計(jì)。上述工具是為專業(yè)軟件開發(fā)者設(shè)計(jì)的,但任何水平的編程者都可使用。Keil軟件公司將這些工具都集合在一個(gè)套件內(nèi)。為滿足不同用戶需求,將軟件開發(fā)工具進(jìn)行綁定,形成了不同的開發(fā)套件或工具包。

PK51專業(yè)開發(fā)套件:該套件提供了所有工具,適合為專業(yè)開發(fā)人員建立和調(diào)試51系列單片機(jī)的復(fù)雜嵌入式應(yīng)用。專業(yè)開發(fā)套件可針對具體的51系列單片機(jī)產(chǎn)品進(jìn)行配置使用。

DK51開發(fā)套件:該套件是PK51的精簡版,不包括RTX51Tiny實(shí)時(shí)操作系統(tǒng)。開發(fā)套件可針對8051及其所有派生產(chǎn)品進(jìn)行配置使用。

CA51編譯器套件:該套件是只需要C編譯器而不需要調(diào)試系統(tǒng)的開發(fā)者的最佳選擇,只包含μVisionIDE集成開發(fā)環(huán)境,不提供μVision調(diào)試器的功能。這個(gè)套件包括了要建立嵌入式應(yīng)用的所有工具軟件,可針對8051及其所有派生產(chǎn)品進(jìn)行配置使用。

A51匯編器套件:該套件包括一個(gè)匯編器和所有創(chuàng)建嵌入式應(yīng)用的工具。它可針對8051及其所有派生產(chǎn)品進(jìn)行配置使用。

RTX51實(shí)時(shí)操作系統(tǒng)(RF51):該系統(tǒng)是一個(gè)用于51系列單片機(jī)的實(shí)時(shí)內(nèi)核程序。RTX51Full實(shí)時(shí)內(nèi)核提供RTX51Tiny的所有功能和一些擴(kuò)展功能,并且包括CAN通信協(xié)議接口子程序。8.1.3

Keil80C51開發(fā)工具

C51的特色主要體現(xiàn)在以下幾個(gè)方面:

(1)?C51雖然繼承了標(biāo)準(zhǔn)C語言的絕大部分特征,而且基本用法相同,但它針對51系列單片機(jī)特定的硬件結(jié)構(gòu)有所擴(kuò)展,如數(shù)據(jù)類型、存儲(chǔ)模式、端口操作等。

(2)?C51的使用必須注重對51系列單片機(jī)系統(tǒng)資源的理解和掌握,因?yàn)橄鄬τ谕ㄓ梦⑿陀?jì)算機(jī),單片機(jī)的系統(tǒng)資源非常有限,開發(fā)人員對單片機(jī)的程序存儲(chǔ)器、數(shù)據(jù)存儲(chǔ)器等要充分、合理利用。

(3)要考慮應(yīng)用程序的代碼質(zhì)量,不要對系統(tǒng)造成過重的負(fù)擔(dān),如代碼優(yōu)化等問題。

KeilC51編譯器是符合ANSI標(biāo)準(zhǔn)的C編譯器。KeilC51語言擴(kuò)展支持51單片機(jī)的應(yīng)用包括:數(shù)據(jù)類型,存儲(chǔ)器類型,存儲(chǔ)器模型,指針,載入函數(shù),中斷函數(shù),實(shí)時(shí)操作系統(tǒng),PL/M和A51源文件接口。本章將介紹其中的主要擴(kuò)展功能。

8.2C51數(shù)據(jù)類型及其在51單片機(jī)中的存儲(chǔ)方式

8.2.1KeilC51中的基本數(shù)據(jù)類型

KeilC51支持的基本數(shù)據(jù)類型有位型(bit)、無符號(hào)字符型(unsignedchar)、有符號(hào)字符型(signedchar)、無符號(hào)整型(unsignedint)、有符號(hào)整型(signedint)、無符號(hào)長整型(unsignedlong)、有符號(hào)長整型(signedlong)和浮點(diǎn)型(float)等。

KeilC51具體支持的基本數(shù)據(jù)類型及其長度、數(shù)域如表8.1所示。除了這些類型外,還可以將基本類型組合成復(fù)雜數(shù)據(jù)結(jié)構(gòu)。通過表8.1可以看出:

(1)?C51具有標(biāo)準(zhǔn)C語言的標(biāo)準(zhǔn)數(shù)據(jù)類型。另外,為了充分利用51單片機(jī)的硬件結(jié)構(gòu),還擴(kuò)充了位變量(bit)、可尋址位(sbit)、特殊功能寄存器(sfr)和16位特殊功能寄存器(sfr16)數(shù)據(jù)類型。

(2)由于51單片機(jī)是8位機(jī),因而不存在字節(jié)校準(zhǔn)問題,這意味著數(shù)據(jù)結(jié)構(gòu)成員是順序放置的。擴(kuò)充的數(shù)據(jù)類型位變量(bit)、可尋址位(sbit)、特殊功能寄存器(sfr)和16位特殊功能寄存器(sfr16)專門用于51系列單片機(jī)硬件和C51編譯器,并不是ANSIC的一部分,不能通過指針進(jìn)行訪問。bit、sbit、sfr和sfr16數(shù)據(jù)類型可用于訪問51單片機(jī)的特殊功能寄存器。

當(dāng)在一個(gè)處理中遇到不同數(shù)據(jù)類型時(shí),C51編譯器自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型。例如,將一個(gè)位變量賦給一個(gè)整型變量時(shí),位型值自動(dòng)轉(zhuǎn)換為整型值。有符號(hào)變量的符號(hào)也能自動(dòng)進(jìn)行處理。這些轉(zhuǎn)換也可以用C語言的標(biāo)準(zhǔn)指令進(jìn)行人工轉(zhuǎn)換。8.2.2C51數(shù)據(jù)在51單片機(jī)中的存儲(chǔ)方式

雖然KeilC51支持表8.1列出的所有數(shù)據(jù)類型,但在51單片機(jī)中,只有bit和unsignedchar兩種直接支持機(jī)器指令。在C語言程序中使用其他數(shù)據(jù)類型,C51編譯器要調(diào)用一系列庫函數(shù)對其進(jìn)行復(fù)雜的數(shù)據(jù)類型處理。特別是當(dāng)使用浮點(diǎn)變量時(shí),將明顯地增加運(yùn)算時(shí)間和程序的長度。如果在編寫單片機(jī)C程序時(shí),不考慮單片機(jī)數(shù)據(jù)處理的特點(diǎn),無約束地使用大量的、不必要的變量類型,則將導(dǎo)致C51編譯器相應(yīng)地增加所調(diào)用庫函數(shù)的數(shù)量,以處理大量增加的變量類型,最終會(huì)使程序變得過于龐大,造成存儲(chǔ)器資源浪費(fèi),運(yùn)行速度減慢,甚至?xí)谶B接(link)時(shí)出現(xiàn)因程序過大而裝不進(jìn)代碼區(qū)的情況。所以,必須特別慎重地進(jìn)行變量和數(shù)據(jù)類型的選擇。

C程序中不同的類型數(shù)據(jù),最終在單片機(jī)中以不同的方式進(jìn)行存儲(chǔ)。下面說明表8.1所列數(shù)據(jù)類型在51系列單片機(jī)中的存儲(chǔ)方式。

位變量(bit):與51單片機(jī)硬件特性操作有關(guān)的位可以定義為位變量。位變量必須定位在51單片機(jī)的片內(nèi)RAM的位尋址空間中。字符變量(char):字符變量的長度為1字節(jié),正好存儲(chǔ)在51單片機(jī)的一個(gè)數(shù)據(jù)單元中。對于無符號(hào)字符變量類型(unsignedchar)的數(shù)據(jù),其字節(jié)中的所有位均用來表示數(shù)據(jù)的數(shù)值,它的值域范圍是0~255。對于有符號(hào)字符變量(signedchar),最具有重要意義的是最高位上的符號(hào)標(biāo)志位(msb),此位為0代表“正”,為1代表“負(fù)”。負(fù)數(shù)一般用補(bǔ)碼表示,例如11111111表示-1。當(dāng)進(jìn)行乘除法運(yùn)算時(shí),符號(hào)問題就變得十分復(fù)雜,C51編譯器會(huì)自動(dòng)地將相應(yīng)的庫函數(shù)調(diào)入程序中來解決這個(gè)問題。整型變量(int):整型變量長度為16位,在51系列單片機(jī)占用2個(gè)字節(jié)存儲(chǔ),數(shù)據(jù)的高位字節(jié)存放在低地址字節(jié)中,低位字節(jié)數(shù)放在高地址字節(jié)中。這與通用微機(jī)系統(tǒng)中的存儲(chǔ)結(jié)構(gòu)是不同的。有符號(hào)整型變量(signedint)也使用最高位作符號(hào)位,并使用二進(jìn)制補(bǔ)碼表示數(shù)值。例如:整型變量值0x1234以圖8.1所示的方式存儲(chǔ)。

長整型變量(longint):長整型變量長度為32位,在51系列單片機(jī)中按照由高位到低位的順序連續(xù)占用4個(gè)字節(jié)存儲(chǔ)。例如:長整型變量值0x12345678以圖8.2所示的方式存儲(chǔ)。圖8.1整型變量的存儲(chǔ)結(jié)構(gòu)圖8.2長整型變量的存儲(chǔ)結(jié)構(gòu)浮點(diǎn)型變量(float):浮點(diǎn)型變量為32位二進(jìn)制數(shù),占4

個(gè)字節(jié)。它用符號(hào)位表示數(shù)的符號(hào),用階碼和尾數(shù)表示數(shù)

的大小。

用它們進(jìn)行任何數(shù)學(xué)運(yùn)算都需要使用由編譯器決定的

各種不同效率等級(jí)的庫函數(shù)。KeilC51的浮點(diǎn)型數(shù)據(jù)是IEEE-754標(biāo)準(zhǔn)的單精度浮點(diǎn)型數(shù)據(jù),在十進(jìn)制中具有7位有效數(shù)字。

浮點(diǎn)型變量在內(nèi)存中的存放格式如下:其中,S為符號(hào)位,“0”表示正,“1”表示負(fù)。E為階碼,占用8位二進(jìn)制數(shù),存放在兩個(gè)字節(jié)中。階碼E是以2為底的指數(shù)再加上127,這樣避免了出現(xiàn)負(fù)的階碼值,而指數(shù)是可正可負(fù)的。階碼E的正常取值范圍是1~254,從而實(shí)際指數(shù)的取值范圍是?-126~127。M為尾數(shù)的小數(shù)部分,用23位二進(jìn)制數(shù)表示,存放在3個(gè)字節(jié)中。尾數(shù)的整數(shù)部分總為1,因此不用保存,它是隱含存在的。小數(shù)點(diǎn)位于隱含的整數(shù)位“1”的后面。一個(gè)浮點(diǎn)數(shù)的數(shù)值范圍是(-1)S×2E-127×(1.M)。例如,浮點(diǎn)數(shù)-12.5的存儲(chǔ)碼為0xC1480000,

(-12.5)10=(-1100.1)2=(-1.1001×23)

即S=1,EEEEEEEE=(127+3)10=(1111111+11)2=10000010

在存儲(chǔ)器中的存儲(chǔ)格式如下:值得注意的是,浮點(diǎn)型數(shù)據(jù)除了有正常數(shù)值之外,還可能出現(xiàn)非正常數(shù)值。根據(jù)IEEE標(biāo)準(zhǔn),當(dāng)浮點(diǎn)型數(shù)據(jù)取以下數(shù)值(十六進(jìn)制數(shù))時(shí),即為非正常值:

0xFFFFFFFNaN(非正常數(shù))

0x7F80000+INF(正無窮大)

0xFF80000-INF(負(fù)無窮大)由于51單片機(jī)不包括捕獲浮點(diǎn)運(yùn)算錯(cuò)誤的中斷向量,因此用戶必須根據(jù)可能出現(xiàn)的錯(cuò)誤條件,用軟件來進(jìn)行適當(dāng)?shù)奶幚怼O旅婢陀蟹?hào)/無符號(hào)(signed/unsigned)問題做一些說明。在編寫程序時(shí),如果使用signed和unsigned兩種數(shù)據(jù)類型,那么就得使用兩種格式類型的庫函數(shù),這將使占用的存儲(chǔ)空間成倍增長。因此,如果只強(qiáng)調(diào)程序的運(yùn)算速度而不進(jìn)行負(fù)數(shù)運(yùn)算,則最好采用無符號(hào)(unsigned)格式。無符號(hào)字符類型的使用:無論何時(shí),應(yīng)盡可能地使用無符號(hào)變量,因?yàn)樗苤苯颖?1單片機(jī)所接受?;谕瑯拥脑?也應(yīng)盡可能使用位變量。有符號(hào)字符變量雖然也只占用1個(gè)字節(jié),但需要進(jìn)行額外的操作來測試代碼的符號(hào)位,這無疑會(huì)降低代碼的效率。最后要提到的是使用縮寫形式定義數(shù)據(jù)類型。在編程時(shí),為了書寫方便,經(jīng)常使用簡化的縮寫形式來定義變量的數(shù)據(jù)類型。其方法是在源程序開頭使用#define語句。例如:

#defineucharunsignedchar

#defineuintunsignedint這樣,在以后的程序中,就可以用uchar代替unsignedchar,用uint代替unsignedint來定義變量。8.3

C51數(shù)據(jù)的存儲(chǔ)類型與

51單片機(jī)存儲(chǔ)結(jié)構(gòu)8.3.1存儲(chǔ)類型

51單片機(jī)中,程序存儲(chǔ)器與數(shù)據(jù)存儲(chǔ)器嚴(yán)格分開,數(shù)據(jù)存儲(chǔ)器又分為片內(nèi)、片外兩個(gè)獨(dú)立的尋址空間,特殊功能寄存器包含在片內(nèi)RAM空間,但不能用于存儲(chǔ)用戶數(shù)據(jù),這是51單片機(jī)與一般微機(jī)存儲(chǔ)器結(jié)構(gòu)有所不同的顯著特點(diǎn)。

KeilC51完全支持51單片機(jī)的硬件結(jié)構(gòu),提供了對所有存儲(chǔ)區(qū)的訪問機(jī)制。在C程序中定義數(shù)據(jù)對象(變量、常量等)時(shí),通過聲明存儲(chǔ)類型,將它們準(zhǔn)確定位在不同的存儲(chǔ)區(qū)中。

C51中定義變量的一般格式如下:數(shù)據(jù)類型存儲(chǔ)類型變量名

C51存儲(chǔ)類型與51單片機(jī)存儲(chǔ)區(qū)的對應(yīng)關(guān)系如表8.2所示。

C51存儲(chǔ)類型既確定數(shù)據(jù)對象的存儲(chǔ)區(qū),同時(shí)也限定了數(shù)據(jù)長度。存儲(chǔ)類型與存儲(chǔ)長度的限定關(guān)系如表8.3所示。下面舉例說明C51存儲(chǔ)類型。

(1)code:當(dāng)使用code存儲(chǔ)類型定義數(shù)據(jù)時(shí),C51編譯器會(huì)將其定位在程序存儲(chǔ)器空間,對code區(qū)的訪問和對xdata區(qū)的訪問時(shí)間是一樣的。程序存儲(chǔ)器空間的對象在編譯的時(shí)候初始化。下面是code存儲(chǔ)類型聲明的例子:

unsignedcharcodetab[16]={

0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,

0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15

};

charcodetext[]=“enterpassword”;

(2)?data:使用data存儲(chǔ)類型定義數(shù)據(jù)時(shí),C51編譯器會(huì)將其定位在片內(nèi)直接尋址的存儲(chǔ)器空間。定義data存儲(chǔ)類型時(shí)需注意以下兩點(diǎn):

片內(nèi)RAM存儲(chǔ)區(qū)能快速存取數(shù)據(jù),但容量非常有限,所以臨時(shí)性數(shù)據(jù)和頻繁使用的數(shù)據(jù)應(yīng)選擇data存儲(chǔ)類型。

片內(nèi)RAM存儲(chǔ)區(qū)中除了包含程序變量外,還包含了堆棧和寄存器組。在定義data存儲(chǔ)類型變量的數(shù)量時(shí),應(yīng)同時(shí)考慮寄存器組和堆棧的使用情況。C51使用默認(rèn)的寄存器來傳遞參數(shù)。另外,還需定義足夠大的堆棧空間,當(dāng)內(nèi)部堆棧溢出的時(shí)候,程序可能會(huì)出現(xiàn)看似莫名其妙的復(fù)位,其原因是51系列單片機(jī)中沒有硬件報(bào)錯(cuò)機(jī)制,堆棧溢出以這種方式表示出來。下面是幾個(gè)data存儲(chǔ)類型聲明的例子:

unsignedchardatasystem_status=0;

unsignedintdataunit_id[8];

chardatainp_str[16];

(3)bdata:使用bdata存儲(chǔ)類型定義數(shù)據(jù)時(shí),C51編譯器將其定位在片內(nèi)存儲(chǔ)器空間的位尋址區(qū)。編譯器不允許在bdata段中定義float和double類型的變量。定義之后,這個(gè)變量就可進(jìn)行位尋址。存儲(chǔ)狀態(tài)信息是十分有用的,因?yàn)樗梢詥为?dú)地使用變量的每一位,有關(guān)位變量的定義和引用的例子詳見8.6節(jié)。

(4)idata:idata存儲(chǔ)類型對應(yīng)間接尋址的片內(nèi)全部數(shù)據(jù)存儲(chǔ)空間(256B),idata區(qū)也可存放使用比較頻繁的變量和臨時(shí)性數(shù)據(jù)。使用寄存器作為指針進(jìn)行尋址,在寄存器中設(shè)置8位地址進(jìn)行間接尋址。與外部存儲(chǔ)器尋址相比,它生成的指令執(zhí)行周期和代碼長度都比較短。下面是幾個(gè)idata存儲(chǔ)類型聲明的例子:

unsignedcharidatasystem_status=0;

unsignedintidataunit_id[8];

charidatainp_str[16];

(5)pdata和xdata:當(dāng)使用xdata存儲(chǔ)類型定義常量和變量時(shí),C51編譯器會(huì)將其定位在片外數(shù)據(jù)存儲(chǔ)器空間,該空間的最大尋址范圍為64KB。片外數(shù)據(jù)存儲(chǔ)器主要用于存放不常使用的變量值、待處理的數(shù)據(jù)或準(zhǔn)備發(fā)往另一臺(tái)計(jì)算機(jī)的數(shù)據(jù)。在使用外部數(shù)據(jù)存儲(chǔ)器空間中的數(shù)據(jù)時(shí),必須用指令將它們?nèi)總魉偷絾纹瑱C(jī)片內(nèi)數(shù)據(jù)存儲(chǔ)空間,數(shù)據(jù)處理完后,再將結(jié)果返回到外部數(shù)據(jù)存儲(chǔ)器中。

pdata存儲(chǔ)類型屬于xdata類型,但它可用工作寄存器R0或R1間接分頁訪問,即由R0或R1提供8位的頁內(nèi)地址,其高8位地址(頁面地址)被妥善保存在P2口中,多用于I/O操作。因?yàn)閷data尋址只需要裝入8位地址,而對xdata尋址需裝入16位地址,所以對pdata尋址比對xdata尋址要快,應(yīng)盡量把外部數(shù)據(jù)存儲(chǔ)在pdata區(qū)中。下面是一個(gè)定義pdata和xdata存儲(chǔ)類型變量的例子:

include〈reg51.h〉

unisgnedcharpdatainp_reg1;

unsignedcharxdatainp_reg2;

voidmain(void)

{

inp_reg1=P1;

inp_reg2=P3;

}8.3.2存儲(chǔ)模式定義變量時(shí),如果缺省存儲(chǔ)器類型,則按編譯時(shí)使用的存儲(chǔ)器模式來規(guī)定默認(rèn)的存儲(chǔ)類型,確定變量的存儲(chǔ)空間。存儲(chǔ)模式?jīng)Q定無明確存儲(chǔ)類型說明的變量的存儲(chǔ)類型和參數(shù)傳遞區(qū)。下面說明三種存儲(chǔ)器模式對變量的影響。

C51中有三種存儲(chǔ)模式。

(1)?SMALL模式。在此模式下,默認(rèn)的存儲(chǔ)類型為data,參數(shù)及局部變量定位于直接尋址的片內(nèi)數(shù)據(jù)存儲(chǔ)區(qū)(最大128B),對變量訪問的速度快,但空間很有限,只適用于小程序。

(2)?COMPACT模式。在此模式下,默認(rèn)的存儲(chǔ)類型為pdata,參數(shù)及局部變量定位于分頁片外部數(shù)據(jù)存儲(chǔ)區(qū),通過@R0或@R1間接尋址。對變量訪問的速度要比SMALL模式慢一些。

(3)?LARGE模式。在此模式下,默認(rèn)的存儲(chǔ)類型為xdata,參數(shù)及局部變量定位于片外部數(shù)據(jù)存儲(chǔ)區(qū),使用數(shù)據(jù)指針寄存器DPTR間接尋址,存儲(chǔ)空間大,可存儲(chǔ)變量多,但訪問速度慢。8.4

51單片機(jī)特殊功能寄存器的C51定義

51系列單片機(jī)中,除了程序計(jì)數(shù)器PC和4組通用工作寄存器之外,其他所有的寄存器均為特殊功能寄存器(SFR)。對于經(jīng)典的51單片機(jī),SFR分散在片內(nèi)RAM區(qū)的高128字節(jié),地址范圍是0x80~0xFF;對于Philips80C51MX單片機(jī),SFR的地址范圍是0x180~0x1FF。51單片機(jī)的有些寄存器具有位尋址能力,它們的字節(jié)地址都能被8整除,即字節(jié)地址以0或8為尾數(shù)。

為了訪問51單片機(jī)中特殊功能寄存器,C51提供了sfr、sfr16和sbit關(guān)鍵字,用來定義8位、16位特殊功能寄存器和可獨(dú)立尋址的位。這幾個(gè)關(guān)鍵字與標(biāo)準(zhǔn)C語言不兼容,只適用于51系列單片機(jī)的C語言編程。8位特殊功能寄存器的一般方法如下:sfrsfr_name=int_constant;其中:“sfr_name”是一個(gè)真實(shí)存在的特殊功能寄存器名;“int_constant”是被定義的特殊功能寄存器的字節(jié)地址,只能用整型常數(shù)表示。如此定義后,就建立起寄存器名稱符號(hào)與地址的關(guān)聯(lián),在程序中就可使用被定義的名稱符號(hào)來訪問真實(shí)地址的特殊功能寄存器了。例如:sfrP0=0x80;/*定義P0口*/

sfrPSW=0xD0;/*定義標(biāo)志寄存器*/

sfrTMOD=0x89;/*定義定時(shí)器/計(jì)數(shù)器方式控制寄存器*/

sfrTH0=0x8C;/*定義定時(shí)器/計(jì)數(shù)器0高字節(jié)*/

sfrTL0=0x8A;/*定義定時(shí)器/計(jì)數(shù)器0低字節(jié)*/在新的51系列產(chǎn)品中,增加了一些可按16位訪問的特殊功能寄存器,其高字節(jié)地址直接位于其低字節(jié)之后時(shí),例如AT89C52單片機(jī)的定時(shí)器/計(jì)數(shù)器T2就是這種情況。對于這類特殊功能寄存器,可使用關(guān)鍵字“sfr16”來定義,其定義語句的語法格式與8位SFR相同,只是“=”后面必須用低字節(jié)地址,即以低字節(jié)地址作為“sfr16”的定義地址。

例如:

sfr16T2=0xCC;

/*定時(shí)器/計(jì)數(shù)器T2L地址為CCH,T2H地址為CDH*/這種定義適用于所有新的16位SFR,但不能用于定時(shí)器/計(jì)數(shù)器C/T0和C/T1。

對于特殊功能寄存器中可獨(dú)立尋址的位,可使用關(guān)鍵字“sbit”來定義。其定義的一般格式為:

sbitbit_name=bit_adress

“bit_name”是被定義的位單元的名稱符號(hào),“bit_adress”是位單元地址。在51單片機(jī)中位單元地址可用“可位尋址的特殊寄存器名稱·位序號(hào)”、“可位尋址的字節(jié)地址·位序號(hào)”和“直接位地址”三種方式來表示。在C51中也有三種位單元的定義格式。第一種格式:sbitbit_name=sfr_name^int_constant

其中,位地址用已經(jīng)定義過可位尋址的特殊功能寄存器的名稱符號(hào)和位序號(hào)來表示。例如:

sfrPSW=0xD0; /*定義標(biāo)志寄存器*/

sbitOV=PSW^2; /*定義OV表示PSW的第2位*/

sbitCY=PSW^7; /*定義CY表示PSW的第7位*/

第二種格式:sbitbit_name=int_constant^int_constant其中,位地址用可位尋址字節(jié)地址和位序號(hào)來表示。例如:

sbitOV=0xD0^2;/*定義OV表示PSW的第2位*/

sbitCY=0xD0^7;/*定義CY表示PSW的第7位*/

第三種格式:sbitbit_name=int_constant

其中,“int_constant”為絕對位地址位。例如:

sbitOV=0xD2; /*定義OV表示絕對地址為D2H的位*/

sbitCY=0xD7; /*定義OV表示絕對地址為0D7H的位*/由于在51系列單片機(jī)產(chǎn)品中特殊功能寄存器的數(shù)量與類型不盡相同,因此建議將所有特殊功能寄存器的“sfr”定義放入一個(gè)頭文件中。該文件應(yīng)包括51單片機(jī)機(jī)型中的特殊功能寄存器的定義。C51編譯器的“reg51.h”就是定義51單片機(jī)中的特殊功能寄存器的頭文件。在程序開頭,只要有“#inlcluedreg51.h”,就可用單片機(jī)中的特殊功能寄存器名稱、位符號(hào)名稱來訪問其數(shù)據(jù)。8.5

51單片機(jī)并行接口的C51定義

51系列單片機(jī)并行I/O口除了芯片上的4個(gè)并行I/O口(P0~P3)外,還可以在片外擴(kuò)展并行I/O口。51系列單片機(jī)I/O口與數(shù)據(jù)存儲(chǔ)器統(tǒng)一編址,即把一個(gè)I/O口當(dāng)作數(shù)據(jù)存儲(chǔ)器中的一個(gè)單元來看待。使用C51編程時(shí),51單片機(jī)片內(nèi)的I/O口與片外擴(kuò)展的I/O口可以統(tǒng)一在一個(gè)頭文件中定義,也可以在程序中(一般在開始的位置)定義。對于51單片機(jī)片內(nèi)的I/O口按特殊功能寄存器方法定義,其定義方法舉例如下:sfrP0=0x80;/*定義端口0,地址為80H*/sfrP1=0x90;/*定義端口1,地址為90H*/對于片外擴(kuò)展I/O口,則根據(jù)硬件譯碼地址,將其視做片外數(shù)據(jù)存儲(chǔ)器的一個(gè)單元,使用#include語句進(jìn)行定義。例如:#include<absacc.h>/*將PRTOUT定義為外部I/O口,地址為0xFFC0, 長度為8位*/#definePRTOUTXBYTE[0xFFC0]PRTOUT=0x80;/*由已定義端口PRTOUT輸出數(shù)據(jù)0x80*/例子中的absacc.h是C51中絕對地址訪問函數(shù)的頭文件,XBYTE是C51提供的用于絕對地址定位的宏。采用以上方法尋址是通過包含絕對地址訪問頭文件absacc.h實(shí)現(xiàn)的。用戶可以充分利用C51運(yùn)行庫提供的預(yù)定義宏來進(jìn)行任意地址的直接操作。例如,可以這樣定義一個(gè)D/A轉(zhuǎn)換接口的地址,每向該地址寫入一個(gè)數(shù)據(jù)即可啟動(dòng)一次D/A轉(zhuǎn)換:#include<absacc.h>#defineDAC0832XBYTE[0x7FFF]/*定義DAC0832端 口地址*/DAC0832=0x80; /*啟動(dòng)一次D/A轉(zhuǎn)換*/另一個(gè)經(jīng)常定義外部I/O口的方法是使用C51的擴(kuò)展關(guān)鍵字“_at_”,用“_at_”給I/O器件指定變量名非常簡單。例如,在XDATA區(qū)的地址0xFFC0處有一個(gè)8位的擴(kuò)展輸入口,可以這樣為它指定變量名:

unsignedcharxdatainPRT_at_0xFFC0;在頭文件或程序中對這些片內(nèi)外I/O口定義后,在程序中就可以利用變量名與其實(shí)際地址之間的聯(lián)系,用軟件模擬51單片機(jī)的硬件操作。8.6位變量的C51定義除了通常的C數(shù)據(jù)類型外,C51編譯器還支持“bit”數(shù)據(jù)類型,這對于記錄系統(tǒng)狀態(tài)是十分有用的,因?yàn)樗枰褂媚骋晃欢皇钦麄€(gè)數(shù)據(jù)字節(jié)。8.6.1位變量的C51定義在使用C51編程時(shí),定義了位變量后,就可以用定義的變量來表示51單片機(jī)的位尋址單元。在C51中定義位變量的一般語法形式如下:位類型標(biāo)識(shí)符(bit)位變量名;

bitmy_bit; /*把my_bit定義為位變量*/

bitdirection_bit; /*把direction_bit定義為位變量*/函數(shù)參數(shù)列表中可以包含類型為“bit”的參數(shù),也可使用bit類型的返回值。例如:

bitdone_flag=0;

/*把done_flag定義為位變量*/

bittestfunc(bitflag1,bitflag2)

{ /*flag1和flag2為bit類型的參數(shù)*/

return(flag); /*flag是bit類型的返回值*/

}8.6.2對位變量定義的限制

(1)位變量不能定義成一個(gè)指針,原因是不能通過指針訪問“bit”類型的數(shù)據(jù),如定義“bit*ptr;”是非法的。

(2)不存在位數(shù)組,如不能定義bitSHOW_BUF[6]。

(3)值得注意的是,使用中斷禁止(#pragmadisable)或包含明確的寄存器組切換(usingn)的函數(shù)不能返回位值,否則編譯器會(huì)給出一個(gè)錯(cuò)誤信息。在位定義中,允許定義存儲(chǔ)類型,位變量都被放入一個(gè)位段,此位段總位于51單片機(jī)片內(nèi)的RAM中,因此存儲(chǔ)器類型限制為data和idata。如果把位變量的存儲(chǔ)類型定義為其他存儲(chǔ)類型,將導(dǎo)致編譯出錯(cuò)??梢韵榷x變量的數(shù)據(jù)類型和存儲(chǔ)類型,然后使用“sbit”定義可尋址訪問的位對象。例如:intbdataibase; /*定義ibase為bdata整型變量*/charbdatabary[4];/*定義bary[4]為bdata字符型數(shù)組*/sbitmybit0=ibase^0;/*定義mybit0為ibase的第0位*/sbitmybit15=ibase^15;/*定義mybit15為ibase的第15位*/sbitAry07=bary[0]^7;/*定義Ary07為bary[0]的第7位*/sbitAry37=bary[3]^7;/*定義Ary37為bary[3]的第7位 */對ibase和bary也可以字節(jié)尋址:

Ary37=0; /*bary[3]的第7位清零*/

bary[3]=′a′;/*字節(jié)尋址,bary[3]賦值為′a′*/

mybit15=1; /*ibase的第15位置1*/用sbit定義時(shí),要求尋址對象所在字節(jié)基址對象的存儲(chǔ)類型為“bdata”,否則只有絕對的特殊位定義(sbit)是合法的。操作符后的最大值依賴于指定的基類型,對于char和

unsignedchar而言是0~7,對于int、unsignedint、short和unsignedshort而言是0~15,對于long和unsignedlong而言是0~31。比如,在BDATA段中聲明變量和使用位變量:

unsignedcharbdatastatus_byte;

unsignedintbdatastatus_word;

unsignedlongbdatastatus_dword;

sbitstat_flag=status_byte^4;

if(status_word^15){

…}

stat_flag=1;8.7

C51的指針前面講述的字符型(char)、整型(int)、浮點(diǎn)型(float)、位型(bit)等數(shù)據(jù),都屬于C51的基本數(shù)據(jù)類型。C語言還提供了一些擴(kuò)展的數(shù)據(jù)類型,它們是由基本數(shù)據(jù)類型按一定的規(guī)則組合而成的數(shù)據(jù)類型,稱之為構(gòu)造數(shù)據(jù)類型。構(gòu)造數(shù)據(jù)類型有數(shù)組、結(jié)構(gòu)、指針、共用體、枚舉等。

C51支持的構(gòu)造數(shù)據(jù)類型的數(shù)目與標(biāo)準(zhǔn)C語言一樣,對構(gòu)造類型定義、引用及其運(yùn)算的規(guī)則也同標(biāo)準(zhǔn)C語言基本一樣,只是定義構(gòu)造類型時(shí),可由C51支持的基本數(shù)據(jù)類型組合而成。在這里需要一提的是:標(biāo)準(zhǔn)C語言中,定義構(gòu)造數(shù)據(jù)類型時(shí),不太去考慮存儲(chǔ)空間問題,而使用C51編寫單片機(jī)應(yīng)用程序時(shí),就需要比較慎重地考慮存儲(chǔ)空間問題,因?yàn)榻?jīng)典的51單片機(jī)的最大數(shù)據(jù)存儲(chǔ)空間只有64KB。如果隨意定義太大規(guī)模的構(gòu)造類型數(shù)據(jù),就會(huì)浪費(fèi)大量的存儲(chǔ)空間,使構(gòu)造類型的數(shù)據(jù)元素不能被有效地利用。因此在進(jìn)行C51編程開發(fā)時(shí),要根據(jù)需要來選擇構(gòu)造類型數(shù)據(jù)的大小。下面對KEILC51的指針類型進(jìn)行詳細(xì)說明。C51編譯器支持使用“*”符號(hào)說明的指針,可以使用指針執(zhí)行標(biāo)準(zhǔn)C中所有可執(zhí)行的操作。針對8051及其派生器件的獨(dú)特結(jié)構(gòu),C51支持兩種不同類型的指針:通用指針和指定存儲(chǔ)器的指針。8.7.1通用指針與指定存儲(chǔ)器的指針

C51中指針區(qū)分為通用指針和指定存儲(chǔ)器的指針,兩種指針的定義和使用是有區(qū)別的。

1.指針定義

C51中定義指針的一般形式為數(shù)據(jù)類型[存儲(chǔ)器類型1]*[存儲(chǔ)器類型2]指針變量名;數(shù)據(jù)類型:表示指針變量所指向數(shù)據(jù)的類型。存儲(chǔ)器類型1:表示指針變量所指向數(shù)據(jù)的存儲(chǔ)空間。如果不定義該選項(xiàng),就定義為通用指針。如果定義了該選項(xiàng),就定義為指定存儲(chǔ)器的指針。存儲(chǔ)類型2:表示指針變量本身的存儲(chǔ)空間。如果不定義該選項(xiàng),指針變量的值(指針)被默認(rèn)存放在data區(qū)(片內(nèi)RAM區(qū))。如果定義了該選項(xiàng),指針變量的值被存放在指定的存儲(chǔ)區(qū)。*?和指針變量名的意義與標(biāo)準(zhǔn)C語言完全一樣。

2.通用指針與指定存儲(chǔ)器指針的區(qū)別

通用指針和指定存儲(chǔ)器的指針不僅在定義形式上有區(qū)別,而且在使用上也有區(qū)別。主要區(qū)別有以下三點(diǎn)。

(1)對指針的存儲(chǔ)不同。通用指針存儲(chǔ)占用三個(gè)字節(jié),第一個(gè)字節(jié)存放該指針存儲(chǔ)器類型的編碼(編譯時(shí)由編譯模式的默認(rèn)值確定),第二和第三字節(jié)分別存放該指針的高8位和低8位地址。存儲(chǔ)器類型的編碼值如表8.4所示。表8.4存儲(chǔ)器類型的編碼值指定存儲(chǔ)器的指針在定義中指定了指針?biāo)笖?shù)據(jù)的存儲(chǔ)區(qū),編譯時(shí)不用識(shí)別存儲(chǔ)器類型(不需存儲(chǔ)存儲(chǔ)器類型碼),只占用一個(gè)或二個(gè)字節(jié)存放指針,idata、data、pdata存儲(chǔ)器指針占一個(gè)字節(jié),code、xdata占二個(gè)字節(jié)。

(2)通用指針可以訪問存儲(chǔ)器空間任何位置的數(shù)據(jù),指定存儲(chǔ)器的指針只能訪問指定存儲(chǔ)區(qū)的數(shù)據(jù)。使用通用指針,可以不考慮數(shù)據(jù)在存儲(chǔ)器中的位置,因此許多庫程序使用這種類型的指針。

(3)通用指針產(chǎn)生的代碼比指定存儲(chǔ)器指針產(chǎn)生代碼的執(zhí)行速度要慢。因?yàn)榇鎯?chǔ)區(qū)在編譯前是未知的,編譯器不能優(yōu)化存儲(chǔ)區(qū)訪問,而必須產(chǎn)生可以訪問存儲(chǔ)區(qū)的通用代碼。

3.定義指針舉例

(1)

char*c_ptr;

int*i_ptr;

long*l_ptr;

定義了三個(gè)通用指針,c_ptr指向的是一個(gè)字符型變量,i_ptr指向的是一個(gè)整型變量,l_ptr指向的是一個(gè)長整變量,三個(gè)指針變量本身存放于片內(nèi)數(shù)據(jù)存儲(chǔ)區(qū)。指針?biāo)赶虻臄?shù)據(jù)位于哪里,與編譯時(shí)編譯模式的設(shè)置有關(guān):

如果模式為Large,則數(shù)據(jù)位于xdata區(qū);

如果模式為Compact,則數(shù)據(jù)位于pdata區(qū);

如果模式為Small,則數(shù)據(jù)位于data區(qū)。

(2)char*datac_ptr;

int*idatai_ptr;

long*xdatal_ptr;

定義了三個(gè)通用指針,指定c_ptr、i_ptr、l_ptr變量本身分別存于data、idata、xdata區(qū)。

(3)

Chardata*datac_ptr;

intxdata*idatai_ptr;

longcode*xdatal_ptr;

定義了三個(gè)指定存儲(chǔ)器的指針,且指定了c_ptr、i_ptr、l_ptr變量本身分別存于data、idata、xdata區(qū)。c_ptr指向的是data區(qū)中的字符型變量,i_ptr指向的是xdata區(qū)中的整型變量,l_ptr指向的是code區(qū)中的長整型變量。8.7.2指針轉(zhuǎn)換

C51編譯器可以在指定存儲(chǔ)器指針和通用指針之間轉(zhuǎn)換,指針轉(zhuǎn)換可以用類型轉(zhuǎn)換的程序代碼來強(qiáng)迫轉(zhuǎn)換,或在編譯器內(nèi)部強(qiáng)制轉(zhuǎn)換。

有些函數(shù)調(diào)用中,進(jìn)行參數(shù)傳遞時(shí)需要采用一般指針,像C51的庫函數(shù)、printf、sprintf、gets等函數(shù)要求使用一般指針作為參數(shù)。當(dāng)把指定存儲(chǔ)區(qū)的指針作為參數(shù)傳遞給要求使用通用指針的函數(shù)時(shí),C51編譯器就把指定存儲(chǔ)區(qū)指針轉(zhuǎn)換為一般指針。指定存儲(chǔ)區(qū)的指針作為參數(shù)時(shí),如果沒有函數(shù)原型,就經(jīng)常被轉(zhuǎn)換為一般指針。如果被調(diào)用函數(shù)的參數(shù)為某種較短長度指針,則會(huì)產(chǎn)生程序錯(cuò)誤。為避免此類錯(cuò)誤,應(yīng)該采用預(yù)處理命令將函數(shù)的說明文件包含到C語言源程序中。

通用指針到指定存儲(chǔ)器指針的轉(zhuǎn)換規(guī)則如表8.5所示。指定存儲(chǔ)器指針到通用指針的轉(zhuǎn)換規(guī)則如表8.6所示。8.8與使用51單片機(jī)內(nèi)部資源有關(guān)的頭文件

KeilC51提供了豐富的庫函數(shù),為使用戶能方便地使用,將庫函數(shù)分類,按類提供一個(gè)擴(kuò)展名為“h”的頭文件。在頭文件中定義一類函數(shù)的公用變量、函數(shù)原型,或是定義一種功能的宏。用戶在使用C51提供的某一類函數(shù)或某一種功能時(shí),只要用“#include”命令將對應(yīng)的頭文件包含到自己的程序文件中,即可直接使用。KeilC51提供的頭文件在“\\Keil\C51\INC”目錄下,其中大多數(shù)頭文件的功能、作用及其使用基本與標(biāo)準(zhǔn)C相同。下面主要介紹幾個(gè)與使用51單片機(jī)內(nèi)部資源有關(guān)的頭文件。

1.reg51.h/reg52.h

reg51.h是定義51子系列單片機(jī)全部特殊功能寄存器及其可獨(dú)立尋址位的頭文件。例如:

sfrP0=0x80;

sfrPSW=0xD0;

sfrTMOD=0x89;

sbitRS0=0xD3;

sbitRS1=0xD4;

sbitEA=0xAF;經(jīng)reg51.h中的定義,就建立了特殊功能寄存器/可獨(dú)立尋址位與其地址的對應(yīng)關(guān)系,且使用了單片機(jī)中真實(shí)的名稱符號(hào)。只要在程序文件中使用“include<reg51.h>”,在C程序中就可直接使用51單片機(jī)中的真實(shí)特殊功能寄存器或位的名稱符號(hào),對其進(jìn)行操作。

reg52.h是定義52子系列單片機(jī)全部特殊功能寄存器/可獨(dú)立尋址位的頭文件。

2.a(chǎn)bsacc.h

absacc.h是直接訪問51單片機(jī)各存儲(chǔ)空間數(shù)據(jù)及函數(shù)的宏定義頭文件。例如:

#defineDBYTE((unsignedcharvolatiledata*)0)

這個(gè)宏定義了DBYTE是指向片內(nèi)直接尋址數(shù)據(jù)存儲(chǔ)器空間(128B)無符號(hào)字符型數(shù)據(jù)的指針,與數(shù)據(jù)段初始偏移量為0,即為一個(gè)空指針。

在absacc.h中,按照同樣的宏結(jié)構(gòu)還定義了CBYTE、PBYTE、XBYTE、CWORD、DWORD、PWORD、XWORD,指向不同存儲(chǔ)空間及不同數(shù)據(jù)類型的指針。

CBYTE是指向程序存儲(chǔ)器空間中無符號(hào)字符型數(shù)據(jù)的空指針。PBYTE是指向片外數(shù)據(jù)存儲(chǔ)器分頁訪問空間(256B)中無符號(hào)字符型數(shù)據(jù)的空指針。

XBYTE是指向片外數(shù)據(jù)存儲(chǔ)器空間(64KB)中無符號(hào)字符型數(shù)據(jù)的空指針。

CWORD是指向程序存儲(chǔ)器空間(64KB)中無符號(hào)整型數(shù)據(jù)(2B)的空指針。DWORD是指向片內(nèi)直接尋址數(shù)據(jù)存儲(chǔ)器空間(128B)中無符號(hào)整型數(shù)據(jù)(2B)的空指針。

PWORD是指向片外數(shù)據(jù)存儲(chǔ)器分頁訪問空間(256B)中無符號(hào)整型數(shù)據(jù)(2B)的空指針。

XWORD是指向片外數(shù)據(jù)存儲(chǔ)器空間(64KB)中無符號(hào)整型數(shù)據(jù)(2?B)的空指針。

只要在程序文件中使用“include<absacc.h>”,在C程序中就可以用空指針來定義絕對地址變量,訪問絕對地址單元的數(shù)據(jù)。

例如,利用absacc.h中宏定義指針來定義一個(gè)擴(kuò)展8255端口,設(shè)控制口、A口、B口、C口地址分別為007Fh、007Ch、007Dh、007Eh。

#defineCOM8255XBYTE[0X007F]

#definePA8255XBYTE[0X007C]

#definePB8255XBYTE[0X007D]

#definePC8255XBYTE[0X007E]經(jīng)上述定義后,就可以用COM8255、PA8255、PB8255、PC8255分別表示端口地址,直接進(jìn)行端口操作。如:

COM8255=0X0F;

是將命令字0FH輸出到8255控制口。

還可以直接訪問存儲(chǔ)器地址單元。例如:

cval=DBYTE[0x0002]

;把程序存儲(chǔ)器0002H地址單元的無符號(hào)字符型數(shù)據(jù)賦給變量

dval=XWORD[0x0004]

;把外數(shù)據(jù)存儲(chǔ)器0004H地址單元的整形數(shù)據(jù)(2B)賦給變量

3.intrins.h

C51提供了模擬51單片機(jī)指令系統(tǒng)中空操作、位測試、移位、堆棧操作指令功能的函數(shù),在intrins.h中對這些函數(shù)原型進(jìn)行說明。

intrins.h的主要內(nèi)容如下:只要在程序文件中使用“include<intrins.h>”,在C程序中就可以調(diào)用其中的函數(shù),實(shí)現(xiàn)相應(yīng)匯編指令的功能。例如:

#include<intrins>h>

main()

{

unsignedinty;

y=0X000F;

y=_irol_(y,4);

}

程序執(zhí)行后,y的值左移4位,變?yōu)?0F0H。

8.951單片機(jī)內(nèi)部資源應(yīng)用的C語言編程

8.9.1中斷應(yīng)用的C語言編程

C51編譯器支持在C源程序中直接開發(fā)中斷程序。中斷服務(wù)程序是按規(guī)定語法格式定義的一個(gè)函數(shù)。定義中斷服務(wù)函數(shù)的一般形式如下:

返回值函數(shù)名([參數(shù)])interruptm[usingn]

{

}

其中:返回值、函數(shù)名([參數(shù)])部分與標(biāo)準(zhǔn)C語言中的意義相同。

interruptm用于選擇中斷號(hào)。m表示中斷源的中斷號(hào),取值為0~31的常整數(shù),不允許使用表達(dá)式。51單片機(jī)中斷源編號(hào)如表8.7所示。

usingn選項(xiàng)用于工作寄存器組的切換,n是中斷服務(wù)子程序中選用的工作寄存器組號(hào)(0~3)。在許多情況下,響應(yīng)中斷時(shí)需保護(hù)有關(guān)現(xiàn)場信息,以便中斷返回后,能使被中斷的程序從斷點(diǎn)處繼續(xù)正確地執(zhí)行下去。在51單片機(jī)中,能很方便地利用工作寄存器組的切換來實(shí)現(xiàn)現(xiàn)場信息保護(hù),即在進(jìn)入中斷服務(wù)程序前的程序中使用一組工作寄存器,進(jìn)入中斷服務(wù)程序后,由“usingn”切換到另一組寄存器,中斷返回后又恢復(fù)到原寄存器組。這樣互相切換的兩組寄存器中的內(nèi)容彼此都沒有被破壞。在函數(shù)體中進(jìn)行相應(yīng)中斷事務(wù)處理。

例1

圖8.3所示是利用優(yōu)先權(quán)解碼芯片,在單片機(jī)8051的外部中斷上擴(kuò)展多個(gè)中斷源的原理電路圖。圖中是以開關(guān)閉合來模擬中斷請求信號(hào)。當(dāng)有任一中斷源產(chǎn)生中斷請求時(shí),能給8051的送一個(gè)有效中斷信號(hào),由P1的低3位可得對應(yīng)中斷源的中斷號(hào)。圖8.3擴(kuò)展多個(gè)中斷源在中斷服務(wù)程序中僅設(shè)置標(biāo)志,并保存I/O口輸入狀態(tài)。C51程序如下:本例中說明了一個(gè)重要的中斷處理技術(shù)。在實(shí)際中斷系統(tǒng)中,如果中斷處理程序比較長,放在中斷服務(wù)程序中進(jìn)行處理,可能會(huì)延長甚至?xí)G掉比該中斷優(yōu)先級(jí)低的中斷請求。為了提高中斷響應(yīng)速度,只在中斷服務(wù)程序中為該中斷建立中斷標(biāo)志,而把中斷處理放在主程序中作為背景程序,根據(jù)中斷標(biāo)志決定是否被執(zhí)行。8.9.2定時(shí)器/計(jì)數(shù)器應(yīng)用的C語言編程

例2

設(shè)單片機(jī)的fosc=12MHz晶振,要求在P1.0腳上輸出周期為2ms的方波。周期為2ms的方波要求定時(shí)時(shí)間隔

1ms時(shí)對P1.0取反輸出。

(1)用定時(shí)器0的方式1編程,采用查詢方式,程序如下:(2)用定時(shí)器0的方式1編程,采用中斷方式。程序如下:

例3

采用12?MHz晶振,在P1.0腳上輸出周期為2.5?s,占空比為20%脈沖信號(hào)。

12?MHz晶振,使用定時(shí)器10?ms。周期2.5?s需250次中斷,占空比20%,高電平應(yīng)為50次中斷。中斷服務(wù)程序流程圖如圖8.4所示。圖8.4中斷服務(wù)程序流程圖8.9.3串行口使用的C語言編程

單片機(jī)的串行口可用于與通用微機(jī)的通信、單片機(jī)間的通信和主從結(jié)構(gòu)的分布式系統(tǒng)機(jī)間的通信。

例4

單片機(jī)fosc?=?11.0592?MHz,波特率為9600,各設(shè)置32字節(jié)的隊(duì)列緩沖區(qū)用于發(fā)送接收。設(shè)計(jì)單片機(jī)和終端或另一計(jì)算機(jī)通信的程序。

編寫程序前的設(shè)計(jì)工作:

(1)用定時(shí)器1工作方式2,作比特率發(fā)生器。根據(jù)以下公式計(jì)算初值,設(shè)初值為x。溢出率=波特率×32(SMOD=0)

(2)設(shè)置接收和發(fā)送隊(duì)列緩沖區(qū)32字節(jié),定義接收隊(duì)列入隊(duì)和出隊(duì)操作指示變量rin和rout、發(fā)送隊(duì)列入隊(duì)和出隊(duì)操作指示變量tin和tout,設(shè)置接收隊(duì)接滿(r_fuu)、發(fā)送隊(duì)列空(t_empty)、發(fā)送完成(t_done)標(biāo)志變量。利用這些變量來管理隊(duì)列操作。

(3)功能模塊規(guī)劃。loadmsg函數(shù)向發(fā)送隊(duì)列加載數(shù)據(jù)串;processmsg函數(shù)對接收隊(duì)列中的數(shù)據(jù)進(jìn)行處理;從串行口SBUF讀取數(shù)據(jù)或向SBUF傳送數(shù)據(jù)的操作在中斷處理程序中完成。在主函數(shù)中初始化定時(shí)器,初始化串行口、調(diào)用隊(duì)列裝載和處理函數(shù)。

具體程序如下:

8.1051單片機(jī)片外擴(kuò)展的C語言編程

8.10.18255與單片機(jī)接口C語言程序

例5

通過擴(kuò)展8255接口控制打印機(jī)。

圖8.5是51單片機(jī)擴(kuò)展8255與打印機(jī)接口的電路。打印機(jī)與單片機(jī)采用查詢方式交換數(shù)據(jù)。BUSY為打印機(jī)的狀態(tài)信號(hào),打印機(jī)忙時(shí)BUSY?=?1,空閑時(shí)BUSY?=?0。微型打印機(jī)的數(shù)據(jù)輸入采用選通控制,當(dāng)產(chǎn)生負(fù)跳變時(shí)數(shù)據(jù)進(jìn)入打印機(jī)。圖8.551單片機(jī)擴(kuò)展8255A與打印機(jī)接口按照接口電路,只要單片機(jī)從P0.7傳送的第7位地址為0即可選中8255。這就確定了A口地址為0xxxxx00。取7CH作A口地址,則B、C、控制口地址分別為7DH、7EH、7FH。A口作為向打印機(jī)傳送數(shù)據(jù)的輸出口,從PC7輸入打印機(jī)的狀態(tài)信號(hào),PC0產(chǎn)生選通控制信號(hào),可設(shè)置PC7~PC4為輸入,PC3~PC0為輸出。方式字設(shè)置為10001xx0,取8EH作方式控制字。向打印機(jī)輸出字符串“WELCOME”的程序如下:8.10.251單片機(jī)數(shù)據(jù)采集的C語言編程

例6ADC0809與51單片機(jī)接口的數(shù)據(jù)采集程序。

按圖8.6所示接口電路,編寫從ADC0809的8通道輪流采集一次數(shù),采集的結(jié)果放在數(shù)組ad中的程序。圖8.6ADC0809與51單片機(jī)的接口電路按照圖中片選線的連接,ADC0809的模擬通道0地址應(yīng)為:0××××××××××××000。取8個(gè)通道地址:7FF8H~7FFFH。

程序如下:

例7AD574與51單片機(jī)接口的數(shù)據(jù)采集程序。

按圖8.7所示的接口電路,進(jìn)行12位分辨的模擬信號(hào)采集。啟動(dòng)AD574進(jìn)行一次轉(zhuǎn)換,編寫一個(gè)獨(dú)立函數(shù),調(diào)用此函數(shù)可得轉(zhuǎn)換結(jié)果。

AD574轉(zhuǎn)換程序如下:圖8.7AD574與51單片機(jī)的接口電路

例851單片機(jī)與TLC0831接口的數(shù)據(jù)轉(zhuǎn)換程序。

51單片機(jī)與TLC0831接口電路如圖8.8所示。

圖8.8TLC0831與51單片機(jī)的接口TLC0832源程序如下:

#include<reg52.h>

#include<stdio.h>

#include<absacc.h>

#defineucharunsignedchar

#defineuintunsignedint

sbitadcdo=P1^2; /*定義數(shù)據(jù)線位變量*/

sbitadccs=P1^0; /*定義片選信號(hào)線位變量*/

sbitadcclk=P1^1; /*定義時(shí)鐘線位變量*/8.10.351單片機(jī)輸出控制的C語言編程

例951單片機(jī)與DAC0832單緩沖區(qū)接口的數(shù)據(jù)轉(zhuǎn)換。

接口電路如圖8.9所示。在單片機(jī)執(zhí)行輸出指令時(shí),只要從地址總線上傳送地址的最低位為0,使和有效,即可實(shí)現(xiàn)數(shù)據(jù)鎖存與啟動(dòng)。圖8.9DAC0832與51單片機(jī)的單緩沖接口電路控制DAC0832轉(zhuǎn)換,輸出一個(gè)鋸齒波電壓信號(hào)的C51程序如下:例1051單片機(jī)與DAC0832雙緩沖接口的數(shù)據(jù)轉(zhuǎn)換程序。

接口電路如圖8.10所示。在單片機(jī)執(zhí)行輸出指令時(shí),只要從地址總線上傳送相應(yīng)地址,即可選通DAC0832相應(yīng)鎖存器,實(shí)現(xiàn)啟動(dòng)轉(zhuǎn)換控制。第一片的輸入寄存器(一級(jí)緩沖器)地址為10001×××××××××××,取8FFFH。第一片的輸入鎖存器(一級(jí)緩沖器)地址為10100×××××××

××××,取A7FFH。兩片的DAC鎖存器(二級(jí)緩沖器)具有相同地址00101×××××××××××,取2FFFH。圖8.10DAC0832雙緩沖接口電路將data1和data2數(shù)據(jù)同步轉(zhuǎn)換為模擬量的C51程序如下:

例1151單片機(jī)與AD7521接口的數(shù)據(jù)轉(zhuǎn)換程序。

接口電路如圖8.11所示。AD7521是12位轉(zhuǎn)換器,從B1~B12接收12位數(shù)字量即可啟動(dòng)轉(zhuǎn)換。它與51單片機(jī)接口,必須在外部設(shè)計(jì)兩級(jí)緩沖器,以實(shí)現(xiàn)分步轉(zhuǎn)送數(shù)據(jù),同步啟動(dòng)。圖中用兩片74LS377鎖存器作為低8位數(shù)據(jù)的兩級(jí)緩沖器,74LS379作高4位數(shù)據(jù)緩沖器。從圖可知,在單片機(jī)執(zhí)行輸出指令時(shí),從地址總線傳送相應(yīng)地址,可分別選通緩沖器。第一級(jí)8位緩沖器的選通地址是0×××××××××××××××,取7FFFH。第二級(jí)8位緩沖器和4位緩沖器為同一選通地址×0××××××××××××××,取BFFFH。單片機(jī)輸出低8位數(shù)據(jù),先鎖存到第一級(jí)緩沖器中,接著輸出高4位數(shù)據(jù),在鎖存高4位數(shù)據(jù)的同時(shí)低8位數(shù)據(jù)也鎖存到第二級(jí)緩沖器,12位數(shù)據(jù)同時(shí)達(dá)到AD7521,啟動(dòng)轉(zhuǎn)換。

使AD7521輸出梯形波的C51程序如下:圖8.1151單片機(jī)與AD5721的接口

例1251單片機(jī)與串行D/A轉(zhuǎn)換器MAX517接口的數(shù)據(jù)轉(zhuǎn)換程序。

MAX517接口電路如圖8.12所示。

轉(zhuǎn)換程序就是在單片機(jī)的P1.0和P1.1口線上模擬產(chǎn)生I2C總線標(biāo)準(zhǔn)的工作時(shí)序,向MAX517發(fā)送數(shù)據(jù),控制轉(zhuǎn)換。51單片機(jī)為主設(shè)備,首先單片機(jī)向MAX517發(fā)送一個(gè)地址字節(jié)58H,等待應(yīng)答后再發(fā)一個(gè)控制字節(jié)00H,再次等待應(yīng)答之后,再發(fā)要轉(zhuǎn)換的8位數(shù)據(jù)。圖8.1251單片機(jī)與MAX517的接口控制MAX517轉(zhuǎn)換的C51程序如下:

8.11頻率、周期測量的C語言編程

8.11.1測量頻率

測量頻率法是指在單位時(shí)間內(nèi)對被測信號(hào)進(jìn)行計(jì)數(shù)。測量頻率法最簡單的接口電路是將頻率脈沖直接連接到51單片機(jī)的T1端,用單片機(jī)的C/T0作定時(shí)器,用C/T1作計(jì)數(shù)器。在定時(shí)時(shí)間里,對頻率脈沖進(jìn)行計(jì)數(shù)。T/C1的計(jì)數(shù)值便是單位定時(shí)時(shí)間里的脈沖個(gè)數(shù)。在計(jì)數(shù)時(shí)會(huì)出現(xiàn)如圖8.13所示的丟失脈沖的情況。第一個(gè)丟失的脈沖,是由于開始檢測時(shí)脈沖寬度小于機(jī)器周期T;第二個(gè)丟失的脈沖是由于脈沖的負(fù)跳變在定時(shí)之外。定時(shí)時(shí)間內(nèi)出現(xiàn)脈沖丟失,將引起測量精度降低。脈沖頻率越低,這種錯(cuò)誤越大。顯然對于較低頻率的脈沖測量,最不適合采用測量頻率法。圖8.13測量頻率中的脈沖丟失

例13

帶同步控制的頻率測量。

為解決圖8.13中的第一個(gè)脈沖丟失,可用門電路實(shí)現(xiàn)計(jì)數(shù)開始與脈沖上升沿的同步控制。51單片機(jī)的T/C0作定時(shí)器,T/C1作計(jì)數(shù)器,對fx的頻率測量接口電路如圖8.14所示。圖8.14帶同步控制的頻率測量接口8.11.2測量周期

測量周期的基本原理是在被測信號(hào)周期T內(nèi),對某一已知周期的脈沖信號(hào)進(jìn)行計(jì)數(shù),已知周期與計(jì)數(shù)值的乘積便是被測信號(hào)周期。這種測量要求在被測周期開始啟動(dòng)計(jì)數(shù),周期結(jié)束時(shí)停止計(jì)數(shù)。可用圖8.15所示接口電路來實(shí)現(xiàn)測量。

74LS74是一個(gè)雙D觸發(fā)器芯片,圖中連接是利用其中的一個(gè)觸發(fā)器將被測信號(hào)的周期轉(zhuǎn)換成圖8.16所示的分頻信號(hào)。Q端輸出的分頻信號(hào)接單片機(jī)的外部中斷0上。用單片機(jī)T/C0的門控方式,在被測信號(hào)的一個(gè)周期內(nèi),對內(nèi)部機(jī)器周期信號(hào)進(jìn)行計(jì)數(shù)。測量時(shí),從P1.0輸出0,清除D觸發(fā)器,Q端輸出為0,定時(shí)器不能啟動(dòng)。在被測信號(hào)上升沿到來時(shí),Q端輸出高電平,此時(shí)啟動(dòng)定時(shí)器對內(nèi)部機(jī)器周期計(jì)數(shù)。在被測信號(hào)的第一個(gè)周期內(nèi)Q端保持高電平,周期結(jié)束時(shí)變?yōu)榈碗娖?,停止定時(shí)器計(jì)數(shù),同時(shí)產(chǎn)生中斷請求。在中斷程序中,讀取計(jì)數(shù)值,即可測量出被測信號(hào)的周期。圖8.15周期測量接口圖8.16頻率周期波形

8.1251單片機(jī)間通信的C語言編程

8.12.1點(diǎn)對點(diǎn)的串行異步通信

1.通信雙方的硬件連接

如果采用單片機(jī)自身的TTL電平直接傳輸信息,其傳輸距離一般不超過1.5m。51單片機(jī)一般采用RS-232C標(biāo)準(zhǔn)進(jìn)行點(diǎn)對點(diǎn)的通信連接。圖8.17是兩個(gè)51單片機(jī)間的連接方法,信號(hào)采用RS-232C電平傳輸,電平轉(zhuǎn)換芯片采用MAX232。

2.通信雙方的約定

按照圖8.17所示的接口電路。假定A機(jī)SYSTEM1是發(fā)送者,B機(jī)SYSTEM2是接收者。當(dāng)A機(jī)開始發(fā)送時(shí),先送一個(gè)“AA”信號(hào),B機(jī)收到后回答一個(gè)“BB”,表示同意接收。當(dāng)A機(jī)收到“BB”后,開始發(fā)送數(shù)據(jù),每發(fā)送一次求“校驗(yàn)和”,假定數(shù)據(jù)塊長度為16個(gè)字節(jié),數(shù)據(jù)緩沖區(qū)為buf,數(shù)據(jù)塊發(fā)送完后馬上發(fā)送“校驗(yàn)和”。

B機(jī)接收數(shù)據(jù)并將其轉(zhuǎn)存到數(shù)據(jù)緩沖區(qū)buf,每接收到一個(gè)數(shù)據(jù)便計(jì)算一次“校驗(yàn)和”,當(dāng)接收完一個(gè)數(shù)據(jù)塊后,再接收A機(jī)發(fā)來的校驗(yàn)和,并將它與B機(jī)求出的校驗(yàn)和進(jìn)行比較。若兩者相等,說明接收正確,B機(jī)回答00H;若

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(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

提交評論