版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第3章 C51語言編程基礎(chǔ)與 Keil µVision3開發(fā)平臺,1,單片機(jī)應(yīng)用系統(tǒng)日趨復(fù)雜,對程序的可讀性、升級與維護(hù)以及模塊化要求越來越高,對軟件編程要求也越來越高,要求編程人員在短時(shí)間內(nèi)編寫出執(zhí)行效率高、運(yùn)行可靠的程序代碼。同時(shí),也要方便多個(gè)編程人員來進(jìn)行協(xié)同開發(fā)。C51語言是近年來在8051單片機(jī)開發(fā)中,普遍使用的程序設(shè)計(jì)語言,能直接對8051單片機(jī)硬件進(jìn)行操作
2、,既有高級語言特點(diǎn),又有匯編語言特點(diǎn),因此在8051單片機(jī)程序設(shè)計(jì)中,得到廣泛使用。本章介紹8051單片機(jī)的C51語言,以及如何使用C51語言集成化開發(fā)平臺Keil µVision3,進(jìn)行C51程序設(shè)計(jì)與開發(fā)。,2,3.1 C51編程語言簡介用于8051單片機(jī)編程的C語言,在標(biāo)準(zhǔn)C基礎(chǔ)上針對8051硬件特點(diǎn)進(jìn)行擴(kuò)展,并向8051上移植,經(jīng)多年努力,C51已成為公認(rèn)的高效、簡潔的8051單片機(jī)的實(shí)用高級編程語言。與8051
3、匯編語言相比,C51語言在功能上、結(jié)構(gòu)性、可讀性、可維護(hù)性上有明顯優(yōu)勢,易學(xué)易用。3.1.1 C51語言與8051匯編語言比較與8051匯編語言相比, C51有如下優(yōu)點(diǎn)。(1)可讀性好。C51語言程序比匯編語言程序的可讀性好,編程效率高,程序便于修改、維護(hù)以及升級。,(2)模塊化開發(fā)與資源共享。用C51開發(fā)的程序模塊可不經(jīng)修改,直接被其他工程所用,使得開發(fā)者能夠很好地利用已有的大量標(biāo)準(zhǔn)C程序資源與豐富的庫函數(shù),減少重復(fù)勞動,同時(shí)
4、也有利于多個(gè)工程師進(jìn)行協(xié)同開發(fā)。(3)可移植性好。為某種型號單片機(jī)開發(fā)的C語言程序,只需把與硬件相關(guān)的頭文件和編譯鏈接的參數(shù)進(jìn)行適當(dāng)修改,就可方便地移植到其他型號的單片機(jī)上。例如,為8051單片機(jī)編寫的程序通過改寫頭文件以及少量的程序行,就可方便地移植到PIC單片機(jī)上。(4)生成的代碼效率高。當(dāng)前較好的C51語言編譯系統(tǒng)編譯出來的代碼效率只比直接使用匯編語言低20%左右,如果使用優(yōu)化編譯選項(xiàng),最高可達(dá)到90%左右。,4,3.1.2
5、 C51語言與標(biāo)準(zhǔn)C語言的比較C51語言與標(biāo)準(zhǔn)C語言間有許多相同地方,但也有自身特點(diǎn)。不同的嵌入式C語言編譯系統(tǒng)之所以與標(biāo)準(zhǔn)C語言有不同的地方,主要是由于它們所針對的硬件系統(tǒng)不同。對于8051單片機(jī),目前廣泛使用的是C51語言。C51語言基本語法與標(biāo)準(zhǔn)C相同,是在標(biāo)準(zhǔn)C的基礎(chǔ)上進(jìn)行適合8051內(nèi)核單片機(jī)硬件的擴(kuò)展。深入理解C51語言對標(biāo)準(zhǔn)C語言的擴(kuò)展部分以及它們的不同之處,是掌握C51語言的關(guān)鍵之一。,5,C51語言與標(biāo)準(zhǔn)C語言一些
6、差別如下。 (1)庫函數(shù)不同。標(biāo)準(zhǔn)C中不適合于嵌入式控制器系統(tǒng)的庫函數(shù),被排除在C51語言之外,如字符屏幕和圖形函數(shù)。有些庫函數(shù)必須針對8051的硬件特點(diǎn)來做出相應(yīng)的開發(fā)。 例如,在標(biāo)準(zhǔn)C中,庫函數(shù)printf和scanf,常用于屏幕打印和接收字符,而在C51語言中,主要用于串行口數(shù)據(jù)的收發(fā)。 (2)數(shù)據(jù)類型有一定區(qū)別。在C51中增加幾種8051單片機(jī)的數(shù)據(jù)類型,在標(biāo)準(zhǔn)C的基礎(chǔ)上又?jǐn)U展了4種類型。例如,8051單片機(jī)包含位
7、操作空間和豐富的位操作指令,因此,C51語言與標(biāo)準(zhǔn)C語言相比增加了位類型。,6,(3)C51語言變量存儲模式與標(biāo)準(zhǔn)C語言中變量存儲模式數(shù)據(jù)不一樣。標(biāo)準(zhǔn)C最初是為通用計(jì)算機(jī)設(shè)計(jì)的,在通用計(jì)算機(jī)中只有一個(gè)程序和數(shù)據(jù)統(tǒng)一尋址的內(nèi)存空間,而C51語言中變量的存儲模式與8051單片機(jī)的各種存儲器區(qū)緊密相關(guān)。 (4)數(shù)據(jù)存儲類型不同。8051存儲區(qū)可分為內(nèi)部數(shù)據(jù)存儲區(qū)、外部數(shù)據(jù)存儲區(qū)以及程序存儲區(qū)。 內(nèi)部數(shù)據(jù)存儲區(qū)可分為3個(gè)不同的C51存
8、儲類型:data、idata和bdata。 外部數(shù)據(jù)存儲區(qū)分為2個(gè)不同的C51存儲類型:xdata和pdata。 程序存儲區(qū)只能讀不能寫,可能在8051內(nèi)部或者在外部,C51語言提供的code存儲類型用來訪問程序存儲區(qū)。,7,(5)標(biāo)準(zhǔn)C語言沒有處理單片機(jī)中斷的定義,而C51語言中有專門的中斷函數(shù)。(6)頭文件不同。C51語言頭文件必須把8051單片機(jī)內(nèi)部的外設(shè)硬件資源(如定時(shí)器、中斷、I/O等)相應(yīng)的特殊功能寄存器寫入
9、到頭文件內(nèi),而標(biāo)準(zhǔn)C不用。 (7)程序結(jié)構(gòu)的差異。由于8051單片機(jī)的硬件資源有限,它的編譯系統(tǒng)不允許太多的程序嵌套。其次,標(biāo)準(zhǔn)C語言所具備的遞歸特性不被C51語言支持。,8,但從數(shù)據(jù)運(yùn)算操作、程序控制語句以及函數(shù)的使用上來說,C51與標(biāo)準(zhǔn)C幾乎沒有什么明顯差別。如果程序設(shè)計(jì)者具備了有關(guān)標(biāo)準(zhǔn)C語言的編程基礎(chǔ),只要注意C51與標(biāo)準(zhǔn)C不同之處,并熟悉8051單片機(jī)的硬件結(jié)構(gòu),就能較快掌握C51編程。3.2 C51語言程序設(shè)計(jì)基礎(chǔ)
10、本節(jié)在標(biāo)準(zhǔn)C基礎(chǔ)上,了解掌握C51的數(shù)據(jù)類型和存儲類型、C51的基本運(yùn)算與流程控制語句、C51語言構(gòu)造數(shù)據(jù)類型、C51函數(shù)以及C51程序設(shè)計(jì)的其他一些問題,為C51的程序開發(fā)打下基礎(chǔ)。,9,3.2.1 C51語言中的數(shù)據(jù)類型與存儲類型1.?dāng)?shù)據(jù)類型 數(shù)據(jù)是單片機(jī)操作的對象,具有一定格式的數(shù)字或數(shù)值,數(shù)據(jù)的不同格式就稱為數(shù)據(jù)類型。 Keil C51支持的基本數(shù)據(jù)類型見表3-1。 針對8051的硬件特點(diǎn),C51在標(biāo)準(zhǔn)C基
11、礎(chǔ)上,擴(kuò)展了4種數(shù)據(jù)類型(見表3-1中最后4行)。 注意,擴(kuò)展的4種數(shù)據(jù)類型,不能使用指針來對它們存取。,10,2.C51的擴(kuò)展數(shù)據(jù)類型 下面對擴(kuò)展的4種數(shù)據(jù)類型說明。 (1)位變量bit的值可以是1(true),也可是0(false)。 (2)特殊功能寄存器sfr。8051單片機(jī)的特殊功能寄存器分布在片內(nèi)數(shù)據(jù)存儲區(qū)的地址單元80H~FFH之間,“sfr”數(shù)據(jù)類型占用一個(gè)內(nèi)存單元。利用它可訪問8051單片機(jī)內(nèi)部的所有
12、特殊功能寄存器。 例如:sfr P1=0x90這一語句定義了P1端口在片內(nèi)的寄存器,在程序后續(xù)的語句中可以用“P1=0xff”,使P1的所有引腳輸出為高電平的語句來操作特殊功能寄存器。,12,(3)特殊功能寄存器sfr16。 “sfr16”數(shù)據(jù)類型占用兩個(gè)內(nèi)存單元,用于操作占兩個(gè)字節(jié)的特殊功能寄存器。例如:“sfr16 DPTR=0x82”語句定義了片內(nèi)16位數(shù)據(jù)指針寄存器DPTR,其低8位字節(jié)地址為82H,高8位字節(jié)地址為83
13、H。在程序的后續(xù)語句中就可對DPTR進(jìn)行操作。(4)特殊功能位sbit。 sbit是指AT89S51片內(nèi)特殊功能寄存器的可尋址位。例如: sfrPSW=0xd0;//定義PSW寄存器地址為0xd0sbitOV=PSW^2;//定義OV位為PSW.2 符號“^”前是特殊功能寄存器名字,“^”后的數(shù)字定義特殊功能寄存器可尋址位在寄存器中的位置,取值必須是0~7。,注意,不要把bit與sbit相混淆。bi
14、t定義普通的位變量,只能是二進(jìn)制的0或1。sbit是定義特殊功能寄存器的可尋址位,值是可以進(jìn)行位尋址的特殊功能寄存器的某位的絕對地址,例如,PSW寄存器OV位的絕對地址0xd2。上面的例子還涉及到C51注釋的寫法問題,C51的注釋寫法有兩種:(1)//……,兩個(gè)斜杠后面跟著的為注釋語句,本寫法只能注釋一行,當(dāng)換行時(shí),必須在新行上重新寫兩個(gè)斜杠。(2)/*……*/,一個(gè)斜杠與星號結(jié)合使用,本寫法可注釋任一行,即斜杠星號與星號斜杠之
15、間的所有文字都作為注釋,即注釋有多行時(shí),只需在注釋的開始處,加斜杠星號,在注釋的結(jié)尾處,加上星號斜杠即可。 加注釋的目的是為了便于讀懂程序,所有注釋都不參與程序編譯,編譯器在編譯過程中會自動刪去注釋。,14,3.?dāng)?shù)據(jù)存儲類型 在討論C51數(shù)據(jù)類型時(shí),須同時(shí)提及它的存儲類型,以及它與8051單片機(jī)存儲器結(jié)構(gòu)的關(guān)系,因?yàn)镃51定義的任何數(shù)據(jù)類型必須以一定的方式,定位在8051單片機(jī)的某一存儲區(qū)中,否則沒有任何實(shí)際意義。,805
16、1有片內(nèi)、片外數(shù)據(jù)存儲區(qū),還有程序存儲區(qū)。 片內(nèi)的數(shù)據(jù)存儲區(qū)是可讀寫的,8051的衍生系列最多可有256字節(jié)的內(nèi)部數(shù)據(jù)存儲區(qū)(例如AT89S52單片機(jī)),其中低128字節(jié)可直接尋址,高128字節(jié)(80H~FFH)只能間接尋址,從地址20H開始的16字節(jié)可位尋址。內(nèi)部數(shù)據(jù)存儲區(qū)可分為3個(gè)不同的數(shù)據(jù)存儲類型:data、idata和bdata。 訪問片外數(shù)據(jù)存儲區(qū)比訪問片內(nèi)數(shù)據(jù)存儲區(qū)慢,因?yàn)樵L問片外數(shù)據(jù)存儲區(qū)要通過對數(shù)據(jù)指針加載地
17、址來間接尋址訪問。 C51提供兩種不同的數(shù)據(jù)存儲類型xdata和pdata來訪問片外數(shù)據(jù)存儲區(qū)。,16,程序存儲區(qū)只能讀不能寫,可能在8051單片機(jī)內(nèi)部或者外部,或外部和內(nèi)部都有,由8051單片機(jī)硬件決定,C51提供了code存儲類型來訪問程序存儲區(qū)。C51存儲類型與8051實(shí)際的存儲空間的對應(yīng)關(guān)系見表3-2。下面對表3-2各種存儲區(qū)作以說明。(1)DATA區(qū)。尋址是最快的,應(yīng)把常使用的變量放在該區(qū),但該區(qū)存儲空間有限,DA
18、TA區(qū)除了包含程序變量外,還包含了堆棧和寄存器組。DATA區(qū)聲明中的存儲類型標(biāo)識符為data,通常指片內(nèi)RAM128字節(jié)的內(nèi)部數(shù)據(jù)存儲的變量,可直接尋址。,17,18,聲明舉例:unsigned char data system_status=0;unsigned int data unit_id[8];char data inp_string[20]; 標(biāo)準(zhǔn)變量和用戶自聲明變量都可存儲在DATA區(qū)中,只要不超過DAT
19、A區(qū)的范圍即可,由于C51用默認(rèn)的寄存器組來傳遞參數(shù),這樣DATA區(qū)至少失去8字節(jié)空間。 另外,當(dāng)內(nèi)部堆棧溢出的時(shí)候,程序會莫名其妙地復(fù)位。這是因?yàn)?051沒有報(bào)錯(cuò)機(jī)制,堆棧溢出只能以這種方式表示,因此要留有較大的堆棧空間來防止堆棧溢出。 (2)BDATA區(qū)。DATA中的位尋址區(qū),在該區(qū)中聲明變量就可進(jìn)行位尋址。BDATA區(qū)聲明中的存儲類型標(biāo)識符為bdata,指的是片內(nèi)RAM可位尋址的16,19,字節(jié)存儲區(qū)(字節(jié)地址為20H~
20、2FH)中的128個(gè)位。下面是在BDATA區(qū)中聲明的位變量和使用位變量的例子:unsigned char bdata status_byte;unsigned int bdata status_word;sbit stat_flag=status_byte^4;if(status_word^15){ …… }stat_flag=1; C51編譯器不允許在BDATA區(qū)中聲明float和double型變量。 (3)IDA
21、TA區(qū)。該區(qū)使用寄存器作為指針來對片內(nèi)RAM進(jìn)行間接尋址,常用來存放使用比較頻繁的變量。與外部存儲器尋址相比,它的指令執(zhí)行周期和代碼長度相對較短。 IDATA區(qū)聲明中的存儲類型標(biāo)識符為idata,指的是片內(nèi)RAM的256字節(jié)的存儲區(qū),只能間接尋址,速度比直接尋址慢。,20,聲明舉例如下:unsigned char idata system_status=0;unsigned int idata unit_id[8];char
22、 idata inp_string[16];float idata out_value;(4)PDATA區(qū)和XDATA區(qū) 位于片外存儲區(qū),PDATA區(qū)和XDATA區(qū)聲明中的存儲類型標(biāo)識符分別為pdata和xdata。 PDATA區(qū)只有256字節(jié),僅指定256字節(jié)的外部數(shù)據(jù)存儲區(qū)。 但XDATA區(qū)最多可達(dá)64KB,對應(yīng)的xdata存儲類型標(biāo)識符可指定外部數(shù)據(jù)區(qū)64KB內(nèi)的任何地址。,21,對PDATA區(qū)的尋址要比對XDATA區(qū)
23、尋址快,因?yàn)閷DATA區(qū)尋址,只需裝入8位地址,而對XDATA區(qū)尋址要裝入16位地址,所以盡量把外部數(shù)據(jù)存儲在PDATA區(qū)中。 對PDATA區(qū)和XDATA區(qū)的聲明舉例如下:unsigned char xdata system_status=0;unsigned int pdata unit_id[8];char xdata inp_string[16];float pdata out_value; 由于外部數(shù)據(jù)存儲
24、器與外部I/O口是統(tǒng)一編址的,外部數(shù)據(jù)存儲器地址段中除了包含數(shù)據(jù)存儲器地址外,還包含外部I/O口的地址。對外部數(shù)據(jù)存儲器及外部I/O口的尋址將在本章的絕對地址尋址中介紹。,22,(5)程序存儲區(qū)CODE。程序存儲區(qū)CODE聲明的標(biāo)識符為code,儲存的數(shù)據(jù)是不可改變的。在C51編譯器中可以用存儲區(qū)類型標(biāo)識符code來訪問程序存儲區(qū)。聲明舉例如下:unsigned char code a[ ]={0x00,0x01,0x02,0x03
25、,0x04,0x05,0x06, 0x07,0x08}; 上面介紹了C51的數(shù)據(jù)存儲類型,其大小和值域見表3-3。 單片機(jī)訪問片內(nèi)RAM比訪問片外RAM相對快一些,所以應(yīng)盡量把頻繁使用的變量置于片內(nèi)RAM。即采用data、bdata或idata存儲類型,而將容量較大或使用不太頻繁的那些變量置于片外RAM,即采用pdata或xdata存儲類型。常量只能采用code存儲類型。,
26、23,24,變量存儲類型定義舉例:(1)char data a1; /*字符變量a1被定義為data型,分配在片內(nèi)RAM低128字節(jié)中*/(2)float idata x,y; /*浮點(diǎn)變量x和y被定義為idata型,定位在 片內(nèi)RAM中,只能用間接尋址方式尋址*/ (3)bi
27、t bdata p; /*位變量p被定義為bdata型,定位在片內(nèi) RAM中的位尋址區(qū)*/ (4)unsigned int pdata var1; /*無符號整型變量var1定義為pdata型 ,定位在片外RAM中,相當(dāng)于@Ri間接尋址*/ (5)unsigned char xd
28、ata a[2] [4]; /*無符號字符型二維數(shù)組變量 a[2][4] 被定義為xdata存儲類型,定位在片外RAM中,占據(jù) 2×4=8字節(jié),相當(dāng)于@DPTR間接尋址*/ 4.?dāng)?shù)據(jù)存儲模式 如果在變量定義時(shí)略去存儲類型標(biāo)識符,編譯器會自動默認(rèn)存儲類型。,25,進(jìn)一步由SMALL、COMPACT和LARGE存儲模式指令限制。例如,若聲明char var1,則在
29、使用SMALL存儲模式下,var1被定位在data存儲區(qū),在使用COMPACT模式下,var1被定位在idata存儲區(qū);在LARGE模式下,var1被定位在xdata存儲區(qū)中。下面對存儲模式作進(jìn)一步說明。(1)SMALL模式。該模式下,所有變量都默認(rèn)位于8051單片機(jī)內(nèi)部的數(shù)據(jù)存儲器,與使用data指定存儲器類型的方式一樣。在此模式下,變量訪問的效率高,但是所有數(shù)據(jù)對象和堆棧必須使用內(nèi)部RAM。(2)COMPACT模式 本模
30、式下所有變量都默認(rèn)在外部數(shù)據(jù)存儲器的1頁(256字節(jié))內(nèi),這與,26,使用pdata指定存儲器類型是一樣的。該類型適用于變量不超過256字節(jié)的情況,此限制是由尋址方式?jīng)Q定的,相當(dāng)于使用數(shù)據(jù)指針@Ri尋址。與SMALL模式相比,該存儲模式的效率比較低,對變量訪問的速度也慢一些,但比LARGE模式快。 (3)LARGE模式 本模式下所有變量都默認(rèn)位于外部數(shù)據(jù)存儲器,相當(dāng)于用@DPTR尋址。通過數(shù)據(jù)指針訪問外部數(shù)據(jù)存儲器的效率較低,
31、特別是當(dāng)變量為2字節(jié)或更多字節(jié)時(shí),該模式要比SMALL和COMPACT產(chǎn)生更多的代碼。,27,在固定的存儲器地址上進(jìn)行變量傳遞,是C51的標(biāo)準(zhǔn)特征之一。 在SMALL模式下,參數(shù)傳遞是在片內(nèi)數(shù)據(jù)存儲區(qū)中完成的。LARGE和COMPACT模式允許參數(shù)在外部存儲器中傳遞。C51也支持混合模式。例如,在LARGE模式下,生成的程序可將一些函數(shù)放入SMALL模式中,從而加快執(zhí)行速度。3.2.2 C51語言的特殊功能寄存器及位變量定義
32、 介紹C51如何對特殊功能寄存器及位變量進(jìn)行定義并訪問。1.特殊功能寄存器的C51定義 C51語言允許通過使用關(guān)鍵字sfr、sbit或直接引用編譯器提供的頭文件來對特殊功能寄存器(SFR)進(jìn)行訪問,,特殊功能寄存器分布在片內(nèi)RAM高128字節(jié)中,只能采用直接尋址方式。(1)使用關(guān)鍵字定義sfr。為能直接訪問特殊功能寄存器SFR,C51提供了一種定義方法,即引入關(guān)鍵字sfr,語法如下: sfr 特殊功能
33、寄存器名字=特殊功能寄存器地址;例如: sfr IE=0xA8;//中斷允許寄存器IE地址A8H sfr TCON=0x88;//定時(shí)器/計(jì)數(shù)器控制寄存器地址88H sfr SCON=0x98;//串行口控制寄存器地址98H在8051中,要訪問16位SFR,要用關(guān)鍵字sfr16。16位SFR的低字節(jié)地址須作為“sfr16”的定義地址,例如:,29,sfr16 DPTR=0x82//DPT
34、R 的低8位地址為82H,高8位地址為83H(2)通過頭文件訪問SFR。各種衍生型的8051單片機(jī)的特殊功能寄存器的數(shù)量與類型有時(shí)是不相同的,對其訪問可通過頭文件訪問來進(jìn)行。為用戶處理方便,C51把8051(或8052單片機(jī))常用的特殊功能寄存器和其中的可尋址位進(jìn)行了定義,放在一個(gè)reg51.h(或reg52.h)的頭文件中。當(dāng)用戶要使用時(shí),只需在使用之前用一條預(yù)處理命令#include把這個(gè)頭文件包含到程序中,就可使用特殊功能寄
35、存器名和其中的可尋址位名稱了。用戶可對頭文件進(jìn)行增減。,30,頭文件引用舉例如下:#include//包含8051單片機(jī)的頭文件void main(void){TL0=0xf0;//給T0低字節(jié)TL0設(shè)置時(shí)間常數(shù),已在reg51.h中定義 TH0=0x3f;//給T0高字節(jié)TH0設(shè)置時(shí)間常數(shù),已在reg51.h中定義 TR0=1;//啟動定時(shí)器0……}(3)特殊功能寄存器中的位
36、定義。對SFR中的可尋址位的訪問,要使用關(guān)鍵字來定義可尋址位,共3種方法。,① sbit 位名=特殊功能寄存器^位置;例如:sfr PSW=0xd0; //定義PSW 寄存器的字節(jié)地址0xd0sbit CY=PSW^7; //定義CY位為PSW.7,地址為0xd0sbit OV=PSW^2; //定義OV位為PSW.2,地址為0xd2② sbit 位名=字節(jié)地址^位置; 例如:sbit
37、 CY=0xd0^7;// CY位地址為0xd7sbit OV=0xd0^2;// OV位地址為0xd2③ sbit 位名=位地址;將位的絕對地址賦給變量,位地址必須在0x80~0xff。例如:sbit CY=0xd7;// CY位地址為0xd7sbit OV=0xd2; // OV位地址為0xd2,32,【例】AT89S51單片機(jī)片內(nèi)P1口的各尋址位的定義如下:sfr P1=0x9
38、0; sbit P1_7= P1^7; sbit P1_6= P1^6; sbit P1_5= P1^5; sbit P1_4= P1^4; sbit P1_3= P1^3; sbit P1_2= P1^2; sbit P1_1= P1^1; sbit P1_0= P1^0; 2.位變量的C51定義 (1)由于8051可位操作,C51擴(kuò)展的“bit”數(shù)據(jù)類型用來定義
39、位變量,這是與標(biāo)準(zhǔn)C的不同之處。,33,C51采用關(guān)鍵字“bit”來定義位變量,一般格式為:bit bit_name;例如: bit ov_flag;//將ov_flag定義為位變量 bit lock_pointer;//將lock_pointer定義為位變量(2)函數(shù)可以包含類型為bit的參數(shù),也可將其作為返回值。C51程序函數(shù)可以包含類型為“bit”的參數(shù),也可將其作為返回值。例如:bit f
40、unc(bit b0, bit b1); // 位變量b0與b1作為函數(shù)func的參數(shù){ …… return(b1);// 位變量b1作為return函數(shù)的返回值},34,(3)位變量定義的限制。位變量不能用來定義指針和數(shù)組。例如: bit *ptr; // 錯(cuò)誤,不能用位變量來定義指針 bit ar
41、ray[ ]; // 錯(cuò)誤,不能用位變量來定義數(shù)組array[ ] 定義位變量時(shí),允許定義存儲類型,位變量都被放入一個(gè)位段,此段總是位于8051的片內(nèi)RAM中,因此其存儲類型限制為DATA或IDATA,如果將位變量定義成其他類型,將會導(dǎo)致編譯時(shí)出錯(cuò)。,35,3.2.3 C51語言的絕對地址訪問如何對8051片內(nèi)RAM、片外RAM及I/O空間進(jìn)行訪問,C51提供兩種常用的訪問絕對地址的方法。1.絕對宏編譯器提供了
42、一組宏定義對code、data、pdata和xdata空間進(jìn)行絕對尋址。程序中用“#include”來對absacc.h中聲明的宏來訪問絕對地址,包括CBYTE、CWORD、DBYTE、DWORD、XBYTE、XWORD、PBYTE、PWORD,具體使用參見absacc.h頭文件。其中:,36,CBYTE以字節(jié)形式對code區(qū)尋址;CWORD以字形式對code區(qū)尋址;DBYTE以字節(jié)形式對data區(qū)尋址;DWORD以字形式對da
43、ta區(qū)尋址;XBYTE以字節(jié)形式對xdata區(qū)尋址;XWORD以字形式對xdata區(qū)尋址;PBYTE以字節(jié)形式對pdata區(qū)尋址;PWORD以字形式對pdata區(qū)尋址。,【例】片內(nèi)RAM、片外RAM及I/O定義的程序如下: #include#define PORTA XBYTE[0xFFC0] //將PORTA定義為外部I/O口,地址為0xFFC0,長度8位#define NRAM DB
44、YTE[0x50] //將NRAM定義為片內(nèi)RAM,地址為0x50,長度8位main( ){PORTA=0x3d; //將數(shù)據(jù)3DH寫入地址為0xffc0的外部I/O端口PORTA中 NRAM=0x01; //將數(shù)據(jù)01H寫入片內(nèi)RAM的0x40單元},38,2. _at_ 關(guān)鍵字關(guān)鍵字 _at_ 可對指定的存儲器空間的絕對地址訪問,格式如下:[存儲器類型] 數(shù)據(jù)類型說明符
45、變量名 _at_ 地址常數(shù)其中,存儲器類型為C51能識別的數(shù)據(jù)類型;數(shù)據(jù)類型為C51支持的數(shù)據(jù)類型;地址常數(shù)用于指定變量的絕對地址,必須位于有效的存儲器空間之內(nèi);使用 _at_ 定義的變量必須為全局變量。,39,【例】使用關(guān)鍵字 _at_ 實(shí)現(xiàn)絕對地址的訪問,程序如下:void main(void){ data unsigned char y1 _at_ 0x50; //在data區(qū)定義字節(jié)變量y1,地址為50H
46、 xdata unsigned int y2 _at_ 0x4000;//在xdata區(qū)定義字變量y2,地址為 //4000H y1=0xff; y2=0x1234; …… while(1);}【例】將片外RAM 2000H開始的連續(xù)20字節(jié)清0,程序如下:,40,xdata unsign
47、ed char buffer[20] _at_ 0x2000;void main(void){ unsigned char i; for(i=0; i<20; i++) { buffer[i]=0 }}如把片內(nèi)RAM 40H單元開始的8個(gè)單元內(nèi)容清0,程序如下:xdata unsigned char buffer[8] _at_ 0x40;void
48、 main(void){,41,unsigned char j ;for(j=0;j<8;j++){ buffer[j]=0 }}3.2.4 C51的基本運(yùn)算與標(biāo)準(zhǔn)C類似,主要包括算術(shù)運(yùn)算、關(guān)系運(yùn)算、邏輯運(yùn)算、位運(yùn)算和賦值運(yùn)算及其表達(dá)式等。1.算術(shù)運(yùn)算符 算術(shù)運(yùn)算符及說明見表3-4。,42,43,C51中表示加1和減1時(shí)可以采用自增運(yùn)算符和自減運(yùn)算符,自增和自減運(yùn)算符是使
49、變量自動加1或減1,自增和自減運(yùn)算符放在變量前和變量之后是不同的,見表3-5。,44,2.邏輯運(yùn)算符 邏輯運(yùn)算的結(jié)果只有“真”和“假”兩種,“1”表示真,“0”表示假。表3-6列出了邏輯運(yùn)算符及其說明。 例如條件“10>20”為假,“220)&&(2<6)=0&&1=0。3.關(guān)系運(yùn)算符 關(guān)系運(yùn)算符是判斷兩個(gè)數(shù)之間的關(guān)系。說明如表3-7所示。,45,46,4.位運(yùn)算
50、位運(yùn)算符及其說明見表3-8。,47,在實(shí)際應(yīng)用中,常想改變I/O口中某一位的值,而不影響其他位,如果I/O口可位尋址的,這個(gè)問題就很簡單。但有時(shí)外擴(kuò)的I/O口只能進(jìn)行字節(jié)操作,要想實(shí)現(xiàn)單獨(dú)位控,就要采用位操作?!纠?編程將擴(kuò)展的某I/O 口 PORTA(只能字節(jié)操作)的PORTA.5清 0,PORTA.1置1,程序如下:#define //定義片外 I/O 口變量PORTA要用該
51、頭文件#define PORTA XBYTE[0xffc0] //定義一個(gè)片外 I/O 口變量PORTAvoid main( ){ …… PORTA=( PORTA&0xdf)│0x02; ……},48,程序中,第2行定義一個(gè)片外 I/O 口變量PORTA,地址為片外數(shù)據(jù)存儲區(qū)的0xffc0。在main( )函數(shù)中,“
52、PORTA=( PORTA&0xdf)│0x02”的作用是先用運(yùn)算符“&”將PORTA.5置成0,然后再用“│0x02”運(yùn)算將PORTA.1置為1。5.指針和取地址運(yùn)算符 指針是C51語言中一個(gè)十分重要的概念,指針變量用于存儲某個(gè)變量的地址,C51用“*”和“&”運(yùn)算符來提取變量內(nèi)容和變量地址,見表3-9。,49,提取變量的內(nèi)容和變量的地址的一般形式分別為:目標(biāo)變量=*指針變量 //將指針變量所指的存
53、儲單元內(nèi)容賦值給目標(biāo)變量指針變量=&目標(biāo)變量//將目標(biāo)變量的地址賦值給指針變量例如:a=&b;//取b變量的地址送至變量ac=*b;//把以指針變量b為地址的單元內(nèi)容送至變量c指針變量中只能存放地址(即指針型數(shù)據(jù)),不能將非指針類型的數(shù)據(jù)賦值給指針變量。例如:int i ;//定義整型變量iint *b; //定義指向整數(shù)的指針變量bb=& i;
54、 //將變量i的地址賦給指針變量bb= i; //錯(cuò),指針變量b只能存放變量指針(變量地址),不能存放變量i的值,50,3.2.5 C51的分支與循環(huán)程序結(jié)構(gòu) C51程序按結(jié)構(gòu)可分為3類,即順序、分支和循環(huán)結(jié)構(gòu)。順序結(jié)構(gòu)是基本結(jié)構(gòu),程序自上而下,從main( )的函數(shù)開始一直到程序結(jié)束,只有一條路可走,無其他路徑可選,結(jié)構(gòu)較簡單和便于理解,這里僅介紹分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)。1.分
55、支控制語句分支控制語句有:if語句和switch語句。(1)if語句用來判定所給定的條件是否滿足,根據(jù)判定結(jié)果決定執(zhí)行兩種操作之一。 if語句的基本結(jié)構(gòu)如下: if (表達(dá)式) {語句} 括號中的表達(dá)式成立時(shí),程序執(zhí)行大括號內(nèi)的語句,否則,51,程序跳過大括號中的語句部分,而直接執(zhí)行下面的其他語句。C51提供3種形式的if語句:形式1 if (表達(dá)式) {語句}例如:
56、 if (x>y) {max=x; min=y;}即如果x>y,則x賦給max,y賦給min。如果x>y不成立,則不執(zhí)行大括號中的賦值運(yùn)算。形式2if (表達(dá)式) {語句1;} else {語句2;},例如:if (x>y){max=x; }else {max=y;}本形式相當(dāng)于雙分支選擇結(jié)構(gòu)。形式3if (表達(dá)式1) {語句1;}else if (表達(dá)式2) {語句2
57、;}else if (表達(dá)式3) {語句3;}……else {語句n;},53,例如:if (x>100) {y=1;}else if (x>50) {y=2;}else if (x>30) {y=3;}else if (x>20) {y=4;}else {y=5;}本形式相當(dāng)于串行多分支選擇結(jié)構(gòu)。在if語句中又含有一個(gè)或多個(gè)if語句,這稱為if語句的嵌套。應(yīng)當(dāng)注意if與else的
58、對應(yīng)關(guān)系,else總是與它前面最近的一個(gè)if語句相對應(yīng)。,54,(2)switch語句。if語句只有兩個(gè)分支可選擇,而switch語句是多分支選擇語句。switch語句的一般形式如下:switch (表達(dá)式1) { case 常量表達(dá)式1:{語句1;}break; case 常量表達(dá)式2:{語句2;}break;……case 常量表達(dá)式n:{語句n;}break;default:{語句n+1;
59、}}上述switch語句說明如下。,55,(1)每一case常量表達(dá)式須互不相同,否則將混亂。(2)各個(gè)case和default出現(xiàn)次序,不影響程序執(zhí)行的結(jié)果。(3)switch括號內(nèi)表達(dá)式的值與某case后面的常量表達(dá)式的值相同時(shí),就執(zhí)行它后面的語句,遇到break語句則退出switch語句。若所有的case中的常量表達(dá)式的值都沒有與switch語句表達(dá)式的值相匹配時(shí),就執(zhí)行default后面的語句。(4)如果在case語句
60、中遺忘了break語句,則程序執(zhí)行了本行之后,不會按規(guī)定退出switch語句,而是將執(zhí)行后續(xù)的case語句。在執(zhí)行1個(gè)case分支后,使流程跳出switch結(jié)構(gòu),即中止switch語句的執(zhí)行,可以用1條break語句完成。,56,switch語句的最后一個(gè)分支可以不加break語句,結(jié)束后直接退出switch結(jié)構(gòu)?!纠吭趩纹瑱C(jī)程序設(shè)計(jì)中,常用switch語句作為鍵盤中按鍵按下的判別,并根據(jù)按下鍵的鍵號跳向各自的分支處理程序。,inp
61、ut: keynum=keyscan( )switch(keynum){case 1:key1( ); break;//如果按下鍵為1鍵,則執(zhí)行函數(shù)key1( )case 2:key2( ); break;//如果按下鍵為2鍵,則執(zhí)行函數(shù)key2( )case 3:key3( ); break;//如果按下鍵為3鍵,則執(zhí)行函數(shù)key3( )case 4:key4( ); break;//如果按下鍵
62、為4鍵,則執(zhí)行函數(shù)key4( )…… default:goto input}例子中的keyscan( )是另行編寫的一個(gè)鍵盤掃描函數(shù),如有鍵按下,該函數(shù)就會得到按下鍵的鍵值,將鍵值賦予變量keynum。如果鍵值為2,則執(zhí)行鍵值處理函數(shù)key2( )后返回;如果鍵值為4,則執(zhí)行key4( )函數(shù)后返回。,58,執(zhí)行完1個(gè)鍵值處理函數(shù)后,則跳出switch語句,從而達(dá)到按下不同的按鍵來進(jìn)行不同的鍵值處理的目的。2.循
63、環(huán)控制語句 許多實(shí)用程序都包含循環(huán)結(jié)構(gòu),熟練掌握和運(yùn)用循環(huán)結(jié)構(gòu)的程序設(shè)計(jì)是C51語言程序設(shè)計(jì)的基本要求。 實(shí)現(xiàn)循環(huán)結(jié)構(gòu)的語句有以下3種:while語句、do-while語句和for語句。(1)while語句。語法形式為:,59,while(表達(dá)式) { 循環(huán)體語句; }表達(dá)式是while循環(huán)能否繼續(xù)的條件,如果表達(dá)式為真,就重復(fù)執(zhí)行循環(huán)體語句;反之,則終止循環(huán)體內(nèi)的
64、語句。while循環(huán)結(jié)構(gòu)特點(diǎn):循環(huán)條件測試在循環(huán)體開頭,要想執(zhí)行重復(fù)操作,首先必須進(jìn)行循環(huán)條件的測試,如條件不成立,則循環(huán)體內(nèi)的重復(fù)操作一次也不能執(zhí)行。,例如: while((P1&0x80)= =0) { }while中的條件語句對AT89S8051單片機(jī)的P1口的P1.7位進(jìn)行測試,如果P1.7為低(0),則由于循環(huán)體無實(shí)際操作語句,故繼續(xù)測試下去(等待),一旦P1.7的電平變高(1),則循環(huán)終止。(2)do-
65、while語句。語法形式為:do{ 循環(huán)體語句;}while(表達(dá)式);,do-while語句特點(diǎn)是先執(zhí)行內(nèi)嵌的循環(huán)體語句,再計(jì)算表達(dá)式,如表達(dá)式的值為非0,則繼續(xù)執(zhí)行循環(huán)體語句,直到表達(dá)式的值為0時(shí)結(jié)束循環(huán)。 由do-while構(gòu)成的循環(huán)與while循環(huán)的重要區(qū)別是:while循環(huán)的控制出現(xiàn)在循環(huán)體之前,只有當(dāng)while后面表達(dá)式的值非0時(shí),才可能執(zhí)行循環(huán)體;在do-while構(gòu)成的循環(huán)中,總是先執(zhí)行一次循環(huán)體,
66、然后再求表達(dá)式的值,因此無論表達(dá)式的值是0還是非0,循環(huán)體至少要被執(zhí)行一次。 在do-while循環(huán)體中,要有能使while后表達(dá)式的值變?yōu)?的操作,否則,循環(huán)會無限制地進(jìn)行下去。根據(jù)經(jīng)驗(yàn),do-while循環(huán)用的并不多,大多數(shù)的循環(huán)用while來實(shí)現(xiàn)會直觀。,【例】實(shí)型數(shù)組sample存有10個(gè)采樣值,編寫程序段,要求返回其平均值(平均值濾波)。程序如下:float avg(float *sample) {
67、 float sum=0;char n=0;do { sum+=sample[n]; n++; } while(n<10); return(sum/10); }(3)基于for語句的循環(huán)。3種循環(huán)常用的是for循環(huán)。不僅可用于循環(huán)次數(shù)已知的情況,也可用于循環(huán)次數(shù)不確定而只給出循環(huán)條件情況,完全可
68、替,代while語句。for循環(huán)的一般格式為:for(表達(dá)式1;表達(dá)式2;表達(dá)式3){循環(huán)體語句;}for是關(guān)鍵字,括號中常含有3個(gè)表達(dá)式,各表達(dá)式間用“;”隔開。這3個(gè)表達(dá)式可以是任意形式的表達(dá)式,通常主要用于for循環(huán)控制。緊跟在for()之后的循環(huán)體,在語法上要求是 1 條語句;若在循環(huán)體內(nèi)需要多條語句,應(yīng)用大括號括起來組成復(fù)合語句。,for執(zhí)行過程如下:① 計(jì)算“表達(dá)式1”,表達(dá)式1通常稱為
69、“初值設(shè)定表達(dá)式”。② 計(jì)算“表達(dá)式2”,表達(dá)式2通常稱為“終值條件表達(dá)式”,若滿足條件,轉(zhuǎn)下一步,若不滿足條件,則轉(zhuǎn)步驟⑤。③ 執(zhí)行1次for循環(huán)體。④ 計(jì)算“表達(dá)式3”,“表達(dá)式3”通常稱為“更新表達(dá)式”轉(zhuǎn)向步驟②。⑤ 結(jié)束循環(huán),執(zhí)行for循環(huán)之后的語句。,下面對for語句的幾個(gè)特例進(jìn)行說明。① for語句中的小括號內(nèi)的3個(gè)表達(dá)式全部為空。例如:for(;;){循環(huán)體語句;}在小括號內(nèi)只有兩分號,無表達(dá)式
溫馨提示
- 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. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 單片機(jī)原理及接口技術(shù) c51編程 教學(xué)課件 ppt 作者 張毅剛 第3章 c51語言編程基礎(chǔ)
- c51語言及編程淺析
- 51單片機(jī)c語言編程基礎(chǔ)及實(shí)例
- c語言第3章
- c51語言復(fù)習(xí)題參考答案
- c51題答案
- 基于單片機(jī)的智能避障小車設(shè)計(jì)(c51語言編程)【開題報(bào)告】
- 第02章 c++語言基礎(chǔ)
- 單片機(jī)語言C51應(yīng)用實(shí)戰(zhàn)集錦.pdf
- 0547、單片機(jī)語言c51應(yīng)用實(shí)戰(zhàn)集錦
- 0547、單片機(jī)語言c51應(yīng)用實(shí)戰(zhàn)集錦
- c語言基礎(chǔ)編程題
- c51存儲單元
- 基于單片機(jī)的電子計(jì)算器設(shè)計(jì)(c51語言編程)【開題報(bào)告】
- c51語言復(fù)習(xí)題參考答案講解
- 單片機(jī)語言C51應(yīng)用實(shí)戰(zhàn)集錦.pdf
- 第3章 jsp語言基礎(chǔ)
- 基于單片機(jī)的智能避障小車設(shè)計(jì)(c51語言編程)【任務(wù)書】
- c51與匯編語言混合編程在單片機(jī)iap中的應(yīng)用
- c51實(shí)用子程序
評論
0/150
提交評論