




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、單片機C語言及程序設計,1.1 C51概述 1.2 C51數(shù)據(jù)類型及存儲 1.3 C51變量的定義及數(shù)據(jù)存儲區(qū)域 1.4 C51位變量的定義 1.5 C51特殊功能寄存器的定義,1.6 C51指令的定義 1.7 C51的輸入/輸出 1.8 C51函數(shù)的定義 1.9 C51與匯編語言混合編程 1.10 C51集成開發(fā)軟件Keil C,目 錄,本章主要討論C51變量的定義和函數(shù)的定義,以及Keil C軟件的使用等。 本章內容的安排,認為讀者已經(jīng)學習過C語言,具有C語言的基本知識,因此,本章內容完全是結合單片機來講解,也就是補充C語言在單片機方面的概念、數(shù)據(jù)定義和函數(shù)定義等。 通過本章學習,使讀者能
2、夠比較順利地編寫C51程序。,1.1 C51概述,主要內容 1.1.1 C語言編程的優(yōu)勢 1.1.2 C51與ANSI C的區(qū)別 1.1.3 C51擴展的關鍵字,1.1 C51概述,學習單片機C語言的必要性 隨著單片機性能的不斷提高,C語言編譯調試工具的不斷完善,以及現(xiàn)在對單片機產品輔助功能的要求、對開發(fā)周期不斷縮短的要求,使得越來越多的單片機編程人員轉向使用C語言,因此有必要在單片機課程中講授“單片機C語言”。 “C51”概念:為了與ANSI C區(qū)別,把“單片機C語言”稱為“C51”,也稱為“Keil C”。,1.1.1 C語言編程的優(yōu)勢,在編程方面,使用C51較匯編語言有諸多優(yōu)勢: 1)編
3、程容易 2)容易實現(xiàn)復雜的數(shù)值計算 3)容易閱讀與交流 4)容易調試與維護程序 5)容易實現(xiàn)模塊化開發(fā) 6)程序可移植性好,1.1.2 C語言與ANSI 的區(qū)別,用匯編語言編寫單片機程序時,必須要考慮其存儲器的結構,尤其要考慮其片內數(shù)據(jù)存儲器、特殊功能寄存器是否正確合理的使用,以及按照實際地址端口數(shù)據(jù)的處理。 用C51編寫程序,雖然不像匯編語言那樣需要具體地組織、分配存儲器資源,但是C51對數(shù)據(jù)類型和變量的定義,必須要與單片機的存儲結構相關聯(lián),否則編譯器不能正確地映射定位。,用C51編寫單片機程序,與用ANSI C編寫程序的不同之處是,需要根據(jù)單片機存儲器結構及內部資源,定義相應的數(shù)據(jù)類型和變
4、量。 其它的語法規(guī)定、程序結構及程序設計方法,都與ANSI C相同。所以本章主要介紹C51各種變量的定義、指針定義、函數(shù)定義和混合編程。,1.1.3 C51擴展的關鍵字,由于單片機在結構及編程上的特殊要求,C51有自己的特殊關鍵字,稱之為C51擴展的關鍵字,下面給出常用的C51擴展的關鍵字。 _at_bdatabit code dataidata interruptpdata reentrant sbitsfr sfr16usingvolatilexdata 這些關鍵字在后面會陸續(xù)接觸到,此處先不給出它們的含義。,1.2 C51數(shù)據(jù)類型及存儲,主要內容 1.2.1 C51的數(shù)據(jù)類型 1.2.2
5、 C51數(shù)據(jù)的存儲,數(shù)據(jù)類型轉換 1)自動轉換 轉換規(guī)則是向高精度數(shù)據(jù)類型轉換、向有符號數(shù)據(jù)類型轉換。如字符型變量與整型變量相加時,則位變量先轉換字符型或整型數(shù)據(jù),然后相加。 2)強制轉換 像ANSI C一樣,通過強制類型轉換的方式進行轉換。如: unsignedintb; floatc;b=(int)c;,1.2.2 C51數(shù)據(jù)的存儲,MCS-51單片機只有bit和unsigned char兩種數(shù)據(jù)類型支持機器指令,而其它類型的數(shù)據(jù)都需要轉換成bit或unsigned char型進行存儲。 為了減少單片機的存儲空間和提高運行速度,要盡可能地使用unsigned char型數(shù)據(jù)。 一、位變量的
6、存儲 bit和sbit型位變量,直接存于RAM的位尋址空間,包括低128位和特殊功能寄存器位。,二、字符變量的存儲 字符變量(char):無論是unsigned char數(shù)據(jù)還是signed char數(shù)據(jù),均為1個字節(jié),能夠被直接存儲在RAM中,可以存儲在00 x7f區(qū)域,也可以存儲在0 x800 xff區(qū)域,與變量的定義有關。 unsigned char數(shù):可直接被MSC-51接受 signed char數(shù)據(jù):用補碼表示。需要額外的操作來測試、處理符號位,使用的是兩種庫函數(shù),代碼量大,運算速度降低。,三、整型變量的存儲 整型變量(int):不管是unsigned int數(shù)據(jù)還是signed
7、int數(shù)據(jù),均為2個字節(jié),其存儲方法是高位字節(jié)保存在低地址(在前面),低位字節(jié)保存在高地址(在后面) 。,例如,整型變量的值為0 x1234,在內存中的存放如右圖所示。 signed int數(shù)據(jù)用補碼表示。,地址 低 高,四、長整型變量的存儲 長整型變量(long)為4個字節(jié),其存儲方法與整型數(shù)據(jù)一樣,是最高位字節(jié)保存的地址最低(在最前面),最低位字節(jié)保存的地址最高(在最后面)。,如長整型變量的值為0 x12345678,在內存中的存放方法如右圖所示。不管是unsigned long數(shù)據(jù)還是signed long數(shù)據(jù)。,地址 低 高,五、浮點型變量的存儲 浮點型變量(fload)占4個字節(jié),用
8、指數(shù)方式表示,其具體格式與編譯器有關。 對于Keil C,采用的是IEEE-754標準,具有24位精度,尾數(shù)的最高位始終為1,因而不保存。具體分布為:1位符號位,8位階碼位,23位尾數(shù),如下圖所示。,符號位S:1表示負數(shù),0表示正數(shù)。 階碼:用移碼表示。如,實際階碼-126用1表示,實際階碼0用127表示,即實際階碼數(shù)加上127得到階碼的表達數(shù)。 階碼數(shù)值范圍:-126+128。,例如浮點數(shù)-12.5 符號位為1, 12.5的二進制數(shù)為1100.1=1.1001E+0011, 階碼數(shù)值為3+127=130=10000010B, 尾數(shù)為1001。 因此,其十六進制數(shù)為0 xC1480000,則存
9、儲結構如右圖所示。,地址 低 高,說明:教材中存儲結構是錯的。,1.3 C51變量的定義及數(shù)據(jù)存儲區(qū)域,主要內容 1.3.1 C51變量的定義 1.3.2 C51變量的存儲類型 1.3.3 C51變量的存儲區(qū)域 1.3.4 C51變量定義舉例 1.3.5 C51變量的存儲模式 1.3.6 C51變量的絕對定位,1.3.1 C51變量的定義,C51變量定義的一般格式為: 存儲類型數(shù)據(jù)類型 存儲區(qū) 變量名1=初值 ,變量名2=初值 , 或存儲類型存儲區(qū) 數(shù)據(jù)類型 變量名1=初值 ,變量名2=初值 , 可見變量(非位變量)的定義由4部分組成,即在變量定義時,指定變量4種屬性。 數(shù)據(jù)類型:在前面的4.
10、2中已經(jīng)敘述過,對于變量名也無須多說,下面主要解釋“存儲類型”和“存儲區(qū)”等概念。,1.3.2 C51變量的存儲類型,存儲類型這個屬性我們仍沿用ANSI C的說法,盡量不改變原來的含義。 按照ANSI C,C語言的變量有4種存儲類型: 動態(tài)存儲(auto) 靜態(tài)存儲(static) 全局存儲(extern) 寄存器存儲(register),一、動態(tài)存儲 動態(tài)(存儲)變量:用auto定義的為動態(tài)變量,也叫自動變量。 作用范圍:在定義它的函數(shù)內或復合語句內部。當定義它的函數(shù)或復合語句執(zhí)行時,C51才為變量分配存儲空間,結束時所占用的存儲空間釋放。 定義變量時,auto可以省略,或者說如果省略了存儲
11、類型項,則認為是動態(tài)變量。動態(tài)變量一般分配使用寄存器或堆棧。,二、靜態(tài)存儲 靜態(tài)(存儲)變量:用static定義的為靜態(tài)變量。分為內部靜態(tài)和外部靜態(tài)變量。 內部靜態(tài)變量:在函數(shù)體內定義的為內部靜態(tài)變量。在函數(shù)內可以任意使用和修改,函數(shù)運行結束后會一直存在,但在函數(shù)外不可見,即在函數(shù)體外得到保護。 外部靜態(tài)變量:在函數(shù)體外部定義的為外部靜態(tài)變量。在定義的文件內可以任意使用和修改,外部靜態(tài)變量會一直存在,但在文件外不可見,即在文件外得到保護。,三、外部存儲 外部(存儲)變量:用extern聲明的變量為外部變量,是在其它文件定義過的全局變量。用extern聲明后,便可以在所聲明的文件中使用。 需要注
12、意的是:在定義變量時,即便是全局變量,也不能使用extern定義。,四、寄存器存儲 寄存器(存儲)變量:用register定義的變量為寄存器變量。 寄存器變量存放在CPU的寄存器中,這種變量處理速度快,但數(shù)目少。 C51中的寄存器變量: C51的編譯器在編譯時,能夠自動識別程序中使用頻率高的變量,并將其安排為寄存器變量,用戶不用專門聲明。,1.3.3 C51變量的存儲區(qū)域,變量的存儲區(qū)屬性是單片機擴展的概念,非常重要,它涉及到7個新的關鍵字。 MCS-51單片機有四個存儲空間,分成三類,它們是片內數(shù)據(jù)存儲空間、片外數(shù)據(jù)存儲空間和程序存儲空間。 MCS-51單片機有更多的存儲區(qū)域:由于片內數(shù)據(jù)存
13、儲器和片外數(shù)據(jù)存儲器又分成不同的區(qū)域,所以單片機的變量有更多的存儲區(qū)域。在定義變量時,必須明確指出是存放在哪個區(qū)域。,1.3.4 C51變量定義舉例,1)定義存儲在data區(qū)域的動態(tài)unsigned char變量: unsigned char data sec=0, min=0, hou=0; 2)定義存儲在data區(qū)域的靜態(tài)unsigned char變量: static unsigned char data scan_code=0 xfe; 3)定義存儲在data區(qū)域的靜態(tài)unsigned int變量: static unsigned int data dd;,4)定義存儲在bdata區(qū)域的
14、動態(tài)unsigned char變量: unsigned char bdata operate, operate1; /定義指示操作的可位尋址的變量 5)定義存儲在idata區(qū)域的動態(tài)unsigned char數(shù)組: unsigned char idata temp20; 6)定義在pdata區(qū)域的動態(tài)有符號int數(shù)組: int pdata send_data30; /定義存放發(fā)送數(shù)據(jù)的數(shù)組,7)定義存儲在xdata區(qū)域的動態(tài)unsigned int數(shù)組: unsigned int xdata receiv_buf50; /定義存放接受數(shù)據(jù)的數(shù)組 8)定義存儲在code區(qū)域的unsigned c
15、har數(shù)組: unsigned char code dis_code10= 0 x3f, 0 x06, 0 x5b, 0 x4f, 0 x66, 0 x6d,0 x7d,0 x07,0 x7f,0 x6f; /定義共陰極數(shù)碼管段碼數(shù)組,1.3.5 C51變量的存儲模式,存儲模式:如果在定義變量時缺省了存儲區(qū)屬性,則編譯器會自動選擇默認的存儲區(qū)域,也就是存儲模式。 變量的存儲模式也就是程序(或函數(shù))的編譯模式。 編譯模式分為三種:小模式(small)、緊湊模式(compact)和大模式(large)。編譯模式由編譯控制命令決定。 存儲模式(編譯模式)決定了變量的默認存儲區(qū)域和參數(shù)的傳遞方法。,一
16、、small模式 在small模式下,變量的默認存儲區(qū)域是“data”、“idata”,即未指出存儲區(qū)域的變量保存到片內數(shù)據(jù)存儲器中,并且堆棧也安排在該區(qū)域中。 small模式的特點:存儲容量小,但速度快。 在small模式下參數(shù)的傳遞:通過寄存器、堆?;蚱瑑葦?shù)據(jù)存儲區(qū)完成的。,二、compact模式 在compact模式下,變量的默認存儲區(qū)域是“pdata”,即未指出存儲區(qū)域的變量保存到片外數(shù)據(jù)存儲器的一頁中,最大變量數(shù)為256字節(jié),并且堆棧也安排在該區(qū)域中。 compact模式的其特點:是存儲容量較small模式大,速度較small模式稍慢,但比large模式要快。 在compact模式下
17、參數(shù)的傳遞:通過片外數(shù)據(jù)區(qū)的一個固定頁完成的。,三、large模式 在large模式下,變量的默認存儲區(qū)域是“xdata”,即未指出存儲區(qū)域的變量保存到片外數(shù)據(jù)存儲器,最大變量數(shù)可達64KB,并且堆棧也安排在該區(qū)域中。 large模式的特點:存儲容量大,速度慢 large模式下參數(shù)的傳遞方式:參數(shù)的傳遞也是通過片外數(shù)據(jù)存儲器完成的。,C51支持混合模式:即可以對函數(shù)設置編譯模式,所以在large模式下,可以對某些函數(shù)設置為compact模式或small模式,從而提高運行速度。 默認編譯模式:如果文件或函數(shù)未指明編譯模式,則編譯器按small模式處理。 編譯模式控制命令: “#pragma sm
18、all(或compact、large)”應放在文件的開始。,1.3.6 C51變量的絕對定位,C51有三種方式可以對變量(I/O端口)絕對定位:絕對定位關鍵字_at_ 、指針、庫函數(shù)的絕對定位宏。對于后兩種方式,在后面指針一節(jié)介紹。 C51擴展的關鍵字_at_專門用于對變量作絕對定位,_at_使用在變量的定義中,其格式為: 存儲類型 數(shù)據(jù)類型 存儲區(qū) 變量名1 _at_ 地址常數(shù),變量名2,舉例說明_at_的使用方法 1)對data區(qū)域中的 unsigned char變量aa作絕對定位: unsignedchardata aa _at_ 0 x30; 2)對pdata區(qū)域中的 unsigned
19、 int數(shù)組cc作絕對定位: unsignedint pdata cc10 _at_ 0 x34; 3)對xdata區(qū)域中的 unsigned char變量printer_port作絕對定位: unsignedcharxdata printer_port _at_ 0 x7fff;,對變量絕對定位的幾點說明: 1)絕對地址變量在定義時不能初始化,因此不能對code型變量絕對定位; 2)絕對地址變量只能夠是全局變量,不能在函數(shù)中對變量絕對定位; 3)絕對地址變量多用于I/O端口,一般情況下不對變量作絕對定位; 3)位變量不能使用_at_絕對定位。,1.4 C51位變量的定義,主要內容 1.4.1
20、 bit型位變量的定義 1.4.2 sbit型位變量的定義,1.4.1 bit型位變量的定義,常說的位變量指的就是bit型位變量。C51的bit型位變量定義的一般格式為: 存儲類型 bit 位變量名1=初值 ,位變量名2=初值 , bit位變量被保存在RAM中的位尋址區(qū)域(字節(jié)地址為0 x200 x2f,16字節(jié))。 例如: bitflag_run,receiv_bit=0; static bitsend_bit;,兩點說明: 1)bit型位變量與其它變量一樣,可以作為函數(shù)的形參,也可以作為函數(shù)的返回值,即函數(shù)的類型可以是位型的; 2)位變量不能定義指針,不能定義數(shù)組。,1.4.2 sbit型
21、位變量的定義,對于能夠按位尋址的特殊功能寄存器、定義在位尋址區(qū)域的變量(字節(jié)型、整型、長整型),可以對其各位用sbit定義位變量。 為了方便起見,分開討論按位尋址的特殊功能寄存器中位變量的定義、按位尋址的變量中位變量的定義。,一、特殊功能寄存器中位變量定義 能夠按位尋址的特殊功能寄存器中位變量定義的一般格式為: sbit位變量名 位地址表達式 這里的位地址表達式有三種形式: 直接位地址 特殊功能寄存器名帶位號 字節(jié)地址帶位號,1、用直接位地址定義位變量 這種情況下位變量的定義格式為: sbit位變量名 位地址常數(shù) 這里的位地址常數(shù)范圍為0 x800 xff,實際是定義特殊功能寄存器的位。例如:
22、 sbitP0_0=0 x80; sbitP1_1=0 x91; sbitRS0=0 xd3; /定義PSW的第3位 sbitET0=0 xa9; /定義IE的第1位,2、特殊功能寄存器名帶位號定義 這時位變量的定義格式為: sbit位變量名 特殊功能寄存器名 位號常數(shù) 這里的位號常數(shù)為07。例如: sbitP0_3=P03; sbitP1_4=P14; sbitOV=PSW2; /定義PSW的第2位 sbitES=IE4; /定義IE的第4位,3、寄存器地址帶位號定義位變量 在這種情況下位變量的定義格式為: sbit位變量名 特殊功能寄存器地址 位號常數(shù) 這里的位號常數(shù)同上,為07。例如:
23、sbitP0_6=0 x806; sbitP1_7=0 x907; sbitAC=0 xd06; /定義PSW的第6位 sbitEA=0 xa87;/定義IE的第7位,4、幾點說明 1)用sbit定義的位變量,必須能夠按位操作,而不能夠對無位操作功能的位定義位變量。 2)用sbit定義位變量,必須放在函數(shù)外面作為全局位變量,而不能在函數(shù)內部定義。 3)用sbit每次只能定義一個位變量。 4)對其它模塊定義的位變量(bit型或 sbit型)的引用聲明,都使用bit。 5)用sbit定義的是一種絕對定位的位變量(因為名字是與確定位地址對應的),具有特定的意義,在應用時不能像bit型位變量那樣隨便使
24、用。,二、位尋址區(qū)變量的位定義 對bdata型變量(字節(jié)型、整型、長整型) ,被保存在RAM中的位尋址區(qū),因此可以對bdata型變量各位作位變量定義。 這樣,既可以對bdata型變量作字節(jié)(或整型、長整型)操作,也可以作位操作。 bdata型變量的位定義格式: sbit 位變量名 bdata型變量名位號常數(shù),bdata型變量為在此之前應該是定義過的,位號常數(shù)可以是07(8位字節(jié)變量),或015(16位整型變量),或031(32位字長整型變量)。例如: unsignedchar bdataoperate; 對operate的低4位作位變量定義: sbit flag_key=operate0; /
25、鍵盤標志位 sbit flag_dis=operate1; /顯示標志位 sbit flag_mus=operate2; /音樂標志位 sbit flag_run=operate3; /運行標志位,1.5 C51特殊功能寄存器的定義,主要內容 1.5.1 8位特殊功能寄存器的定義 1.5.2 16位特殊功能寄存器的定義,1.5.1 8位特殊功能寄存器的定義,定義的一般格式為: sfr特殊功能寄存器名 地址常數(shù) 地址常數(shù)范圍:0 x800 xff。 特殊功能寄存器定義例子(見reg51.h、reg52.h等文件): sfrP0=0 x80;/定義P0寄存器 sfrP1=0 x90;/定義P1口寄
26、存器 sfrPSW=0 xd0;/定義PSW sfrIE=0 xa8;/定義IE,1.5.2 16位特殊功能寄存器的定義,定義的一般格式為: sfr16 特殊功能寄存器名 地址常數(shù) 地址常數(shù)范圍:0 x800 xff。 例如(見reg51.h、reg52.h等文件): sfr16 DPTR=0 x82; sfr16 T2=0 xcc; /含TL2和TH2 sfr16 RCAP2=0 xca; /含RCAP2L/和RCAP2H, 0 xca為RCAP2L的地址,幾點說明: 1)定義特殊功能寄存器中的地址必須在0 x800 xff范圍內。 2)定義特殊功能寄存器,必須放在函數(shù)外面作為全局變量。 3
27、)用sfr或sfr16每次只能定義一個特殊功能寄存器。 4)像sbit一樣,用sfr或sfr16定義的是絕對定位的變量(因為名字是與確定地址對應的),具有特定的意義,在應用時不能像一般變量那樣隨便使用。,1.6 C51指針的定義,主要內容 1.6.1 通用指針 1.6.2 存儲器專用指針 1.6.3 指針變換 1.6.4 C51指針應用,1.6 C51指針的定義,由于MCS-51單片機有三種不同類型的存儲空間,并且還有不同的存儲區(qū)域,因此C51指針的內容更豐富。 指針除了具有像變量的四種屬性(存儲類型、數(shù)據(jù)類型、存儲區(qū)、變量名)外,按存儲區(qū),將指針分為通用指針和不同存儲區(qū)域的專用指針。,1.6
28、.1 通用指針,所謂通用指針,就是通過該類指針可以訪問所有的存儲空間。 在C51庫函數(shù)中通常使用這種指針來訪問。 通用指針用3個字節(jié)來表示: 第一個字節(jié):表示指針所指向的存儲空間 第二個字節(jié):為指針地址的高字節(jié) 第三個字節(jié):為指針地址的低字節(jié),通用指針的定義與一般C語言指針的定義相同,其格式為: 存儲類型 數(shù)據(jù)類型 *指針名1 ,*指針名2 , 例如: unsigned char *cpt; int *dpt; long *lpt; static char *ccpt;,通用指針的特點: 定義簡單 訪問所有空間 訪問速度慢,1.6.2 存儲器專用指針,所謂存儲器專用指針,就是通過該類指針,只能
29、夠訪問規(guī)定的存儲空間區(qū)域。 指針本身占用1個字節(jié)(data *,idata *,bdata *,pdata *)或2個字節(jié)(xdata *,code *)。 存儲器專用指針的一般定義格式為: 存儲類型 數(shù)據(jù)類型 指向存儲區(qū) *指針存儲區(qū) 指針名1 ,*指針存儲區(qū) 指針名2,指向存儲區(qū): 是指針變量所指向的數(shù)據(jù)存儲空間區(qū)域。不能夠缺省。 指針存儲區(qū): 是指針變量本身所存儲的空間區(qū)域。 缺省時認為指針存儲區(qū)在默認的存儲區(qū)域,其默認存儲區(qū)域決定于所設定的編譯模式。 指向和指針存儲區(qū),兩者可以是同一個區(qū)域,但多數(shù)情況下不會是同一個區(qū)域。,存儲器專用指針例子: unsigned char data *c
30、pt1, *cpt2; signed int idata *dpt1, *dpt2; unsigned char pdata *ppt; signed long xdata *lpt1, *lpt2; unsigned char code *ccpt; 上面所定義的指針雖然所指向的空間不同,但指針變量本身都存儲在默認的存儲區(qū)域。,又如: 1)unsigned char data *idata cpt1,*idata cpt2; 2)signed int idata *data dpt1, *data dpt2; 3)unsigned char pdata *xdata ppt; 4)signe
31、d long xdata *lpt1, *xdata lpt2; 5)unsigned char code *data ccpt; 綠色關鍵字為指針所指向的存儲區(qū) 藍色關鍵字為指針本身所存儲的區(qū)域,注意:(1)要區(qū)分指針變量指向的空間區(qū)域和指針變量本身所存儲的區(qū)域;(2)定義時,前者不能缺省,而后者可以缺省;(3)指針變量的長度:指向不同的區(qū)域,占用的字節(jié)數(shù)不同。 說明:指針變量本身所存儲的區(qū)域,在定義指針時一般都省略了,指針變量本身保存在缺省存儲的區(qū)域中。 定義時,缺省指針存儲的區(qū)域,顯得簡單,并且對初學者更容易理解。,1.6.3 指針變換,一、通用指針格式 由前面的討論知,通用指針由3個字
32、節(jié)組成,第一個字節(jié)為數(shù)據(jù)的存儲區(qū)域,后兩個字節(jié)為指針地址,第一個字節(jié)的存儲區(qū)域編碼如表4-6所示。,一、指針轉換 指針轉換有兩種途徑,一種是顯式的編程轉換,另一種是隱式的自動轉換。 指針的編程轉換:(1)通用指針的第一字節(jié),與專用指針的指向數(shù)據(jù)區(qū)屬性,二者相互轉換;(2)通用指針后兩個字節(jié)的地址,與專用指針值的轉換。 指針的隱式自動轉換:由編譯器在進行編譯時自動完成。,1.6.4 C51指針應用,指針在PC機上的C語言中應用很廣泛。 在單片機中,由于不使用操作系統(tǒng),指針的應用可以獨立于變量,獨立地指向所需要訪問的存儲空間位置。 本節(jié)通過例子來學習和認識C51指針的這種獨立應用性。 下面介紹兩種
33、利用指針訪問存儲區(qū)的方法。也可以訪問函數(shù)。,二、通過指針定義的宏訪問存儲器 1、訪問存儲器宏的定義 用指針定義的、訪問存儲器宏的格式: #define 宏名 (數(shù)據(jù)類型 volatile 存儲區(qū)*)0) 格式中的數(shù)據(jù)類型主要為無符號的字符型數(shù)、整型;格式中的存儲區(qū)域主要使用data、idata、pdata、xdata和code類型,不使用bdata存儲區(qū)類型。,格式中的關鍵字“volatile”: “volatile”是單片機中定義的,其含義為:這種變量在程序執(zhí)行中可被隱含地改變而編譯器無法檢測到,告知編譯器不要做優(yōu)化處理,使應用者能夠得到正確的變量值。 volatile的應用:volatil
34、e常用于定義寄存器,特別是狀態(tài)寄存器,因為狀態(tài)寄存器的值不是程序員設置,而是單片機在運行中CPU設置的。 特別說明:“volatile”的含義與教材上表述不太一致,此處表述直觀更容易理解。,2、庫函數(shù)中訪問存儲器宏的原型 C51編譯器提供了兩組用指針定義的絕對存儲器訪問的宏,其原型如下。 1)按字節(jié)訪問存儲器的宏: #define CBYTE (unsigned char volatile code*)0) #define DBYTE (unsigned char volatile data*)0) #define PBYTE(unsigned char volatile pdata*)0)
35、#define XBYTE (unsigned char volatile xdata*)0),2)按整型雙字節(jié)訪問存儲器的宏: #define CWORD (unsigned int volatile code*)0) #define DWORD (unsigned int volatile data*)0) #define PWORD (unsigned int volatile pdata*)0) #define XWORD (unsigned int volatile xdata*)0) 無idata型,不能訪問片內RAM高128字節(jié)區(qū)域(0 x800 xff),需要時可以自己定義。
36、這些宏定義原型放在absacc.h文件中,使用時需要用預處理命令把該頭文件包含到文件中,形式為:#include 。,3、絕對訪問存儲器宏的應用 使用宏定義訪問存儲器的形式類似于數(shù)組。 1)按字節(jié)訪問存儲器宏的形式 宏名地址 即數(shù)組中的下標就是存儲器的地址,因此使用起來非常方便。例如: DBYTE0 x30=48;/給片內RAM送數(shù)據(jù) XBYTE0 x0002=0 x36;/給片外RAM送數(shù)據(jù) dis_buf0=CBYTETABLE+5; /從CODE區(qū)讀取數(shù)據(jù),2)按整型數(shù)訪問存儲器宏的形式 宏名下標 由于整型數(shù)占兩個字節(jié),所以下標與地址的關系為:地址=下標2。 由于數(shù)組中的下標與存儲器的地
37、址是倍數(shù)關系,使用時要注意。例如: DWORD0 x20=0 x1234; /給0 x40、0 x41送數(shù) XWORD0 x0002=0 x5678;/給4、5單元送數(shù) 通過指針定義的宏訪問存儲器這種方法,特別適用于訪問I/O口。,一、通過專用指針直接訪問存儲器 使用指針直接訪問存儲器對PC機是禁止的,但對于單片機來說使用時注意是可以的。 使用指針直接訪問存儲器方法是先定義所需要的指針,給指針賦地址值,然后使用指針訪問存儲器。例如: unsigned char xdata *xcpt; xcpt=0 x2000; *xcpt=123; /給0 x2000送數(shù) xcpt+;*xcpt=234;
38、/給0 x2001送數(shù),例1-1 編寫程序,將單片機片外數(shù)據(jù)存儲器中地址從0 x1000開始20個字節(jié)數(shù)據(jù),傳送到片內數(shù)據(jù)存儲器地址從0 x30開始的區(qū)域。 程序段如下: unsigned char data i, *dcpt; unsigned char xdata*xcpt; dcpt=0 x30;/給指針賦地址 xcpt=0 x1000; for(i=0;i20;i+) *(dcpt+i)=*(xcpt+i);,dcpt和xcpt兩個指針 變量存儲在什么地方?,例4-2 在數(shù)字濾波中有一種叫做“中值濾波”技術,就是對采集的數(shù)據(jù)按照從大到小或者從小到大進行排序,然后取中間位置的數(shù)作為采樣值
39、。試編寫一函數(shù),對存放在片內數(shù)據(jù)存儲器中,從0 x50開始的21個單元的采樣數(shù)據(jù),用冒泡法排序進行中值濾波,并把得到的中值數(shù)據(jù)返回。 中值濾波函數(shù)如下: unsigned char median_filter() unsigned char data *point,i,j,n,d;,for(i=0;i20;i+)/外層循環(huán)20次 point = 0 x50;/point指向0 x50處 n=20i;/n為內層循環(huán)次數(shù) for(j=0;jn;j+)/內層循環(huán) if(*point*(point+1)/從大到小排 d=*point; *point=*(point+1); *(point+1)=d;
40、point+;/指針指向下一個數(shù) point=0 x50+10;/指向位于中間的數(shù) return *point;/返回得到的中值 ,1.7 C51的輸入/輸出,主要內容 1.7.1 基本輸入/輸出函數(shù) 1.7.2 格式輸出函數(shù)printf 1.7.3 格式輸入函數(shù)scanf,C51的輸入和輸出函數(shù)的形式雖然與ANSI C的一樣,但實際意義和使用方法都大不一樣,因此,有必要專門介紹一下C51的輸入/輸出函數(shù)。 在C51的I/O函數(shù)庫中定義的I/O函數(shù),都是以_getkey和putchar函數(shù)為基礎。 這些I/O函數(shù)包括:字符輸入/輸出函數(shù)getchar和putchar,字符串輸入/輸出函數(shù)get
41、s和puts,格式輸入/輸出函數(shù)printf和scanf等。,C51的輸入/輸出函數(shù),都是通過單片機的串行接口實現(xiàn)的。 在使用這些I/O函數(shù)之前,必須先對單片機的串行口、定時器/計數(shù)器T1進行初始化。假設單片機的晶振為11.0592MHz,波特率為9600bps,則初始化程序段為: SCON=0 x52;/設置串口方式1收、發(fā) TMOD=0 x20;/設置T1以模式2工作 TL1=0 xfd;/設置T1低8位初值 TH1=0 xfd;/設置T1自動重裝初值 TR1=1;/開T1,1.7.1 基本輸入/輸出函數(shù),1、基本輸入函數(shù)getkey getkey函數(shù)是基本的字符輸入函數(shù),原型為 char
42、 _getkey(void) 函數(shù)功能:從單片機串行口讀入一個字符,如果沒有字符輸入則等待,返回值為讀入的字符,不顯示??芍厝牒瘮?shù)。 字符輸入函數(shù)getchar() 功能:與getkey基本相同, 唯一的區(qū)別:還要從串行口返回字符。,2基本輸出函數(shù)putchar putchar函數(shù)是基本的字符輸出函數(shù),其原型為: char putchar(char) 函數(shù)功能:是從單片機的串行口輸出一個字符,返回值為輸出的字符。 putchar為可重入函數(shù)。,1.7.2 格式輸出函數(shù)printf,函數(shù)功能:通過單片機的串行口輸出若干任意類型的數(shù)據(jù)。格式如下: printf(格式控制,輸出參數(shù)表) 格式控制 是
43、用雙引號括起來的字符串,也稱為轉換控制字符串,它包括三種信息: 格式說明符 普通字符 轉義字符。,1)格式說明符:由百分號“%”和格式字符組成,其作用是指明輸出數(shù)據(jù)的格式,如%d、%c、%s等,詳細情況見表4-3。 2)普通字符:這些字符按原樣輸出,主要用來輸出一些提示信息。 3)轉義字符:由“”和字母或字符組成,它的作用是輸出特定的控制符,如轉義字符n的含義是輸出換行,詳細情況見表4-4。,用printf函數(shù)輸出例子(假設y已定義過,也賦值過): printf(“x=%d”,36) ;/從串行口輸出x=36 printf(“y=%d”,y) ;/從串行口輸出y=y的值 printf(“c1=
44、%c,c2=%c”,A,B) ; /從串行口輸出c1=A,c2=B printf(“%sn”,“OK,Send data begin!”) ; /從串行口輸出OK, Send data begin!和n,1.7.2 格式輸入函數(shù)scanf,scanf函數(shù)的功能:通過單片機串行口實現(xiàn)各種數(shù)據(jù)輸入。函數(shù)格式如下: scanf(格式控制,地址列表) 格式控制 格式控制與printf函數(shù)的類似,也是用雙引號括起來的一些字符,包括三種信息:格式說明符、普通字符和空白字符。 1)格式說明符:由百分號“%”和格式字符組成,其作用是指明輸入數(shù)據(jù)的格式,見表4-5。,2)普通字符:在輸入時,要求這些字符按原樣輸
45、入。 3)空白字符:包括空格、制表符和換行符等,這些字符在輸入時被忽略。 地址列表:是由若干個地址組成,它可以是指針變量、變量地址(取地址運算符“ /存放原始的時分秒 unsigned char data dis_buf6;/數(shù)碼管顯示 void main(void) unsigned char data t23;/放接收的時間 unsigned char data sec0=61;/秒備份 unsigned char data i;,SCON=0 x52;/串行口初始化 TMOD=0 x20; /設置定時器工作模式 TH1=0 xfd; /設置T1重裝的初值 TR1=1; /開T1運行 wh
46、ile(1) if(sec0!=t12)/判斷秒是否已經(jīng)改變 putchar(t1i); t2i+=_getkey();,if(i2) dis_buf0=t20/10; dis_buf1=t20%10; dis_buf2=t21/10; dis_buf3=t21%10; dis_buf4=t22/10; dis_buf5=t22%10; i=0; sec0=t12;/更新秒備份 display( ); /調用數(shù)碼管掃描顯示函數(shù) ,1.8 C51函數(shù)的定義,主要內容 1.8.1 C51函數(shù)的定義 1.8.2 C51中斷函數(shù)的定義,C51函數(shù)的定義與ANSI C相似,但有更多的屬性要求。本節(jié)先討論
47、函數(shù)的一般定義,然后專門給出中斷函數(shù)的定義,因為中斷函數(shù)有其特殊性。,1.8.1 C51函數(shù)的定義,在C51中,函數(shù)的定義與ANSI C中是相同的。唯一不同的就是在函數(shù)的后面需要帶上若干個C51的專用關鍵字。C51函數(shù)定義的一般格式如下: 返回類型 函數(shù)名(形參表) 函數(shù)模式 reentrant interrupt m using n 局部變量定義 執(zhí)行語句 ,各屬性含義如下: 函數(shù)模式:也就是編譯模式、存儲模式,可以為small、compact和large。缺省時則使用文件的編譯模式。 reentrant:表示重入函數(shù)。所謂可重入函數(shù),就是允許被遞歸調用的函數(shù)。是C51定義的關鍵字。,在編譯
48、時會為重入函數(shù)生成一個堆棧,通過這個堆棧來完成參數(shù)的傳遞和存放局部變量。 重入函數(shù)不能使用bit型參數(shù);函數(shù)返回值也不能是bit型。,interrupt m:中斷關鍵字和中斷號。 interrupt是C51定義的。C51支持32個中斷源 中斷入口地址與中斷號m的關系: 中斷入口地址38m。,using n:選擇工作寄存器組和組號, n可以為03,對應第0組到第3組。關鍵字using是C51定義的。 如果函數(shù)有返回值,不能使用該屬性,因為返回值是存于寄存器中,函數(shù)返回時要恢復原來的寄存器組,導致返回值錯誤。,1.8.2 C51中斷函數(shù)的定義,C51函數(shù)的定義實際上已經(jīng)包含了中斷服務函數(shù),但為了明
49、確起見,下面專門給出中斷處理函數(shù)的具體定義形式: void 函數(shù)名(void) 函數(shù)模式 interrupt m using n 局部變量定義 執(zhí)行語句 ,中斷服務函數(shù)需要注意以下幾點: 1)中斷服務函數(shù)不傳遞參數(shù); 2)中斷服務函數(shù)沒有返回值; 3)中斷服務函數(shù)必須有interrupt m屬性; 4)進入中斷服務函數(shù),ACC、B、PSW會進棧,根據(jù)需要,DPL、DPH也可能進棧,如果沒有using n屬性,R0R7也可能進棧,否則不進棧; 5)在中斷服務函數(shù)中調用其它函數(shù),被調函數(shù)最好設置為可重入的,因為中斷是隨機的,有可能中斷服務函數(shù)所調用的函數(shù)出現(xiàn)嵌套調用; 6)不能夠直接調用中斷服務函
50、數(shù)。,例1-4 編寫程序,使用定時器/計數(shù)器0定時并產生中斷,實現(xiàn)從P1.7產生方波的功能。 程序如下: #include #defineTIMER0L0 x18/設振蕩頻率為12MHz #defineTIMER0H0 xfc/定時1ms(1000微秒) void timer0_int(void) interrupt 1 TL0=TIMER0L; TH0=TIMER0H; P1_7=P1_7;/產生的方波頻率為500Hz ,voidmain(void) TMOD=0 x01;/設置T1模式1定時 TL0=TIMER0L;/設置T0低8位初值 TH0=TIMER0H;/設置T0高8位初值 IE=
51、0 x82;/開T0中斷和總中斷 TR0=1;/開T0運行 while(1);/等待中斷,產生方波 ,1.9 C51與匯編語言混合編程,主要內容 1.9.1 在C51程序中嵌入?yún)R編程序 1.9.2 C51程序與匯編程序混合編程,混合編程有兩種方式: 一種是在C語言函數(shù)中嵌入?yún)R編語言程序,程序中沒有獨立的匯編語言函數(shù),只有個別C語言函數(shù)中嵌入有匯編程序; 另一種是C語言文件與匯編語言文件混合編程,程序中有獨立的匯編程序函數(shù)和匯編語言文件。 無論是哪種混合編程方式,采用C51后,程序的大部分是C語言,只有少部分是匯編語言。,1.9.1 在C51程序中嵌入?yún)R編程序,其方法是用編譯控制指令“#prag
52、ma src”、“#pragma asm”和“#pragma endasm”實現(xiàn)。 “#pragma src”是控制編譯器將C源文件編譯成匯編文件,“#pragma src”要放在文件的開始; “#pragma asm”和“#pragma endasm”指示匯編語言程序的開始和結束,分別放在匯編程序段的前面和后面。,例1-5 編寫一從單片機P1口做循環(huán)右移輸出的流水燈子程序。 #pragma src/指示將C文件編譯成匯編文件 void round_lamp(void) static unsigned char lamp=0 x55; P1=lamp; # pragma asm/指示匯編語言程
53、序開始 MOVA,lamp/對變量lamp做循環(huán)右移 RRA MOVlamp,A # pragma endasm/指示匯編語言程序結束 ,1.9.2 C51程序與匯編程序混合編程,在這種情況下,C語言與匯編語言程序都是獨立的文件,它們的函數(shù)要相互調用,這就涉及到了匯編語言程序的參數(shù)傳遞和函數(shù)命名兩個問題。 下面先討論匯編語言函數(shù)的命名和參數(shù)傳遞問題,然后討論混合編程。,主要內容 一、C51函數(shù)的命名規(guī)則 二、C51函數(shù)段與數(shù)據(jù)段的格式 三、C51函數(shù)的參數(shù)傳遞規(guī)則 四、匯編語言文件及函數(shù)編寫方法 五、匯編語言文件編程舉例 六、在C語言中調用匯編語言的方法,一、C51函數(shù)的命名規(guī)則 從表4-8中
54、可以看出,C51函數(shù)的命名規(guī)則主要有: 函數(shù)名字符串 /不傳遞參數(shù)的函數(shù) _函數(shù)名字符串 /通過寄存器傳遞參數(shù) _?函數(shù)名字符串 /通過堆棧傳遞參數(shù)的可重入函數(shù) C51函數(shù)名還有其它的格式,如通過存儲器傳遞參數(shù)的函數(shù)等,在混合編程中基本不用,所以不再介紹。,二、C51函數(shù)段與數(shù)據(jù)段的格式 C51編譯后對每個函數(shù)都分配一個獨立的CODE段,并且匯編函數(shù)名字還要帶上模塊名,所以C51匯編語言函數(shù)段的格式為: ?PR?函數(shù)名字符串?模塊名 ?PR?_函數(shù)名字符串?模塊名 ?PR?_?函數(shù)名字符串?模塊名 如果函數(shù)中定義有局部變量,編譯時也給局部變量分配數(shù)據(jù)段,數(shù)據(jù)段的格式為: ?數(shù)據(jù)段前綴?函數(shù)名?
55、數(shù)據(jù)類型,三、C51函數(shù)的參數(shù)傳遞規(guī)則 分為調用時的參數(shù)傳遞和返回時參數(shù)的傳遞。 1、調用時參數(shù)的傳遞 分三種情況:少于等于3個參數(shù)時通過寄存器傳遞(寄存器不夠用時通過存儲區(qū)傳遞);多于3個時有一部分通過存儲區(qū)傳遞;對于重入函數(shù)參數(shù)通過堆棧傳遞。 通過寄存器傳遞速度最快。表4-10給出了第一種情況通過寄存器傳遞參數(shù)的規(guī)則。,2、函數(shù)返回值的傳遞 當函數(shù)有返回值時,通過寄存器傳遞。,四、匯編語言文件及函數(shù)編寫方法 匯編語言文件的構成主要有:定義模塊名、函數(shù)聲明、公共函數(shù)聲明、引用函數(shù)聲明、引用變量聲明、函數(shù)定義等部分。 1、定義模塊 對匯編語言文件定義模塊名,一般一個文件為一個模塊,也可以多個文
56、件為同一個模塊名。模塊定義格式如下: NAME 模塊名 定義模塊要放在文件的開始。 例如:NAME EXAMP,2、函數(shù)聲明 即對本模塊定義的函數(shù)作聲明,其格式為: ?PR?函數(shù)名?模塊名 SEGMENT CODE 格式中的函數(shù)名規(guī)則如上面一所述。 例如: ?PR?DISPLAY?EXAMP SEGMENT CODE ?PR?_RIGHT?EXAMP SEGMENT CODE ?PR?_?MUSIC?EXAMP SEGMENT CODE 說明:函數(shù)的聲明放在文件的前面,一般在模塊定義之后,并且緊接著模塊定義。,3、公共函數(shù)聲明 如果函數(shù)在其它文件(模塊)中調用,必須作公共函數(shù)聲明。聲明格式為:
57、 PUBLIC 函數(shù)名 例如: PUBLICDISPLAY PUBLIC_RIGHT_SHIFT PUBLIC_?MUSIC 聲明公共函數(shù)應放在函數(shù)聲明之后。,4、引用函數(shù)聲明 如果在匯編程序中引用了其它文件中的函數(shù),必須作引用聲明。聲明格式為: EXTRN CODE(函數(shù)名) 例如: EXTRNCODE(KEY) EXTRNCODE(_COUNT) 函數(shù)引用聲明中的“KEY” 函數(shù)不傳遞參數(shù);“_COUNT”函數(shù)通過寄存器傳遞參數(shù)。,5、引用變量聲明 如果在匯編程序中引用了其它文件中的變量,必須作引用聲明。聲明格式為: EXTRN 存儲區(qū)(變量名) 其存儲區(qū)域類型如表4-2所示的7種類型。
58、例如: EXTRNDATA(TIMER_SEC) EXTRNIDATA(DIS_BUF) ENTRNXDATA(SEND_BUF),6、函數(shù)編寫格式 匯編語言函數(shù)的格式如下: RSEG ?PR?函數(shù)名?模塊名 函數(shù)名: RET(或RETI),五、匯編語言文件編寫舉例 例1-6 編寫一個完整的匯編語言程序文件,文件包含三個函數(shù),分別是定時器/計數(shù)器T1產生方波信號的中斷函數(shù)、循環(huán)右移多位函數(shù)和循環(huán)左移多位函數(shù); 參數(shù)傳遞:T1的計數(shù)初值通過全局變量T1_H、T1_L傳遞。 左移、右移函數(shù)都有兩個入口參數(shù)(被移位的數(shù)、移位的位數(shù))和返回值(被移位后的數(shù)) ,要求通過寄存器傳遞。所有參數(shù)都是無符號字
59、符型數(shù)據(jù)。,程序如下: NAME EXAMP;定義模塊名 ?PR?T1_INT?EXAMPSEGMENT CODE ?PR?_RIGHT?EXAMP SEGMENT CODE ?PR?_LEFT?EXAMPSEGMENT CODE PUBLIC_RIGHT;公共函數(shù)聲明 PUBLIC_LEFT EXTRNDATA(T1_H);引用外部變量聲明 EXTRNDATA(T1_L),CSEGAT001BH;設置T1中斷入口 LJMPT1_INT RSEG ?PR?T1_INT?EXAMP;定義T1中斷處理函數(shù) T1_INT: MOVTL1, T1_L MOVTH1, T1_H CPLP1.7 RETI,RSEG ?PR?_RIGHT?EXAMP; 右移函數(shù) _RIGHT : ;R7中為第1個參數(shù), MOV A, R7;為將被移位的數(shù) RIGHT_LP: ;R5為第2個參數(shù),移位的位數(shù) RRA;右移1位 DJNZ R5, RIGHT_LP MOV R7, A;保存返回值于R7中 RET ;為被移位后的數(shù),RSEG ?PR?_LEFT?EXAMP;左移函數(shù) _ LEFT: ;R7為第1個參
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 算法理論講解
- 數(shù)字經(jīng)濟探究
- 小學環(huán)保課程指導
- 期中分析與學習規(guī)劃
- 文學流派發(fā)展解讀
- 靜脈置管護理管理課件
- 物理與化學的跨學科融合策略
- 冰雪旅游的技術創(chuàng)新與數(shù)字化發(fā)展策略
- 商品房安裝電梯合同范本
- 商場廣告招商合同范例
- 博士后研究報告(出站)
- 2024年單招考試題
- 公鐵兩用牽引車市場發(fā)展預測和趨勢分析
- 3.1 導數(shù)的概念 課件 《高等數(shù)學》
- 2024江西南昌云上國脈(江西)數(shù)字技術限公司招聘1人重點基礎提升難、易點模擬試題(共500題)附帶答案詳解
- 鄉(xiāng)村振興相關知識備考試題庫(含答案)
- 《子路、曾皙、冉有、公西華侍坐》練習及參考答案
- 2024年湖南省長沙縣高橋鎮(zhèn)敬老院招聘院長歷年高頻考題難、易錯點模擬試題(共500題)附帶答案詳解
- 2022-2023學年北京中橋外國語學校 高一數(shù)學文上學期摸底試題含解析
- 保險車商工作規(guī)劃
- 第2課古代希臘羅馬(教學課件)-【中職專用】《世界歷史》同步課堂(同課異構)(高教版2023?基礎模塊)
評論
0/150
提交評論