




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
重點與難點:
C51的數(shù)據(jù)類型、存儲類型和存儲模式;C51的指針定義與使用;C51與匯編語言的混合編程;C51的單片機片內(nèi)、片外資源編程控制方法。教學目標:
※掌握C51語言的數(shù)據(jù)結(jié)構(gòu)相關(guān)內(nèi)容;
※了解C51與匯編語言的混合編程方法;
※熟悉KeiluVision2的C5l仿真開發(fā)環(huán)境的使用;
※熟悉KeiluVision2與Proteus聯(lián)合仿真;
※掌握單片機的工作原理和編程方法。第4章單片機的C51語言4.1C51的程序結(jié)構(gòu)4.1.1C51語言概述如前所述,用匯編語言編寫MCS-51單片機程序必須要考慮其存儲器結(jié)構(gòu),尤其是其片內(nèi)數(shù)據(jù)存儲器與特殊功能寄存器的使用以及按實際地址處理端口數(shù)據(jù)。而用C51語言編寫單片機應用程序,則不用具體組織、分配存儲器資源和處理端口數(shù)據(jù),但對數(shù)據(jù)類型與變量的定義,必須要與單片機的存儲結(jié)構(gòu)相關(guān)聯(lián),否則編譯器不能正確地映射定位。與標準C語言相比,C51在數(shù)據(jù)類型、變量存儲模式、輸入/輸出處理、函數(shù)等方面有一定差異,它需要根據(jù)單片機存儲結(jié)構(gòu)及內(nèi)部資源定義相應的數(shù)據(jù)類型和變量,而其他語法規(guī)則、程序結(jié)構(gòu)及程序設(shè)計方法等與標準的C語言程序設(shè)計相同。本章著重介紹C51的數(shù)據(jù)結(jié)構(gòu)、C51與匯編語言的混合編程、C51仿真開發(fā)環(huán)境以及C51初步編程等內(nèi)容。學習本章要注意復習標準C語言的基本知識,因為在應用實例中要用到標準C的內(nèi)容。4.1.2C51的程序結(jié)構(gòu)
C51程序的基本單位是函數(shù)。一個C51源程序至少包含一個主函數(shù),也可以是一個主函數(shù)和若干個其他函數(shù)。主函數(shù)是程序的人口;主函數(shù)中的所有語句執(zhí)行完畢,則程序結(jié)束。以下通過一個可實現(xiàn)開關(guān)控制LED燈亮滅功能的源程序說明C51程序的基本結(jié)構(gòu)#include<REG51.H>//51單片機頭文件sbitK1=P3^0;//定義輸入開關(guān)sbitL1=P1^0;//定義輸出指示燈voiddelay();//延時函數(shù)聲明//---------------------------------voidmain(void)//主函數(shù)
{while(1)//無限循環(huán)體
{if(K1==0)//開關(guān)是否合上
{delay();//延時
if(K1==0)//開關(guān)是否合上,不是抖動
{L1=0;}//合上,燈亮}else//開關(guān)是斷開的
{L1=1;}//開關(guān)斷開,燈滅
}}voiddelay(void)//延時函數(shù)
{unsignedchari;//字符型變量i定義
for(i=200;i>0;i--);
}//循環(huán)延時開關(guān)控制LED燈亮滅.DNS圖4-1模擬開關(guān)燈電路原理圖在本例的開始處使用了預處理命令#include,它告訴編譯器在編譯時將頭文件REG51.H讀入一起編譯。在頭文件REG51.H中包括了對51單片機特殊功能寄存器名的集中說明。本例中main()是一個無返回、無參數(shù)型函數(shù),雖然參數(shù)表為空,但一對圓括號()必須有,不能省略。其中:①sbitL1=P1^0和sbitK1=P3^0是全局變量定義,它將Pl.0端口定義為L1輸出變量;它將P3.0端口定義為K輸入變量;②unsignedchari是局部變量定義,它說明i是位于片內(nèi)RAM且長度為8的字符型變量;③while(l)是循環(huán)語句,可實現(xiàn)死循環(huán)功能;④L1=0和L1=1是兩個賦值語句,等號=作為賦值運算符;⑤if(K1==0)是條件判斷語句,判斷開關(guān)是否合上⑥for(i=200,i>0;i--)是沒有語句體的循環(huán)語句,這里起到軟件延時的作用。C51語言程序的基本結(jié)構(gòu)為:包含<頭文件>
函數(shù)類型說明全局變量定義
main(){局部變量定義
<程序體>}funcl(){局部變量定義
<程序體>}…funcN(){局部變量定義
<程序體>}其中,func1()…funcN()代表用戶定義的函數(shù),程序體指C51提供的任何庫函數(shù)調(diào)用語句、控制流程語句或其他函數(shù)調(diào)用語句。4.2C51的數(shù)據(jù)結(jié)構(gòu)4.2.1C51的變量在程序執(zhí)行過程中,數(shù)值可以發(fā)生改變的量稱為變量。變量的基本屬性是變量名和變量值。一旦在程序中定義了一個變量,C51編譯器就會給這個變量分配相應的存儲單元。此后變量名就與存儲單元地址相對應,變量值就與存儲單元的內(nèi)容相對應。例如,圖4.2所示程序中通過引用變量i實現(xiàn)了對分配內(nèi)存30H單元的數(shù)據(jù)操作。圖4.2C51的變量概念示意圖要在C51程序中使用變量必須先對其進行定義,這樣編譯系統(tǒng)才能為變量分配相應的存儲單元。定義一個變量的格式如下:
[存儲種類]數(shù)據(jù)類型[存儲類型]變量名這說明變量具有4大要素,其中數(shù)據(jù)類型和變量名是不能省略的部分。1.存儲種類2.數(shù)據(jù)類型3.存儲類型
4.變量名存儲種類是指變量在程序執(zhí)行過程中的作用范圍。變量的存儲種類有4種:自動(auto)、外部(extern)、靜態(tài)(static)和寄存器(register)。使用存儲種類說明符auto定義的變量稱為自動變量。自動變量的作用范圍在定義它的函數(shù)體或復合語句內(nèi)部。在定義它的函數(shù)體或復合語句被執(zhí)行時,C51才為該變量分配內(nèi)存空間,當函數(shù)調(diào)用結(jié)束返回或復合語句執(zhí)行結(jié)束時,自動變量所占用的內(nèi)存空間被釋放,這些內(nèi)存空間又可被其他的函數(shù)體或復合語句使用。在定義變量時,如果省略存儲種類,則變量默認為自動(auto)變量。由于89C51單片機訪問片內(nèi)RAM速度很快,通常將函數(shù)體內(nèi)和復合語句中使用頻繁的變量放在片內(nèi)RAM中,且定義為自動變量,這樣可有效地利用片內(nèi)有限的RAM資源。使用存儲種類說明符extern定義的變量稱為外部變量。在一個函數(shù)體內(nèi),要使用一個已在該函數(shù)體外或別的程序模塊文件中定義過的外部變量時,該變量在本函數(shù)體內(nèi)要用extern說明。外部變量被定義后,即分配了固定的內(nèi)存空間,在程序的整個執(zhí)行期間都是有效的。通常將多個函數(shù)或模塊共享的變量定義為外部變量。外部變量是全局變量,在程序執(zhí)行期間一直占有固定的內(nèi)存空間。當片內(nèi)RAM資源緊張時,不應將外部變量放在片內(nèi)RAM。使用static定義的變量稱為靜態(tài)變量,它又分為內(nèi)部靜態(tài)變量和外部靜態(tài)變量。在函數(shù)體內(nèi)部定義的靜態(tài)變量為內(nèi)部靜態(tài)變量,它在對應的函數(shù)體內(nèi)有效,但在函數(shù)體外不可見,這樣不僅使變量在定義它的函數(shù)體外被保護,還可以實現(xiàn)當離開函數(shù)時值不被改變。外部靜態(tài)變量是在函數(shù)外部定義的靜態(tài)變量,它在程序中一直可見,但在定義的范圍之外是不可見的。如在多文件或多模塊處理中,外部靜態(tài)變量只在文件內(nèi)部或模塊內(nèi)部有效。
1.存儲種類2.數(shù)據(jù)類型表4-1C51支持的基本數(shù)據(jù)類型數(shù)據(jù)類型長度值域字符型(char)signedchar單字節(jié)0~255unsignedchar單字節(jié)-128~+127整型(int)signedint雙字節(jié)0~65535unsignedint雙字節(jié)-32768~+32767長整型signedlong4字節(jié)0~4294967295unsignedlong4字節(jié)-2147483648~+2147483647浮點型float4字節(jié)10-38~1038double8字節(jié)10-308~10308指針型普通指針*1~3字節(jié)0~65535數(shù)據(jù)的不同格式叫做數(shù)據(jù)類型,C51支持的基本數(shù)據(jù)類型與標準C相同其中,有符號數(shù)據(jù)類型可以忽略signed標識符,如signedchar等價于char,signedint等價于int等。C51還增加了一些特殊的數(shù)據(jù)類型,它們分別對應于bit、sfr、sfr16和sbit4個關(guān)鍵字。
(l)bit位型。bit位型是C51編譯器的一種擴充數(shù)據(jù)類型,利用它可定義一個位變量或位函數(shù),但不能定義位指針,也不能定義位數(shù)組。它的值是一個二進制位,不是0就是1。
(2)sfr特殊功能寄存器型。51系列單片機內(nèi)有21個特殊功能寄存器(SFR),分散在片內(nèi)RAM區(qū)的高128字節(jié),地址為80H~FFH。為了能直接訪問這些SFR,需要通過關(guān)鍵字sfr對其進行定義,語法如下:
sfrsfr_name=地址常數(shù);
這里sfr_name是一個特殊功能寄存器名,“=”后面必須是常數(shù),其數(shù)值范圍必須在特殊功能寄存器地址范圍內(nèi),即位于0x80~0xFF之間。例如:
sfrP1=0x90;//定義P1口地址90HsfrPSW=0xD0;//定義PSW地址D0H
對于16位SFR,可使用關(guān)鍵字sfr16,語法與8位SFR相同,定義的地址必須是16位
SFR的低端地址,例如:
sfr16DPTR=0x82;//定義DPTR,其DPL=82H,DPH=83H
注意:這種定義適用于所有新的SFR,但不能定義定時/計數(shù)器0和1,因為他們的地址不是連續(xù)的。
(3)sbit可位尋址型。在51系列單片機中,經(jīng)常要訪問特殊功能寄存器中的某些位,用關(guān)鍵字sbit定義可位尋址的特殊功能寄存器的位尋址對象。用關(guān)鍵字sbit定義可位尋址的特殊功能寄存器的位尋址對象。定義方法有如下3種:
1)sbit位變量名=位地址將位的絕對地址賦給位變量名,位地址必須位于0x80~0xFF之間。例如:
sbitCY=0xD7;//將位的絕對地址賦給變量
2)sbit位變量名=SFR名稱^位位置當可尋址位位于特殊功能寄存器中時,可采用這種方法。其中SFR名稱必須是已定義的SFR的名字,位位置是一個0~7之間的常數(shù)。例如:
sfrPSW=0xD0;sbitCY=PSW^7;//定義CY位為PSW.7,位地址為0xD7
3)sbit位變量名=字節(jié)地址^位位置這種方法是以一個常數(shù)(字節(jié)地址)作為基地址,該常數(shù)必須在0x80~0xFF之間。位位置是一個0~7之間的常數(shù)。例如:
sbitCY=0xD0^7;//將位的相對地址賦給變量注意sbit和bit的區(qū)別:sbit定義特殊功能寄存器中的可尋址位,而bit則定義了一個普通的位變量,一個函數(shù)中可包含bit類型的參數(shù),函數(shù)返回值也可為bit類型。典型REG51.h頭文件的部分內(nèi)容如圖4-3所示圖4-3reg51.h頭文件部分內(nèi)容示意圖
3.存儲類型
51系列單片機具有3個存儲空間:片內(nèi)低128BRAM、片外64KBRAM和片內(nèi)外統(tǒng)一編址的64KBROM,對于8052型單片機還有片內(nèi)高128BRAM空間。這些存儲空間與存儲類型的對應關(guān)系如圖4-4和表4-2所示。data區(qū)code區(qū)xdata區(qū)bdata區(qū)pdata區(qū)idata區(qū)圖4-451系列單片機存儲空間示意圖表4-2C51的存儲類型與存儲空間對應關(guān)系存儲類型存儲空間位置字節(jié)地址說明data片內(nèi)低128B存儲區(qū)00H~7FH訪問速度快,可作為常用變量或臨時性變量存儲區(qū)bdata片內(nèi)可位尋址存儲區(qū)20H~2FH允許位與字節(jié)混合訪問idata片內(nèi)高128B存儲區(qū)80H~FFH只有52系列單片機才有pdata片外頁RAM00H~FFH常用于外部設(shè)備訪問xdata片外64KBRAM0000H~FFFFH常用于存放不常用的變量或等待處理的數(shù)據(jù)code程序ROM0000H~FFFFH常用于存放數(shù)據(jù)表格等固定信息一個變量除了與存儲單元相對應外,還與它所在的存儲空間有關(guān),即還需要指出其存儲類型。例如語句chardataa聲明了a是位于片內(nèi)低128BRAM區(qū)的字符型變量。如果在定義變量時省略了存儲類型說明符,C51編譯器會根據(jù)當前編譯模式自動認定默認的存儲類型。編譯模式共分為:小編譯模式(SMALL)、緊湊編譯模式(COMPACT)和大編譯模式(LARGE)3種模式。表4-33種編譯模式的特點小結(jié)編譯模式變量存儲區(qū)域默認存儲類型特點SMALL片內(nèi)低128BRAMdata訪問數(shù)據(jù)的速度最快,但由于存儲容量小,難以滿足需要定義變量更多的場合COMPACT片外頁256BRAMpdata介于兩者之間,且受片外RAM的容量限制LARGE片外64KBRAMxdata訪問數(shù)據(jù)的效率不高,但由于存儲容量大,可以滿足需要定義變量更多的場合由表4-3可知,在SMALL編譯模式下,語句chara等價于chardataa,而在LARGE編譯模式下,語句chara等價于charxdataa。
4.變量名
C51規(guī)定變量名可以由字母、數(shù)字和下劃線3種字符組成,且第一個字符必須為字母或下劃線,變量名長度無統(tǒng)一規(guī)定,隨編譯系統(tǒng)而定。使用時應注意:大寫的變量和小寫的變量是兩個不同的變量,如SUM和sum。習慣上變量用小寫表示。另外,變量名除了應避免使用標準C語言的32個關(guān)鍵字外,還要避免使用C51擴展的新關(guān)鍵字。表4-4C51擴展的21個關(guān)鍵字一覽表關(guān)鍵字用途說明_at_地址定位為變量進行存儲器絕對空間地址定位alien函數(shù)特性聲明聲明與PL/M-51編譯器的接口bdata存儲類型說明可位尋址的內(nèi)部數(shù)據(jù)存儲器bit位變量聲明聲明一個位變量或位函數(shù)code存儲器類型聲明程序存儲器compact存儲模式聲明聲明一個緊湊編譯存儲模式data存儲器類型聲明直接尋址的內(nèi)部數(shù)據(jù)存儲器far遠變量聲明Keil用3BYTE指針來引用它idata存儲器類型聲明間接尋址的內(nèi)部數(shù)據(jù)存儲器interrupt中斷函數(shù)聲明定義一個中斷服務函數(shù)large存儲模式聲明聲明一個大編譯存儲模式pdata存儲器類型聲明分頁尋址的外部數(shù)據(jù)存儲器_priority_多任務優(yōu)先聲明規(guī)定RTX51或RTX51Tiny的任務優(yōu)先級reentrant再入函數(shù)聲明用于把函數(shù)定義為可重人函數(shù)sbit擴充數(shù)據(jù)類型聲明聲明一個可位尋址變量sfr擴充數(shù)據(jù)類型聲明聲明一個特殊功能寄存器sfr16擴充數(shù)據(jù)類型聲明聲明一個16位的特殊功能寄存器small存儲模式聲明聲明一個小編譯存儲模式_task_任務聲明定義實時多任務函數(shù)using寄存器組定義定義51單片機工作寄存器組xdata存儲器類型聲明外部數(shù)據(jù)存儲器所有變量在使用前必須聲明,即變量須“先定義,后使用”,凡未被定義的,不作為變量名,這樣可保證程序中變量名使用的正確性。
unsignedchardatasystem_status=0;//定義system_status為無符號字符型自動變
//量,該變量位于data區(qū)中且初值為0unsignedcharbdatastatus_byte;//定義status_byte為無符號字符型自動變量,
//該變量位于bdata區(qū)中
unsignedintcodeunit_id[2]={Ox1234,Ox89ab};//定義unit_id[2]為無符號整型自
//動變量,該變量位于code區(qū)中,且
//為長度為2的數(shù)組,初值為0x1234//和0x89abstaticcharm,n;//定義m和n為2個位于data區(qū)中的有符號字符型靜態(tài)變量
externfloatxdatavar4;//在片外RAM64KB空間定義外部實型變量var4#pragmaCOMPACT//設(shè)置編譯模式,指定默認存儲類型
chark2;//定義k2為有符號字符型自動變量,且默認為pdata型
4.2.2C51的指針標準C語言指針的一般定義形式為:
數(shù)據(jù)類型*指針變量名其中“*指針變量名”表示這是一個指針變量,它指向一個由“數(shù)據(jù)類型”說明的變量。被指向變量和指針變量都位于C編譯器默認的存儲區(qū)中。例如:inta='A';int*p1=&a;
這表示p1是一個指向int型變量的指針變量,此時p1的值為int型變量a的地址,而a和p1兩個變量都位于C編譯器默認的內(nèi)存區(qū)域中。對于C51來講,除上述信息外,指針定義還應包括以下信息:(1)指針變量自身位于哪個存儲區(qū)中(2)被指向變量位于哪個存儲區(qū)中故C51指針的一般定義形式為:
數(shù)據(jù)類型[存儲類型1]*[存儲類型2]指針變量名;其中“數(shù)據(jù)類型”是被指向變量的數(shù)據(jù)類型,如int型或char型等;“存儲類型1”是被指向變量所在的存儲區(qū)類型,如data,code,xdata等,缺省時根據(jù)該變量的定義語句確定;“存儲類型2”是指針變量所在的存儲區(qū)類型,如data,code,xdata等,缺省時根據(jù)C51編譯模式的默認值確定;指針變量名可按C51變量名的規(guī)則選取。
例4-1charxdataa='A’;char*ptr=&a;
解:在這個例子里,ptr是一個指向char型變量的指針變量,它本身位于SMALL編譯模式默認的data存儲區(qū)里,它的值是位于xdata存儲區(qū)里的char型變量a的地址。
例4-2charxdataa='A';char*ptr=&a;charidatab='B';*ptr=&b;
解:在這個例子里,前兩句與例4-1相同。而后兩句里,由于變量b位于idata存儲區(qū)中,所以當執(zhí)行完*ptr=&b之后,ptr的值是位于idata存儲區(qū)里的char型變量b的地址。從此可看出,以char*ptr形式定義的指針變量,其數(shù)值既可以是位于xdata存儲區(qū)的char型變量的地址,也可以是位于idata存儲區(qū)的char型變量的地址,具體結(jié)果由賦值操作關(guān)系決定。例4-3charxdataa='A';charxdata*ptr=&a;
解:這里變量a是位于xdata存儲區(qū)里的char型變量,而ptr是位于data存儲區(qū)且固定指向xdata存儲區(qū)的char型變量的指針變量,此時ptr的值為變量a的地址(不能像例4-2那樣再將idata存儲區(qū)的char型變量b的地址賦予ptr)。
例4-4charxdataa='A';charxdata*idataptr=&a;
解:這里表示,ptr是固定指向xdata存儲區(qū)的char型變量的指針變量,它自身存放在idata存儲區(qū)中,此時ptr的值為位于xdata存儲區(qū)中的char型變量a的地址。4.3C51與匯編語言的混合編程C51語言提供了豐富的庫函數(shù),具有很強的數(shù)據(jù)處理能力,可生成高效簡潔的目標代碼,在絕大多數(shù)場合采用C51語言編程即可完成預期的任務。盡管如此,有時仍需要采用一定的匯編語言程序,如對于某些特殊的I/O接口地址的處理、中斷向量地址的安排、提高程序代碼的執(zhí)行速度等。為此,C51編譯器提供了與匯編語言程序的接口規(guī)則,按此規(guī)則可以方便地實現(xiàn)C51語言程序與匯編語言程序的相互調(diào)用。
4.3.1在C51中調(diào)用匯編程序要實現(xiàn)在C51函數(shù)中調(diào)用匯編函數(shù),需要了解C51編譯器的編譯規(guī)則。下面我們從一個實例人手,介紹有關(guān)內(nèi)容,即在兩個給定數(shù)據(jù)中選出較大的那個數(shù)據(jù),其程序源代碼如下://以下代碼在main.c文件中實現(xiàn)voidmax(chara,charb);//由匯編語言實現(xiàn)main(){chara=30,b=40,C;C=max(a,b);}在上面的主函數(shù)中,voidmax(chara,charb)函數(shù)是在下面的匯編文件中實現(xiàn)的:
;以下代碼在匯編文件max.asm中實現(xiàn)
PUBLICMAXDESEGMENTCODERSEGDE_MAX:MOVA,R7;取第一個參數(shù)
MOV30H,R5;取第二個參數(shù)
CJNEA,30H,TAG SJMPEXITTAG:JNCEXITMOVA,R5;
MOVR7,A;返回第二個參數(shù)
EXIT:RET;返回第一個參數(shù)END要想使以匯編語言實現(xiàn)的函數(shù)能夠在C程序中被調(diào)用,需要解決下面3個問題:①程序的尋址。在main()中調(diào)用的max()函數(shù),如何與匯編文件中的相應代碼對應起來;②參數(shù)傳遞,從main()中傳遞給max()函數(shù)的參數(shù)a和b,存放在何處可使匯編程序能夠獲取它們的值;③返回值傳遞,匯編語言計算得到的結(jié)果,存放在何處可使C語言程序能夠獲取。程序的尋址是通過在匯編文件中定義同名的“函數(shù)”來實現(xiàn)的,例如上面匯編代碼中的:
PUBLICMAXDESEGMENTCODERSEGDE_MAX:…
在上面的例子中,
“_MAX”與C程序中的max相對應。在C程序和匯編語言之間,函數(shù)名的轉(zhuǎn)換規(guī)則見表4-5。表4-5函數(shù)名的轉(zhuǎn)換規(guī)則C程序的函數(shù)聲明匯編語言的符號名解釋voidfunc(void)FUNC無參數(shù)傳遞或不含寄存器參數(shù)的函數(shù)名不做改變地傳人目標文件中,名字只是簡單地轉(zhuǎn)換為大寫形式voidfunc(char)_FUNC帶寄存器參數(shù)的函數(shù)名轉(zhuǎn)為大寫,并加上“_”前綴voidfunc(void)reentrant_?FUNC重人函數(shù)須使用前綴“_?”傳遞參數(shù)的簡單辦法是使用寄存器,這種做法能夠產(chǎn)生精煉高效的代碼,具體規(guī)則見表4-6。
表4-6參數(shù)傳遞規(guī)則參數(shù)類型charintlong,float一般指針第1個參數(shù)R7R6,R7R4~R7R1,R2,R3第2個參數(shù)R5R4,R5R4~R7R1.R2,R3第3個參數(shù)R3R2,R3無R1.R2,R3在前面的例子語句voidmax(chara,charb);中,第一個char型參數(shù)a放在寄存器R7中,第二個char型參數(shù)b放在寄存器R5中。因此在后面的匯編代碼中,就是分別從R7和R5中取這兩個參數(shù):
…MAX:MOVA,R7;取第一個參數(shù)
MOV30H,R5;取第二個參數(shù)
…匯編語言通過寄存器或存儲器傳遞參數(shù)給C語言程序。匯編語言通過寄存器傳遞參數(shù)給C語言的返回值見表4-7。
表4-7匯編語言返回值返回值寄存器說明bitC進位標志(unsigned)charR7(unsigned)intR6.R7高位在R6,低位在R7(unsigned)longR4~R7高位在R4,低位在R7floatR4~R732位IEEE格式,指數(shù)和符號位在R7指針R1,R2,R3R3存放寄存器類型,高位在R2,低位在R1在前面的例子中,匯編程序就是通過把兩個數(shù)中較大的一個保存在寄存器R7中返回給C函數(shù)的。
4.3.2在C51中嵌入?yún)R編代碼在C51函數(shù)內(nèi)嵌入?yún)R編代碼,可以有3種不同的方法。
方法1
直接在函數(shù)體內(nèi)的每個匯編語句前加“asm”預編譯指令。例如:
voidreset__data(void){asmMOVR1,#0AHasmLOOP:INCA
asmDJNZR0,LOOPreturn;
}
方法2把asm作為關(guān)鍵字,后續(xù)的匯編語句用大括號括起來即可。例如:
voidreset__data(void){asm{MOVR1,#0AHLOOP:INCADJNZR0,LOOP}return;}
方法3在C模塊內(nèi)通過語句“#pragma”嵌入?yún)R編代碼。例如:
voidreset(void){#pragmaasmMOVR1,#0AHLOOP:INCADJNZR0,LOOP#pragmaendasmreturn;
}4.4C51仿真開發(fā)環(huán)境4.4.1Keil的編譯環(huán)境μVision2Keil是德國KeilSoftware公司出品的單片機集成開發(fā)軟件,該軟件支持51單片機的所有變種(目前共有400多種型號)。Keil提供了包括C編譯器、宏匯編、連接器、庫管理及一個功能強大的仿真調(diào)試器在內(nèi)的完整開發(fā)方案,并通過一個集成開發(fā)環(huán)境(μVision2)將這些部分組合在一起。Keil單片機集成開發(fā)軟件可以運行在Windows98/NT/2000及XP等操作系統(tǒng)下。
μVision2的軟件界面包括4大組成部分,即菜單工具欄、工程管理窗口、文件窗口和輸出窗口(如圖4.5所示)。以下僅針對組成結(jié)構(gòu)做個簡單介紹,具體使用方法將在本書附錄A中結(jié)合實驗需要進行介紹。圖4-5μvision2的軟件界面①菜單工具欄:菜單為標準的Windows風格,μVision2中共有11個下拉菜單。②工程管理窗口:工程管理窗口用于管理工程文件目錄,它由5個子窗口組成,可以通過子窗口下方的標簽進行切換,它們分別是文件窗口、寄存器窗口、幫助窗口、函數(shù)窗口及模板窗口。③文件窗口:文件窗口用于顯示打開的程序文件,多個文件可以通過窗口下方的文件標簽進行切換。④輸出窗口:輸出窗口用于輸出編譯過程中的信息,由三個子窗口組成,可以通過子窗口下方的標簽進行切換,它們分別是編譯窗口、命令窗口和搜尋窗口。為了掌握程序運行信息,Keil軟件在調(diào)試程序時還提供了許多信息窗口,包括輸出窗口、觀察窗口、存儲器窗口、反匯編窗口以及串行窗口等。為了能夠比較直觀地了解單片機中定時器、中斷、并行端口、串行端口等常用外設(shè)的使用情況,Keil還提供了一些外圍接口對話框。然而,Keil的這些調(diào)試手段都是通過數(shù)值變化來監(jiān)測程序運行的,很難直接看出程序的實際運行效果,特別是對于包含測量、控制、人機交互等外部設(shè)備的單片機應用系統(tǒng)來講缺乏直觀性。具有強大仿真功能的Proteus軟件雖然較好地解決了外圍電路與單片機混合仿真的問題,它卻沒有C51仿真功能。Proteus與KeilC的聯(lián)合使用則可使這兩個仿真軟件優(yōu)勢互補,組建單片機應用系統(tǒng)在C51條件下的整機虛擬實驗環(huán)境。該虛擬實驗環(huán)境包括一個硬件執(zhí)行環(huán)境和一個軟件執(zhí)行環(huán)境,其中Proteus提供硬件仿真與運行環(huán)境,Keil提供軟件執(zhí)行環(huán)境。4.4.2基于KeilC和Proteus的程序開發(fā)過程在PC機上安裝KeiluVision2軟件,完成后先要建立一個項目,如圖4-6所示,啟動KeiluVision2,單擊“Project菜單/New…”選項:圖4-6建立新項目圖4-7保存新項目
從彈出的窗口中,選擇要保存項目的路徑,并輸入項目文件名“ADC0809.uv2”,然后點擊保存按鈕,如圖4-7所示:這時會彈出一個選擇CPU型號的對話框,可以根據(jù)所使用的單片機來選擇,如圖4-8所示選擇SST89x516RD2,選定CPU型號之后從窗口右邊一欄可以看到對這個單片機的基本說明,點擊確定按鈕后會彈出如圖4-9所示窗口,詢問是否要將啟動代碼“StartupCode”加入到項目中,對于采用高級語言C51編寫的程序,點擊“是”按鈕,對于采用匯編語言編寫的程序可以不用啟動代碼“StartupCode”,因此點擊否按鈕。圖4-8選擇CPU圖4-9添加啟動代碼圖4-10創(chuàng)建程序文件接下來要創(chuàng)建程序文件,如圖4-10所示,單擊“File菜單/New…”選項:在彈出的編輯窗口中輸入如下C51源程序://********************************************************************************//********************************************************************************//**<程序名>:數(shù)字電壓表 **//**<功能>:使用LCD顯示被檢測電壓,精度為0.05V,范圍是0~5V。**//**<版本說明>:這是第1版,使用16X2LCD顯示。 **//**<作者>:皮大能 **//**<完成時間>:2010年2月8日 **//**<聯(lián)系方式>:pidaneng@163.com;QQ:399676777 **//********************************************************************************//*******************************頭文件及宏定義*******************************//********************************************************************************#include<REG52.h>#include"delay.h"http://插入延時頭文件(見4.5)#include"LCD1602.h"http://插入LCD1602顯示頭文件#defineTIME0H0x3C//定時初值高八位#defineTIME0L0xB0//定時初值高低位#defineucharunsignedchar#defineuintunsignedint//*************************************************************************//***********************端口設(shè)置宏定義************************************//*************************************************************************sbitSTART=P2^4;//ATART,ALE接口。0->1->0:啟動AD轉(zhuǎn)換。sbitOE=P2^3;//讀ADC0809數(shù)據(jù),低電平有效sbitEOC=P3^3;//轉(zhuǎn)換完畢由0變1.#defineOUTPORTP0//ADC0809數(shù)據(jù)接口//**************************************************************************//********************************全局變量**********************************//**************************************************************************ucharuc_Clock=0; //定時器0中斷計數(shù)bitb_ADTransform=0;//啟動A/D轉(zhuǎn)換時間到標志,為1時啟動A/D轉(zhuǎn)換//*************************************************************************//******************************函數(shù)聲明***********************************voidDelay(); //延時函數(shù)。voidWR_CMD(ucharucCommand);//把1個命令寫入LCD函數(shù)。voidInitialize(); //LCD初始化函數(shù)voidWR_Data(ucharucData); //把1個數(shù)據(jù)寫入LCD。voidShow_1_Char(ucharucChar);//把1個字符寫入LCD.voidShow_Char(ucharucaChar[]);//把組字符寫入LCD.voidvShowVoltage(unintuiNumber);//uintuiADTransform();//AD轉(zhuǎn)換函數(shù),返回轉(zhuǎn)換結(jié)果.voidTime0();//定時器0中斷函數(shù).//**************************************************************************//AD轉(zhuǎn)換函數(shù)//AD轉(zhuǎn)換函數(shù),返回轉(zhuǎn)換結(jié)果。//轉(zhuǎn)換結(jié)果是3位數(shù),小數(shù)點在百位與十位之間。//**************************************************************************uintuiADTransform(){uintuiResult;OUTPORT=0x00;//選ADC0809的0通道START=1; //啟動AD轉(zhuǎn)換。0->1->0START=0;while(EOC==0);//等待轉(zhuǎn)換結(jié)束。
OUTPORT=0xff;//數(shù)據(jù)口設(shè)為輸入狀態(tài)
OE=0;//打開ADC0809的數(shù)據(jù)口三態(tài)門uiResult=OUTPORT;//出入轉(zhuǎn)換結(jié)果。
OE=1;//關(guān)閉ADC0809的數(shù)據(jù)口uiResult=(100*uiResult)/51;//處理運算結(jié)果。returnuiResult;//帶處理好的AD轉(zhuǎn)換結(jié)果返回}//**************************************************************************//電壓數(shù)據(jù)寫入LCD函數(shù)//**************************************************************************voidvShowVoltage(unintuiNumber){ucharucaNumber[3],ucCount;if(uiNumber>999) {uiNumber=999;} ucaNumber[0]=uiNumber/100;//把計算數(shù)字的每個位存入數(shù)組。取整數(shù)部分
ucaNumber[1]=(uiNumber/10)%10;//取小數(shù)點后第1位數(shù)
ucaNumber[2]=uiNumber%10;//取小數(shù)點后第2位數(shù)
for(ucCount=0;ucCount<3;ucCount++) { Show_1_Char(ucaNumber[ucCount]+48); //從首位到末位逐一輸出。
if(ucCount==0) {Show_1_Char('.');} }}//**************************************************************************//*********************************主函數(shù)***********************************//**************************************************************************voidmain(){TMOD=0x01; //定時器0,模式1。TH0=TIME0H;//定時器初值的高八位送入TH0TL0=TIME0L;//定時器初值的低八位送入TL0uc_Clock=5;//設(shè)定時計數(shù)初值TR0=1;//啟動定時器。ET0=1;//開定時器中斷。EA=1;//開總中斷LCD_Initial1();//LCD初始化WR_CMD(0x84);//寫入顯示"Voltage:"的起始地址Show_Char("Voltage:");//寫入"Voltage:"到LCD顯示W(wǎng)R_CMD(0xC9);//寫入顯示"(V)"的起始地址Show_Char("(V)");//寫入"(V)"到LCD顯示while(1){if(b_ADTransform==1)//如果A/D采樣時間到就啟動A/D轉(zhuǎn)換
{ b_ADTransform=0;//清采樣時間到標志
WR_CMD(0xC4);//寫入顯示電壓數(shù)據(jù)的起始地址
vShowVoltage(uiADTransform()); } }}//**************************************************************************//***************************定時器0中斷函數(shù)********************************//**************************************************************************voidTime0()interrupt1{TH0=TIME0H;//恢復定時器0的初值。TL0=TIME0L;uc_Clock--;//定時計數(shù)器減1if(uc_Clock==0){ uc_Clock=5;//定時計數(shù)器置初值
b_ADTransform=1;//置采樣周期到標志}}//**************************************************************************//*LCD1602驅(qū)動程序 *// 文件名:LCD1602.h//**************************************************************************#ifndef__LCD1602_H__#define__LCD1602_H__//*****************************************************#include<REG52.h>//插入52特殊功能寄存器頭文件#include<intrins.h>#include"delay.h"http://插入延時頭文件(見4.5)//*************************************************************************#defineuintunsignedint#defineucharunsignedchar//***********************端口設(shè)置宏定義************************************//*************************************************************************sbitLCDRS=P2^0;//寄存器選擇信號sbitLCDRW=P2^1;//讀寫信號sbitLCDE=P2^2;//片選信號,當輸入下降沿信號時,執(zhí)行指令或傳送數(shù)據(jù)。#defineLCDDBPP0//LCD數(shù)據(jù)接口。/***********1602液晶顯示部分子程序****************///內(nèi)部等待函數(shù)*********************************************unsignedcharLCD_Wait(void){chardatamykey;LCDE=0;//操作脈沖信號置低電平_nop_();LCDRS=0;//LCD設(shè)為命令模式_nop_();LCDRW=1;//LCD設(shè)為讀狀態(tài)
_nop_();LCDE=1;//產(chǎn)生操作脈沖上升沿
_nop_();mykey=LCDDBP&0x80;//讀LCD的狀態(tài)信息LCDE=0;returnmykey;//帶LCD狀態(tài)信息返回
}//**************************************************************************//把1個命令寫入LCD函數(shù)//**************************************************************************voidWR_CMD(unsignedcharCommand) {LCDE=0;//操作脈沖信號置低電平_nop_();LCDRS=0;//LCD設(shè)為命令模式_nop_();LCDRW=0;//LCD設(shè)為寫狀態(tài)LCDE=1;//產(chǎn)生操作脈沖上升沿_nop_(); LCDDBP=Command;//輸出命令。_nop_();LCDE=0;//最后執(zhí)行命令。while((LCD_Wait())==0x80);//測試操作完否}//**************************************************************************//把1個數(shù)據(jù)寫入LCD函數(shù)//**************************************************************************voidWR_Data(unsignedcharData) {LCDE=0;//操作脈沖信號置低電平_nop_();LCDRS=1;//LCD設(shè)為數(shù)據(jù)模式_nop_();LCDRW=0;//LCD設(shè)為寫狀態(tài)_nop_();LCDE=1;//然后把LCD改為寫入數(shù)據(jù)狀態(tài)。_nop_(); LCDDBP=Data;//再輸出數(shù)據(jù)。LCDE=0;//最后顯示數(shù)據(jù)。while((LCD_Wait())==0x80);//測試操作完否}//**************************************************************************//設(shè)置顯示模式************************************************************#defineLCD_SHOW 0x04//顯示開#defineLCD_HIDE 0x00//顯示關(guān)#defineLCD_CURSOR 0x02//顯示光標#defineLCD_NO_CURSOR 0x00//無光標#defineLCD_CLEAR_SCREEN 0x01//清屏#defineLCD_HOMING 0x02//光標返回原點#defineLCD_FLASH 0x01//光標閃動#defineLCD_NO_FLASH 0x00//光標不閃動voidLCD_SetDisplay(unsignedcharDisplayMode){WR_CMD(0x08|DisplayMode);}//設(shè)置輸入模式************************************************************#defineLCD_AC_UP 0x02#defineLCD_AC_DOWN 0x00//default#defineLCD_MOVE 0x01//畫面可平移#defineLCD_NO_MOVE 0x00//defaultvoidLCD_SetInput(unsignedcharInputMode){WR_CMD(0x04|InputMode);}//LCD初始化1************************************************************voidLCD_Initial1(){LCDE=0;//操作脈沖信號置低電平WR_CMD(0x38);//8位數(shù)據(jù)端口,2行顯示,5*7點陣LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR);//開啟顯示,無光標WR_CMD(LCD_CLEAR_SCREEN);//清屏LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE);//AC遞增,畫面不動}//LCD初始化2************************************************************voidLCD_Initial2(){LCDE=0;//操作脈沖信號置低電平WR_CMD(0x38);//8位數(shù)據(jù)端口,2行顯示,5*7點陣LCD_SetDisplay(LCD_SHOW|LCD_CURSOR|LCD_FLASH);//開啟顯示,有光標,光標閃動WR_CMD(LCD_CLEAR_SCREEN);//清屏LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE);//AC遞增,畫面不動}//************************************************************************** //把1個字符寫入LCD函數(shù)//**************************************************************************voidShow_1_Char(unsignedcharucChar){WR_Data(ucChar);}//調(diào)用寫數(shù)據(jù)函數(shù)//**************************************************************************//把一組字符寫入LCD函數(shù)//**************************************************************************voidShow_Char(unsignedcharucaChar[]){unsignedchari;for(i=0;;i++){Show_1_Char(ucaChar[i]);//調(diào)用一個字符寫入LCD函數(shù)if(ucaChar[i+1]=='\0')//如果下一個字符是'\0'就退出
{break;}}}//***********************************************************//液晶字符輸入的位置*****************************************voidGotoXY(unsignedcharx,unsignedchary){if(y==0)//是0行嗎?
{WR_CMD(0x80|x);}//是,寫入0行的寫入數(shù)據(jù)的首地址
if(y==1)//是1行嗎?
{WR_CMD(0x80|(x-0x40));}////是,寫入1行的寫入數(shù)據(jù)的首地址}//------------------------------------------------------------#endif程序輸入完成后,單擊“File菜單/Saveas…”選項,如圖4-11示:圖4-11存程序文件從彈出的窗口中,選擇要保存程序文件的路徑,并輸入程序文件名“ADC0809.c”,然后點擊保存按鈕,如圖4.12示:圖4.12保存程序文件圖4-13添加程序文件下面需要將剛才創(chuàng)建的程序文件添加到項目中去。先用鼠標左建點擊uVision2左邊“項目窗口”中“Target1”前面的“+”號,展開里面的內(nèi)容“SourceGroup1”,然后將鼠標指向“SoureceGroup1”并單擊右鍵,彈出一個右鍵菜單,單擊右鍵菜單中的“AddFilestoGuoup'SourceGroup1'”選項,如圖4-13所示:圖4-14選擇添加程序文件從彈出的窗口中選擇剛才保存的文件“ADC0809.c”添加到項目中去,如圖4-14所示。圖4-15設(shè)置目標選項程序文件添加完畢后,還要設(shè)置當前項目的目標選項,將鼠標指向“Target1”并單擊右鍵,再從彈出的右鍵菜單中單擊“OptionsforTarget”選項,如圖4-15所示:從彈出的“Options”窗口中選擇“Target”標簽欄,并如圖4-16所示設(shè)置其中各項:圖4-16設(shè)置Target選項圖
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 海南改性塑料項目可行性研究報告
- 酒店開會員計劃方案
- 高中一年級數(shù)學《函數(shù)的應用(2)》
- 高蛋白人造肉即食產(chǎn)品行業(yè)跨境出海項目商業(yè)計劃書
- 新校區(qū)建設(shè)工程項目可行性研究報告-廣州2025咨詢
- 環(huán)保型水性PU合成革行業(yè)跨境出海項目商業(yè)計劃書
- 農(nóng)業(yè)氣象指數(shù)保險企業(yè)制定與實施新質(zhì)生產(chǎn)力項目商業(yè)計劃書
- DB32/T 4532-2023點螺漆器技術(shù)規(guī)范
- 材料作文與生活實際的結(jié)合
- 留守兒童家訪記錄內(nèi)容范文
- 2025年液壓馬達開發(fā)行業(yè)深度研究報告
- 樹木移栽施工協(xié)議書
- 手術(shù)前抗凝藥停用時間
- 租地解除合同協(xié)議書
- 2025智能礦山暨無人駕駛行業(yè)藍皮書-億歐智庫
- 2025湖北水發(fā)集團園招聘40人筆試參考題庫附帶答案詳解
- 2025年人工智能應用技術(shù)考試試題及答案
- 2025年武漢鐵路局招聘筆試參考題庫含答案解析
- GA 1551.6-2021 石油石化系統(tǒng)治安反恐防范要求 第6部分:石油天然氣管道企業(yè)
- 工程機械維修工時費標準
- 投資決策流程圖
評論
0/150
提交評論