第10章 80C51單片機的C語言程序設計_第1頁
第10章 80C51單片機的C語言程序設計_第2頁
第10章 80C51單片機的C語言程序設計_第3頁
第10章 80C51單片機的C語言程序設計_第4頁
第10章 80C51單片機的C語言程序設計_第5頁
已閱讀5頁,還剩120頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第10章 80C51單片機的C語言程序設計 C51的數據類型 10.2C51流程控制語句10.4C51的運算符和表達式310.3 單片機C語言概述310.110.5C51的構造數據類型10.6C51編程實例310.7C51的函數10.1單片機C語言概述10.1.1 C51的程序結構 返回 C51的程序結構與標準C語言根本相同。其結構特點如下:1.函數是C51程序的根本單位。標準的C51程序通常是多個函數的集合,在這個集合當中,有且只有一個main函數主函數。不管main函數在整個程序中所處的位置如何,C51程序總是從main函數開始執行。2.C51程序書寫格式自由,一行內可以寫幾個語句。3.分

2、號是C51語句的重要組成局部,每個語句和數據定義函數除外的最后必須有一個分號。4.C51本身沒有輸入輸出語句。標準的輸入和輸出是由scanf和printf等庫函數來完成的。對于用戶定義的輸出,比方直接以輸出端口讀取鍵盤輸入或驅動LED,那么需要自行編制輸出函數。5.可以用/*/對C51程序中的任何局部作注釋。10.1.2 C51編譯器介紹單片機不能直接執行C51程序,執行前必須經過編譯,形成相應的可執行代碼,目前開發的編譯器種類繁多,并非所有的C51編譯器產生高效代碼。AMERICAN AUTOMATION編譯器:該編譯器通過#asm和endasm預處理選擇支持匯編語言,此編譯器的編譯速度較慢

3、。IAR編譯器:IAR編譯器是由瑞典開發的,它和ANSI C兼容,但需要一個較復雜的鏈接程序才能運行。BSOTASKing編譯器:它是基于windows下的集成開發環境軟件(EDE),支持鼠標操作,人機界面友好,它的匯編器和Intel匯編器兼容KEIL編譯器:KEIL編譯器效率很高。它支持浮點和長整數、重入和遞歸,支持DOS和Window環境,但它不提供庫源代碼,只能產生混合代碼,假設使用匯編語言,必須分開匯編程序,然后手工連接。假設使用單片模式,它是最好的選擇。10.1.3 C51的特點(1) C語言采用與人的思維更接近的關鍵字和操作函數。(2) C語言提供了大量的標準庫文件 (3) C語言

4、采用模塊化編程思想(4)C語言可移植性好 (5)通用性好(6)存放器分配和尋址方式由編譯器進行管理很多系統特別是實時時鐘系統都是用C 語言和匯編語言聯合編寫的,尤其是對時序要求很嚴格的驅動程序來說使用匯編語言是唯一的方法。10.2 C51的數據類型返回 數據是具有一定格式的數字或數值,是計算機操作的對象。任何語言編寫的程序最終在計算機中運行的只有數據流。編程的目的就是讓CPU按照程序流程對各種數據進行相應的操作,并得到編程者所期望的運算結果。數據操作會因數據類型不同而有較大的差異,其差異主要表達在取值范圍、存儲位置和存儲空間大小等幾個方面。數據類型長度取值范圍字符型Unsigned char8

5、0255Signed char8-128127整型Unsigned int16065535Signed int16-3276832767長整型Unsigned long3204294967295Signed long32-21474836482147483647浮點型float321.18e-383.40e38位型bit10或1sbit10或1SFRsfr80-255Sfr1616065535C51的數據類型 C51和標準C的區別:1. C語言的根本數據類型有char、int、short、long、float、double等六種類型。對于C51來說,short、int、float和double

6、類型都是一樣的。因為C51主要針對控制類的應用,所以C51不支持復雜的雙精度浮點運算double。2 .float也與標準C一樣符合IEEE-754標準,但float的使用和運算,需要調用數學庫“math.h函數的支持。3 .布爾處理器是8051單片機的特色,位類型bit可以定義一個位變量,由C51編譯器在8051內部RAM區20H-2FH的128個位地址中分配一個位地址。需要注意的是,位類型不能定義指針和數組。4 .特殊功能存放器sfr和sfr16:8051及其兼容產品的特殊功能存放器必須采用直接尋址的方式來訪問,sfr可以對8051的特殊功能存放器進行定義,數據占用一個字節。sfr16為1

7、6位特殊功能存放器,8051及其兼容產品的16位特殊功能存放器如DPTR可以用sfr16來定義,數據占用兩個字節。5. 在C51編譯器提供的頭文件reg51.h中已經把所有的特殊功能存放器進行了定義,我們可以直接用include命令使其包括在程序中。注意:在使用時,所有的sfr的名稱都必須大寫。6. 可尋址位類型sbit:利用sbit可以對8051內部RAM的位尋址空間及特殊功能存放器的可尋址位進行定義。7.數據類型的轉換: 不同類型的數據是可以相互轉換的,可以通過賦值或者強制轉換。賦值轉換次序為:bit-char-int-long-float,如果反向賦值,那么結果丟棄高位。10.2.2 C

8、51數據的存儲類型 C51是面向51單片機的程序語言,所以任何數據都必須以一定的方式存儲在不同的位置。數據分為常量和變量兩種形式。常量可以用一個標志符號來代表。變量由變量名和變量值組成,每一個變量占據一定的存儲空間用以存放變量的值。存儲器類型長度存儲位置說 明data8片內RAM直接尋址:007FH,速度最快bdata8可位尋址:20H2FHidada8間接尋址:00FFHpdata8片外RAM分頁間址:00FFH, MOVX Ri指令訪問xdata16間接尋址:0000FFFFH MOVX DPTR訪問code16ROM間接尋址:0000FFFFH MOVC A+DPTR訪問C51對變量定義

9、時,既可以定義數據類型,還可以定義存儲類型。其格式為: “數據類型 存儲類型 變量名。例如: char data name_var; /*字符變量name_var存儲在片內RAM區*/ float idata x ; /*浮點型變量x存儲在片內間址RAM區*/ bit bdata flags; /*位變量flags存儲在片內RAM位尋址區*/存儲類型為可選項,如果不做存儲類型的定義,系統將選擇默認存儲模式來存儲,默認類型由編譯控制命令指令限制。存儲模式與默認存儲類型存儲模式默認存儲類型特點說明SMALLdata(小模式)存儲于片內RAM,速度快COMPACTpdata(緊湊模式)存儲于片外分頁

10、RAMLARGExdata(大模式)存儲于片外64K的RAM,速度慢例如,假設聲明char v,在SMALL模式下,v被定位在data區;在使用COMPACT模式下,那么v被定位在pdata區;在使用LARGE模式情況下,v被定位在xdata區中。10.2.3 8051單片機特殊功能存放器的C51定義一 、特殊功能存放器的聲明如何對SFR操作對SFR的操作,只能用直接尋址方式。為了能直接訪問這些特殊功能存放器SFR,C51提供了一種獨特的定義方法,這種定義方法與標準C語言不兼容,只適用于對8051系列單片機進行編程。其定義語法如下:sfr nameadress “sfr為保存關鍵字,其后面必須

11、跟一個特殊存放器名稱, “后面的地址必須是常數,不允許帶有運算表達式,其常數值范圍必須在特殊功能存放器地址范圍0 x80到0 xFF之間。例: sfr SCON0 x90; *串口控制存放器地址 90H*特殊功能存放器位的聲明在8051單片機的應用中,經常需要對SFR進行位操作,特殊位的定義利用關鍵字sbit進行說明,與sfr定義一樣,用關鍵字“sbit定義某些持殊位時能接受任何符號名稱,這種地址分配有三種方式:第1種方式: sbit 位變量=特殊功能存放器名位位置0-7有效例如:sfr PSW0 xD0; /*定義PSW存放器地址為0 xD0*/第2種方式: sbit 位變量名=字節地址位位

12、置0-7例如:sbit OV0 xD02; *OV位地址為0 xD2* 這種方法以一個整常數作為基地址,該值必須在0X800 xFF之間,并能被8整除。第3種方式:sbit 位變量名=位地址 這種方法將位的絕對地址賦給變量,地址必須位于0 x80到0 xFF之間。例如:sbit OV0XD2;10.3 C51的運算符和表達式運算符就是完成某種特定運算的符號,按運算符在表達式中與運算對象的數量可分為單目運算符,雙目運算符和三目運算符。單目就是指需要有一個運算對象雙目就要求有兩個運算對象表達式那么是由運算及運算對象所組成的具有特定含義的式子。返回10.3.1 賦值運算符將數據賦給變量:變量 = 表

13、達式例如:a=0 xFF;/將常數0 xFF賦于變量a b=c=33;/同時將33賦值給變量b,c f=a+b;/將變量a+b的值賦于變量f先計算出=右邊的表達式的值,然后將得到的值賦給左邊的變量。而且右邊的表達式可以是一個賦值表達式。注意:賦值符號“=與關系運算符“=相等不能混淆。10.3.2 算術運算符+ 加或取正值運算符 - 減或取負值運算符* 乘運算符 / 除運算符% 取余運算符 算術表達式的形式: 表達式1 算術運算符 表達式2算術運算符的優先級: 先乘除模,后加減,括號最優先。 算術運算符的結合性:算術運算符的結合性規定為自左至右方向,又稱為“左結合性。10.3.3 關系運算符當指

14、定的條件滿足時結果為1真,不滿足時結果為0假。 關系運算符的優先級別: 前四個具有相同的優先級,后兩個也具有相同的優先級,但是前四個的優先級要高于后兩個。例 假設a=4,b=3,c=2 那么 ab的值為“真,表達式值為1;b+cbc,由于關系運算符的結合性為左結合,故ab值為1。而1c位為0,故f值為0。10.3.4 邏輯運算符 邏輯運算符那么是用于求條件式的邏輯值,邏輯運算結果只有真與假兩種。& :邏輯與AND| :邏輯或(OR)! :邏輯非(NOT)常用運算符的優先級 “與邏輯和“或邏輯是雙目運算符,而“非邏輯是單目運算符。邏輯運算符優先級別:邏輯非最高,邏輯與次之,邏輯或最低。C51邏輯

15、運算符、算術運算符、關系運算符和賦值運算符之間優先級的次序中,!(非)運算符優先級最高,算術運算符次之,關系運算符再次之,與和或再次之,最低為賦值運算符。 例: a=1,b=2,c=3,d=4,m=0,n=0,那么m=ab: 因為ab為假(0),即m=0。(m=cd): 因為=運算符的優先級比運算符的低,所以先判斷cb& (n=cd): 因為ab為假(0),即m=0為真1,故需繼續向右執行,又因為cd為假(0),即n=0為真1,兩者相與結果為真1,故表達式值為1。10.3.5 位運算符位運算符:是按位對變量進行運算,但是并不改變參與運算和變量的值。 & 按位與;| 按位或; 按位異或; 按位取

16、反; 位右移;位運算一般的表達形式為:變量1 位運算符 變量2位運算符的優先級:高到低依次是: (按位取反)(右移) &(按位與)(按位異或)|(按位或)位運算符對象只能是整型或字符型數據,不能為實型數據例:a=0 xff,b=0 x01,那么c=a & b :c=0 x01c=a | b :c=0 xffc=ab:c= 0 xfec=a:c=0 x00c=ab:c=0 x7f10.3.6 其他運算符1.條件運算符C51中有一個三目運算符,它就是條件運算符?。邏輯表達式? 表達式1 : 表達式2; 當邏輯表達式的值為真時1時,整個表達式的值為表達式1的值; 當邏輯表達式的值為假0時,整個表達式

17、的值為表達式2的值。返回例:將a和b兩數中的較小的值放入min變量中。程序1if (ab)min = a;elsemin = b; 程序2min =(a= 右移位賦值 -= 減法賦值 &= 邏輯與賦值 *= 乘法賦值 |= 邏輯或賦值 /= 除法賦值 = 邏輯異或賦值 %= 取模賦值 != 邏輯非賦值 20|x-10) if(yx) printf(Good); else printf(Bad); 4. 可用階梯式if-else-if結構 if(表達式1) 語句1; else if(表達式2) 語句2; else if(表達式3) 語句3; else 語句n; 這種結構是從上到下逐個對條件進行判

18、斷, 一旦發現條件滿點足就執行與它有關的語句, 并跳過其它剩余階梯; 假設沒有一個條件滿足, 那么執行最后一個else語句n。10.4.2 循環語句一 .for循環for(; ; ) 語句; 初始化一般是一個賦值語句, 它用來給循環控制變量賦初值; 條件表達式是一個關系表達式, 它決定什么時候退出循環; 更新表達式說明循環控制變量每循環一次后按什么方式變化,假設更新后條件表達式為假FALSE那么退出循環。 例如: for(i=1; i10)時結束循環。注意: 1.for循環中語句可以為語句體, 但要用“將參加循環的語句括起來。 2.for循環中的初始化、條件表達式和更新表達式都是選擇項,可缺省

19、, 但分號“;不能缺省。 3.for循環可以多層嵌套。二 、 while循環 while(條件) 語句; 假設while循環條件為真時, 那么執行語句,為假那么循環結束。與for循環一樣,while循環總是在循環的開始檢驗條件,如果一開始條件就不滿足,那么意味著循環語句可能一次也不執行就退出。注意: 1、在while循環體內允許空語句。 2、可以有多層循環嵌套。 3、語句可以是語句體, 此時必須用“括起來。4、當條件恒為真時,那么程序進入一個死循環。單片機系統中經常利用這一特性實現前后臺系統的調用。三、do-while 循環 do 語句; while(條件); 該循環與while循環的不同在于

20、它先執行循環中的語句, 然后再判斷條件是否為真,如果為真那么繼續循環,如果為假, 那么終止循環。10.4.3 開關語句switch(變量) case 常量1: 語句1或空; case 常量2: 語句2或空; . . . case 常量n; 語句n或空; default: 語句n+1或空; 執行switch開關語句時, 將變量逐個與case后的常量進行比較, 假設與其中一個相等, 那么執行該常量下的語句, 假設不與任何一個常量相等, 那么執行default 后面的語句。 注意: 1. switch中變量可以是數值, 也可以是字符。 2. 可以省略一些case和default。 3. 每個case

21、或default后的語句可以是語句體,同樣要使用“括起來。 10.4.4 break、continue 和 goto 語句一.break語句break語句可以跳出循環而執行循環后面的語句,通常用在循環語句和開關語句中配合使用。break用于開關語句switch中時, 可使程序跳出switch而執行switch以后的語句;如果沒有break語句, 那么將成為一個死循環而無法退出。當break語句用于for、do-while、while循環語句中時, 可使程序終止循環而執行循環后面的語句, 通常break語句總是與if語句聯在一起,即滿足條件時便跳出循環。 二. continue 語句 conti

22、nue語句的作用是跳過本次循環中剩余的語句而強行執行下一次循環。這是與break語句的最大差異。continue語句通常只用在for、while、do-while等循環體中,常與if條件語句一起使用,用來加速循環。三.goto 語句 是一種無條件轉移語句goto 語句的使用格式為: goto標號: 標號是一個有效的標識符, 這個標識符加上一個“:一起出現在函數內某處, 執行goto語句后, 程序將跳轉到該標號處并執行其后的語句。 另外標號必須與goto語句同處于一個函數中,但可以不在一個循環層中。 在編程時goto語句要盡量少用,因為它將使程序層次不清,但在多層嵌套退出時, 用goto語句那么

23、比較合理。 10.5 C51的構造數據類型10.5.1 數組數組是一組具有固定數目和相同類型成分分量的有序集合,其成分分量的類型為該數組的根本類型。常用的有整型數組、字符型數組等。數組的各元素必須是同一類型的變量。1.數組的定義數組是用同一個名字的不同下標訪問的,數組的下標放在方括號中,是從0開始的一組有序整數。例如數組bi,當i=0,1,2,n時,b0,b1,,bn分別是數組b的元素。一維數組類型說明 存儲器類型 數組名整型 =初始值 例: char a6=“shiwei; /*字符數組a0=s, ,a5=i*/ int idata b5=0,1,2,3,4; /*字符數組b存儲于片內RAM

24、,且b0=0, ,b4=4 */二維數組類型說明 存儲器類型 數組名整型整型 =初始值二維數組的存取順序是按行存取,即先依次存取第1行元素的所有列,再存儲第2行,依次類推。例 int a22=1,2,3,4 /*整型數組a有4個元素,且a00=1, a01=2, a10=3, a11=4*/。二維數組的初始化有多種形式,下面的初始化結果是等效的:int a22=1,2,3,4; int a22=1,2,3,4;2.數組的應用例:設單片機的P0引腳和數碼管代碼段相連,P1.0和數碼管公共段相連共陰,請在數碼管上依次顯示0-9個數字,顯示時間間隔為1秒,試利用數組編寫程序。#includeint

25、code=0 x3f,0 x06,0 x5b,0 x4f,0 x66,0 x6d,0 x7d,0 x07,0 x7f,0 x6f;void main() for(i=0; i=9; i+) /*數組的訪問下標從0開始*/P1=0 xff; /*消隱*/ P0=codei; /*段譯碼*/P1=0 xfe; /*使能*/ Delay(1000); /*延時1秒*/ 10.5.2 指針指針就是指變量或數據所在的存儲區的地址,它為變量的訪問提供了一個特殊的方式。返回1.指針的根本概念如果程序中定義了一個變量,C51編譯器在編譯時就給這個變量在內存中分配相應的存儲空間。變量有變量名和變量值兩個概念,其

26、中變量名是數據的標號,變量值那么是數據的內容。內存單元也有兩個概念,一個是內存單元的地址,一個是內存單元的內容。前者是內存對該單元的編號,它表示在內存中的位置。后者指的是在該內存單元中存放的數據。在變量與內存單元的對應關系中,變量的變量名與內存單元的地址相對應。變量的變量值與內存單元的內容相對應。假設程序中定義了兩個整型變量a和b,它們的值分別為2、3,而C51編譯系統將地址為1000和1001的兩個字節內存單元分配給了變量a,將地址為1002和1003的兩字節內存單元分配給了變量b,那么變量a和b的地址為1000和1002,在內存中變量名a、b是不存在的,對變量值的存取是通過地址進行的。存取

27、的方式有兩種:1)直接訪問方式例:x=a,找到變量a在內存中的位置,即地址l000,然后由地址1000開始的兩個字節中取出2并賦給x。2)間接訪問方式例如:char data *bp ; /*定義指針變量bp */bp=&b ; /*將b的地址賦給指針變量bp*/X=*bp ; /*將b的內容3送給X*/要讀取變量b的值時,可以將變量b的地址放在另一個內存單元中(如放在2021、2021中),訪問時,先找到存放變量b的地址的內存單元的地址(2021、2021),然后從中取出變量b的地址(1002),然后從地址為(1002、1003)的兩字節內存單元中取出變量b的值3,該讀取過程中就使用了指針。

28、為了使用指針進行間接訪問,必須弄清關于指針的兩個根本概念,即變量的指針和指向變量的指針變量(簡稱指針變量)。變量的指針:變量的指針就是變量的地址。對于上面提到的變量a而言,其指針就是1000。指向變量的指針變量:假設有一個變量專門用來存放另一個變量的地址(即指針),那么該變量稱為指向變量的指針變量(簡稱指針變量)。上例中提到的地址為2021的內存單元,如果我們定義一個變量ap,并使其定位在地址為2021的這個內存單元上,那么ap就是一個指針變量。因為ap中(即2021址址單元中)存放著變量a的地址1000。上例中我們可以說變量a的指針(地址)為1000,不能說a的指針變量是1000。變量a的指

29、針變量應該是ap,ap的指針是2021。2. 指針的根本類型變量的指針就是變量的地址,用取地址運算符“&取得。語句ap = &a 就能把所取得的a指針地址存放在ap指針變量中。ap的值就變為 1000H。可見指針變量的內容是另一個變量的地址。指針定義的一般的格式: 數據類型指向對象的存儲器類型*指針存儲器類型變量名;一般指針類型當指向對象的存儲類型缺省時指針變量為一般類型,一般指針占用3個字節,第一個字節存放指針的存儲類型編碼,第二、三字節分別存放指針的高位和低位的地址。存儲類型data/bdata/idataxdatapdatacode編碼0 x000 x010 xfe0 xff例如: ch

30、ar * xdata pi 指針pi本身存于xdata空間,它指向char 型數據,任何區域的對象都可以賦值給它,第一字節為0 x01,其余字節為地址。由于指針變量的指向對象沒有確定存儲位置,所以在編譯不能確定對象的存儲位置,只能在程序運行時才能確定,故程序運行速度比較慢,但由于一般指針可以存儲任何變量而不必考慮變量在單片機的存儲位置,所以在單片機編程時絕大多數的指針都可采用一般指針形式。基于存儲器的指針類型當指向對象的存儲器類型缺省時,指針變量為基于存儲器的指針類型。由于不必為指針選擇存儲器,指針的長度可以為1字節idata,data,pdata或2字節code,xdata 例如: char

31、 data * xdata pi; 指針pi本身存于xdata空間,它指向char 型數據,且只能將data區域的對象賦值給pi,pi只占用1個字節。 char xdata * pi; 指針pi本身存于任意空間,它指向char 型數據,但只能將xdata區域的對象賦值給它,pi占用2字節。明確定義指針對象的存儲類型可以高效訪問對象,還能節省存儲器的開銷,這在嚴格要求程序體積的工程中很有用處,但只能將符合定義條件的變量賦值與它,兼容性較差,初學者要慎用。3.指針的應用指針變量中只能存放指針型數據即地址,不能將非指針型數據賦值給一個指針變量。如果有一個變量a,那么可以利用&a表示變量a的地址,如果

32、執行以下語句P=&a;那么表示將a的地址賦給了指針變量P,即P指向了變量a。為了獲取指針所指向的內容,可利用指針運算符“*來實現。例:char data *P; /*定義指針變量P為char類型,且指向data存儲器*/P=&a; /*將a的地址賦給指針變量P,a的地址為片內RAM區*/X=*P ; /*將a的地址的內容送給X*/10.5.3 結構將字符,整型,浮點等簡單數據類型按層次產生各種構造數據類型,這些組合在一起的數據是互相關聯的,這種按固定模式聚集在一起而構成的數據就是結構。結構的定義和使用: 1.將有共同屬性的一組變量放在一個結構體里,既可方便理解和標準編程,也有利于程序的移植和維

33、護。 2.用結構可以分配一連續內存,方便與指針結合起來使用。 3.同一結構中不同分量不能同名。返回.例:#include structfloat amplitude; int frequency; int offset;waveform ; /*結構體定義*/main() int asizeof(waveform); unsigned char *ptr=&waveform;unsigned char i; waveform.amplitude=1 ; /*結構體賦值*/waveform.frequency=2 ; /*結構體賦值*/ waveform.offset=3 ; /*結構體賦值*/

34、for(i=0;isizeof(waveform);i+)ai=*(ptr+i) ; /*將結構體的值分別存儲到數組a中*/顯然,結構體數據利用指針和數組就可以將數據讀出來,當然也可以將這些數據保存到對應的存儲區。10.5.4 枚舉枚舉是一個被命名的整型常數的集合。例如表示星期的SUNDAY,MONDAY,TUESDAY, WEDNESDAY,THURSDAY,FRIDAY,SATURDAY。枚舉的說明:enum 枚舉名標識符=整型常數,標識符=整型常數,標識符=整型常數,枚舉變量;返回如果枚舉沒有初始化, 即 “=整型常數局部缺省,那么從第一個標識符開始, 順次賦給標識符0,1,2,但當枚舉

35、中的某個成員賦值后, 其后的成員按依次加1的規那么確定其值。例如:enum string x1,x2,x3=50,x4 那么x1=0, x2=1, x3=50, x4=51注意:1.枚舉中每個成員間用逗號隔離,不是分號,且最后一個逗號可省。2.初始化時可以賦負數,以后的標識符仍依次加1。3.枚舉變量只能取枚舉說明結構中的某個標識符常量。10.6 C51的函數 返回 main()也算是一個函數,只不過它比較特殊,編譯時以它做為程序的開始段。C51函數分為: 庫函數,自定義函數。庫函數是C51在庫文件中已定義的函數,其函數說明在相關的頭文件中。對于這類函數,用戶在編程時只要用#include預處理

36、指令將頭文件包含在用戶文件中就可直接調用。用戶函數是用戶自己定義和調用的一類函數。 一個函數在程序中可以有三種形態:函數定義、函數調用和函數說明。函數定義和函數調用不分先后,但假設調用的函數在定義之前,那么在調用前必須先進行函數說明。函數說明是一個沒有函數體的函數定義,而函數調用那么要求有函數名和實參數表。#include / 使用include預處理偽指令將所需庫函數包含進來unsigned int z ;/ 變量定義int max(x,y);/ 函數說明unsigned int a=2;unsigned int b=3;main()while(1)z=max(a,b) ;/函數調用int

37、max(x,y) / 函數定義if(xy) return x;elsereturn y;10.6.1 C51函數定義函數定義的形式:函數返回值類型 函數名形式參數函數體函數返回值其實就是一個變量,只要按變量類型來定義函數類型就行。函數體返回值的類型一定要和函數類型一致,否那么會造成錯誤。如果函數不需要返回值應用關鍵字“void明確表示。返回函數名的定義在遵循C語言變量命名規那么的同時,不能在同一程序中定義同名的函數。形式參數是指調用函數時要傳入到函數體內參與運算的變量,它可以有多個或沒有,沒有形式參數時括號內為空,但括號不能少。函數體中能包含有局部變量的定義和程序語句,如函數要返回運算值那么要

38、使用return語句進行返回。在函數體中可以沒有任何語句的函數稱為空函數。在一個程序工程中能寫一些空函數,在以后的修改和升級中能方便地利用這些空函數中進行功能擴展。int max(x,y) / 函數定義if(xy) return x;elsereturn y;該函數的名稱為max, 函數返回值類型為int,x和y是函數的形式參數。10.6.2 C51函數調用函數是能相互調用的,但在調用函數前,必須對函數的類型進行說明。函數調用是指一個函數體中引用另一個已定義的函數來實現所需要的功能。調用函數的一般形式: 函數名 (實際參數表);函數名就是指被調用的函數名。假設被調用函數有參數,那么主調函數必須

39、把被調函數所需的參數傳遞給被調函數的參數,即實參,實參向形參的傳遞是單向的,且實參的類型、位置應與形參一一對應,否那么就會產生錯誤。返回main()while(1)z=max(a,b) ;/函數調用max函數調用時a和b為實際參數,其實際參數和形式參數的對應關系為: a=x,b=y。10.6.3 混合編程簡介混合編程中,首先要了解C51函數名和匯編函數名之間的轉換規律,其次要明白函數間參數的傳遞原那么。1.C51函數名的轉換在KEIL C51中,編譯器對C語言程序中的函數會自動的進行轉換。 混合編程函數轉換規那么C51函數名稱轉換后的函數名稱說 明void func1(void)func1無參

40、數傳遞的函數void func2(int)_func2通過寄存器傳遞參數的函數void func3(char)reentrant_?func3可重入函數固定存儲位置傳遞參數的函數2.C51函數名和段屬性的命名規那么Keil編譯器的編譯過程是首先將工程中的源文件編譯為目標代碼obj文件,然在再通過連接器產生為最終可執行的hex文件。其中目標代碼將其中的代碼、數據、常量放在不同的“段中,保存程序的段稱為“代碼段,保存數據的段稱為“數據段,最終目標代碼經過Keil的連接器按照“段的要求轉換為程序和數據地址固定的可執行文件。“段按定位屬性分為:“可重定位段和“絕對段。 段命名規那么可重定位段:程序和數

41、據在其分別所對應的存儲單元FLASH和RAM中的存儲地址是浮動的、可重定義的、相對可變的。絕對段:其地址在連接前就已確定不變,連接器據此為它分配地址。段的命名格式隨存儲器模式的不同有所變化。段內容段類型段 名程序代碼CODE?PR?函數名?模塊名變量DATA?DT?函數名?模塊名(SMALL模式)PDATA?PD?函數名?模塊名(COMPACT模式)XDATA?XD?函數名?模塊名(LARGE模式)BIT型變量BIT?BI?函數名?模塊名3.C51函數參數傳遞和返回常用的參數傳遞方式有存放器傳遞和固定存儲器位置傳遞兩種方式。存放器參數傳遞:存放器參數傳遞指參數通過存放器R1R7來傳遞的,這種形

42、式可產生高效的代碼,利用51單片機的工作存放器最多傳遞3個參數。固定存儲位置參數傳遞:當無存放器可用或是采用了編譯控制指令“NOREGPARMS,那么參數的傳遞將發生在固定的存儲器區域,該存儲器區域稱為參數傳遞段,其地址空間取決于編譯時所選擇的存儲器模式。在SMALL模式下參數傳遞在內部RAM中完成,在COMPACT和LARGER模式下參數傳遞要在外部RAM中完成。例如: Fun1int a:a是第一個參數,在R6,R7中傳遞; Fun2int b,int c, int *d:b在R6,R7中傳遞, c在R4,R5中傳遞, *d那么在R1,R2,R3中傳遞。在混合編程有時還要進行參數返回,在函

43、數或子程序返回時,依據返回數據的類型不同有較大的差異。存放器參數傳遞對應的存放器傳遞參數char、1字節指針int 、2字節指針Long、 float一般指針參數1R7R6,R7R4-R7R1,R2,R3參數2R5R4,R5R4-R7R1,R2,R3參數3R3R2,R3無R1,R2,R3混合編程返回值規那么返回類型所用寄存器返回類型所用寄存器BitC累加器Char,1字節指針R7longR4-R7int,2字節指針R6,R7floatR4-R7一般指針R1-R310.6.4 混合編程形式舉例 混合編程主要有C51內嵌匯編代碼和C51調用匯編函數等兩種形式。 1.C51內嵌匯編代碼要實現在C51

44、函數中直接加匯編代碼,需要注意以下幾個方面:1將要嵌入的匯編語句用#pragma ASM和#pragma ENDASM語句涵括。2在 Project 窗口中右擊包含匯編代碼的 C 文件,選擇“Options for . ,然后單擊右邊的“Generate Assembler SRC File和“Assemble SRC File,使選擇框由灰色變成黑色狀態。 3根據選擇的編譯模式,把KeilC51Lib路徑下相應的庫文件參加工程中,假設未添加此庫文件,那么會提示“ UNRESOLVED EXTERNAL SYMBOL 警告。通過以上三步設置,即可編譯生成目標代碼。庫文件和編譯模式的選擇表庫文件

45、編譯模式C51S.LIB沒有浮點運算的 Small modelC51C.LIB沒有浮點運算的 Compact modelC51L.LIB沒有浮點運算的 Large modelC51FPS.LIB帶浮點運算的 Small modelC51FPC.LIB帶浮點運算的 Compact modelC51FPL.LIB帶浮點運算的 Large model例:include void main(void)P2=1;#pragma asmMOV R7,#10DEL:MOV R6,#20DJNZ R6,DJNZ R7,DEL#pragma endasmP2=0;本卷須知:1在匯編語言中可以加標簽以執行跳轉指令

46、,但標簽不要與編譯器產生的其他標簽相同。2在遵循了Cx51參數的調用規那么后,如要傳遞char參數時,編譯器會將其編譯成通過R7傳遞,此時假設在匯編語言中直接調用R7,會出現定義的變量形參未調用警告。2.C51調用匯編函數 采用C51調用匯編子程序時,被調用的匯編程序的名字、段名、參數讀取方式和返回值的設置都要按照相應的規那么進行,否那么將無法完成調用。同時還要注意以下三個方面的設置:要在C程序中用extern語句聲明即將調用的匯編函數;要在匯編函數中用PUBLIC語句將被調用的匯編函數聲明為公共函數;在匯編程序前面要注意段屬性的說明。 例如:example.c和example.a51為工程中

47、的兩個文件,只要將兩個文件添加到同一個工程工程中就可以成功編譯。*example.c*#include extern void delay100();extern DELAY100(a,b); /聲明外部函數,以便在C51中調用直接調用。unsigned int a=4;unsigned int b=3;main()DELAY100(a,b);*example.a51*?PR?DELAY100 SEGMENT CODE; / 在程序存儲區中定義段PUBLIC _DELAY100; /聲明函數帶參數傳遞,故函數形式為_DELAY100RSEG ?PR?DELAY100; /函數可被連接器放置在任

48、何地方_DELAY100: DJNZ R5,$DEL:DJNZ R7,DELRETEND10.6.4 C51庫函數標準庫函數按功能不同寫在各種頭文件中,使用時只要在程序最前面用#include預處理語句予以說明相應的頭文件即可。C51常用頭文件簡介 頭文件名說 明reg51.h51單片機的特殊寄存器reg52.h52單片機的特殊寄存器stdio.h標準輸入和輸出程序math.h數學程序absacc.h允許直接訪問8051不同存儲區的宏定義string.h字符串操作程序、緩沖區操作程序10.7 C51編程實例10.7.1 中斷效勞函數編程中斷函數編程的完整形式如下:函數返回值 函數名(參數)編譯

49、模式 重入 interrupt n using m編譯模式為SMALL、COMPACT或LARGE,用來指定參數和變量的存儲空間。重入:用于定義可重入函數。interrupt n 用于定義中斷函數,n為中斷號,取值范圍為0-31,單片機系統中不同的中斷號都有固定的程序入口地址。using m 用于確定中斷效勞函數所使用的存放器組,m的取值范圍為0-3返回常用中斷源的中斷號和入口地址中斷號中斷源中斷向量0外部中斷 00003H1 定時器/計數器 0000BH2外部中斷 10013H3 定時器/計數器 1001BH4 串行口0023H 在編寫C51的中斷函數時,注意幾個問題:1.中斷函數沒有返回值

50、,因此它必須是一個void類型的函數;2.中斷函數不允許利用形式參數進行數據傳遞,只能利用存放器實現;3.不允許直接調用中斷函數;4.中斷函數對壓棧和出棧的處理由編譯器完成,無需人工管理;5.需要嚴格注意using m的使用,必須確保存放器組的正確切換;6.進入中斷函數時,SFR中的A,B,DPH,DPL和PSW都需要入棧;7.函數退出前,所有的存放器內容要出棧;8.函數由8051的特定中斷返回指令“RETI終止。例:設單片機的晶振頻率為12MHz,要求在P1.0引腳上輸出周期為2ms的方波。解:周期為2ms的方波要求定時的間隔1ms,定時時間到那么P1.0取反。定時器計數頻率晶振頻率12=1

51、MHz。計數周期1計數頻率1us。1msl000us,故計算器要計數1000次。考慮到計數器工作時是向上計數,所以必須給定時器賦初值為65536-1000。 (1)用定時器0的方式1編程,采用查詢方式。#include sbit P1_0=P10;void main()TMOD=0 x01 /*設置定時器0的工作方式為1*/TR0=1;/*開啟T/C0*/For(;) TH0(65536-1000)256); /*裝載計值*/ TL0(65536-1000)256); do while (!TF0); *查詢等待TF0置位(計數溢出時TF置1)* P1_0!P1_0 ; /*時間到P1.0取反

52、* TF0=0 ; /*軟件清TF0*(2)用定時器0的方式1編程,采用中斷方式。# include sbit P1_0=P10 ;定義T/C中斷函數*/void time0(void) interrupt 1 using 1 P1_0!P1_0 ; /* P1.0取反* /*裝載計數初值*/TH0(65536-1000)256); TL0(65536-1000)256);void main(void) /*設置定時器0的工作方式為1*/TMOD=0 x01; /*裝載計數初值*/ TH0(65536-1000)256); TL0(65536-1000)256);EA=1 ; /*開啟總中斷*

53、/ET0=1 ;/*開啟T/C0中斷*/TR0=1 ;/*啟動T/C0定時*/ while (1) ; *死循環等待中斷*10.7.2 串行口編程通常情況下,使用單片機的串行口時,選用的晶振比較固定,一般為6MHz,12MHz和11.0592MHz,常用于與微機的通信;選用的波特率也相對固定。 串行口常用波特率(波特率單位補充完整)串行口工作方式波特率fOSC= 6MHzfOSC= 12MHzfOSC=11.0592MHzSMOD TMOD TH1SMOD TMOD TH1SMOD TMOD TH1方式01Mb/s 方式2375Kb/s 1 1 187.5Kb/s 0 方式1或方式362.5K

54、b/s 1 20 FF H 19.2Kb/s 1 20 FDH9.6Kb/s 0 20 FDH4.8Kb/s 1 20 F3H 0 20 FAH2.4Kb/s1 20 F3H 0 20 F3H 0 20 F4H1.2Kb/s1 20 E6H 0 20 E6H 0 20 E8H600Kb/s1 20 CCH 0 20 CCH300Kb/s0 20 CCH137.5Kb/s1 20 1DH110b/s0 20 72H例:請利用單片機串行口發送/接收程序,每接收到字節即刻發送出去,并利用串口調試助手將字符回顯在屏幕上。 /* Title 串口接收發送程序字母*/#include #define uc

55、har unsigned charvoid main()uchar a;TMOD=0 x20; / 定時器1的工作方式為1,即自動重設初值的8位定時/計數器 TL1=0 xfd; / 采用11.0592MHz的晶振,波特率9600bpsTH1=0 xfd; SCON=0 xd8 ; /串行口的工作方式3PCON=0 x00; TR1=1 ; /啟動定時器T1while(1) while(RI=0) ; /串口接收RI=0; a=SBUF;SBUF=a;while(TI=0);TI=0;將該程序編譯后寫入單片機,并連好串口線。通過串口調試助手向單片機發送字符,那么發送的內容被原樣發送回來。10.

56、7.3 LCD接口編程SMG12864A可以看成是兩個64*64的屏幕,每個屏通過CS1,CS2兩個片選信號來控制低電平有效,對于每一片左邊和右邊,分成8行*64列,每一行的高度為8位,從上到下對應的是DB的低位到高位。每寫一個數據,光標自動向后移動,到行末的時候返回到下一行行首。具體信號如下:返回CS1,CS2:屏幕控制片選信號,低電平有效;RST:復位信號,低電平有效;DB0-DB7:雙向并行指令/數據信號;E:使能信號,高電平有效;R/W:讀寫控制信號,低電平為寫入,高電平為讀出;RS:數據命令控制信號,低電平為指令,高電平為數據;例:要求在LCD上交替實現“測試開始和“測試完畢字樣,試

57、編寫程序。#include #define Disp_On 0 x3f/開顯示指令碼#define Disp_Off 0 x3e/關顯示指令碼#define Col_Add 0 x40/列指針指令碼#define Page_Add 0 xb8/頁指針指令碼#define Start_Line 0 xc0/初始行指令碼#define Lcd_Bus P1 sbit Mcs=P31;sbit Scs=P32; sbit Enable=P34; sbit RS=P30; sbit RW=P33;char code ce= /*- 文字: 測 -*/*- 宋體12; 此字體下對應的點陣為:寬x高=16

58、x16 -*/0 x08,0 x31,0 x86,0 x60,0 x00,0 xFE,0 x02,0 xF2,0 x02,0 xFE,0 x00,0 xF8,0 x00,0 x00,0 xFF,0 x00,0 x04,0 xFC,0 x03,0 x00,0 x80,0 x47,0 x30,0 x0F,0 x10,0 x67,0 x00,0 x07,0 x40,0 x80,0 x7F,0 x00;char code shi= /*- 文字: 試 -*/0 x40,0 x42,0 xDC,0 x08,0 x00,0 x90,0 x90,0 x90,0 x90,0 x90,0 xFF,0 x10,0

59、 x12,0 x1C,0 x10,0 x00,0 x00,0 x00,0 x7F,0 x20,0 x10,0 x20,0 x20,0 x1F,0 x10,0 x10,0 x01,0 x06,0 x18,0 x20,0 x78,0 x00;char code kai= /*- 文字: 開 -*/0 x40,0 x42,0 x42,0 x42,0 x42,0 xFE,0 x42,0 x42,0 x42,0 x42,0 xFE,0 x42,0 x42,0 x42,0 x42,0 x00,0 x00,0 x40,0 x20,0 x10,0 x0C,0 x03,0 x00,0 x00,0 x00,0 x

60、00,0 x7F,0 x00,0 x00,0 x00,0 x00,0 x00;char code shi3= /*- 文字: 始 -*/0 x10,0 x90,0 x70,0 x1F,0 x12,0 xF0,0 x00,0 x20,0 x70,0 x28,0 x27,0 x22,0 x28,0 x70,0 x20,0 x00,0 x40,0 x21,0 x12,0 x0C,0 x06,0 x09,0 x30,0 x00,0 x7F,0 x21,0 x21,0 x21,0 x21,0 x7F,0 x00,0 x00;char code wan= /*- 文字: 完 -*/0 x00,0 x90,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論