基于koilc的8051單片機(jī)嵌入式開發(fā)_第1頁
基于koilc的8051單片機(jī)嵌入式開發(fā)_第2頁
基于koilc的8051單片機(jī)嵌入式開發(fā)_第3頁
基于koilc的8051單片機(jī)嵌入式開發(fā)_第4頁
基于koilc的8051單片機(jī)嵌入式開發(fā)_第5頁
已閱讀5頁,還剩1頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

基于koilc的8051單片機(jī)嵌入式開發(fā)

1c語言生成模塊8151納米針系列是八本最著名的機(jī)系列之一。近幾年,隨著8051系列單片機(jī)版權(quán)的開放,在8051系列上的應(yīng)用開發(fā)不斷增加,而且應(yīng)用規(guī)模比以往大,可執(zhí)行代碼往往上幾百KB。這對(duì)于現(xiàn)在32位的PC平臺(tái)來說只是小菜一碟,而對(duì)于8位的單片機(jī)來說,已經(jīng)算是大規(guī)模的開發(fā)了。這種大型的嵌入式開發(fā)不可能完全用匯編語言或C語言來完成。C語言便于模塊化的編程風(fēng)格、優(yōu)良的可讀性、良好的可移植性和調(diào)試方便性更是這種大型程序開發(fā)的項(xiàng)目維護(hù)管理所需要的。另外,C51經(jīng)過多年的發(fā)展,已經(jīng)具有很多優(yōu)秀的集成開發(fā)工具,KeilC就是其中之一,這些集成開發(fā)工具為程序開發(fā)調(diào)試提供了良好的人機(jī)接口。因此,C語言廣泛應(yīng)用在這類大型的嵌入式程序中,通常占95%以上的代碼量。由于C51是8051單片機(jī)的C語言編譯器,與ANSI-C編譯器有不同的地方,具有很多8051單片機(jī)的特點(diǎn)。280c語言代碼設(shè)計(jì)8051系列單片機(jī)有多種存儲(chǔ)器類型:外部程序存儲(chǔ)器、內(nèi)部程序存儲(chǔ)器、外部數(shù)據(jù)存儲(chǔ)器、內(nèi)部數(shù)據(jù)存儲(chǔ)器。在開發(fā)較大型程序的時(shí)候,因?yàn)閮?nèi)部程序存儲(chǔ)器和內(nèi)部數(shù)據(jù)存儲(chǔ)器容量都比較小,通常會(huì)被分配給實(shí)現(xiàn)底層功能的匯編語言使用。C語言的代碼一般使用外部程序存儲(chǔ)器和外部數(shù)據(jù)存儲(chǔ)器。由于51系列單片機(jī)16位地址寄存器的限制,外部程序存儲(chǔ)器和外部數(shù)據(jù)存儲(chǔ)器的尋址范圍都是64KB。分組連接定位器BL51允許生成代碼長度大于64KB的8051目標(biāo)程序,它可以管理一個(gè)公共區(qū)域(COMMONAREA)和最多32個(gè)代碼組區(qū)域(BANKAREA),每個(gè)代碼組最大為64KB。8051單片機(jī)本身不支持代碼組切換,切換要通過額外的地址線(片選信號(hào))來完成。代碼組切換的軟件功能由文件L51_BANK.A51完成。每次組切換要花費(fèi)50個(gè)機(jī)器周期和2個(gè)字節(jié)的堆??臻g,所以如果發(fā)生頻繁的組切換,會(huì)消耗CPU大量的時(shí)間。外部數(shù)據(jù)存儲(chǔ)器和外部程序存儲(chǔ)器包括公共區(qū)域和組區(qū)域就是我們最關(guān)心的部分。3存儲(chǔ)模式分類C51有三種存儲(chǔ)器模式,分別是SMALL、COMPACT和LARGE。存儲(chǔ)器模式?jīng)Q定默認(rèn)情況下給變量分配的存儲(chǔ)器的類型。本文所討論的問題都設(shè)定在LARGE存儲(chǔ)器模式下,在這種模式下,變量缺省被定義在外部存儲(chǔ)器中。3.1外部程序存儲(chǔ)的靜態(tài)分配圖我們可以通過查看BL51連接器產(chǎn)生的m51文件來了解程序所使用的存儲(chǔ)器的情況。在m51文件中的LINKMAPOFMODULE部分,可以看到其中XDATAMEMORY段是外部數(shù)據(jù)存儲(chǔ)器的靜態(tài)分配圖,CODEMEMORY段是外部程序存儲(chǔ)器公共區(qū)域的連接分配圖,緊跟在后面的是CODEBANKx段就是各個(gè)組代碼的連接分配圖。在這些段里,我們可以看到類型、開始地址、長度和段名等的信息。段名的前綴?PR?、CO?和?XD?是最常見的,分別代表程序執(zhí)行代碼、程序代碼中的常量和放在外部存儲(chǔ)器的數(shù)據(jù)變量。而段的后綴一般就是大寫的C文件名的前綴。3.2堆棧方式管理通常硬件設(shè)計(jì)時(shí)外部數(shù)據(jù)存儲(chǔ)器要比外部程序存儲(chǔ)器少得多,一般限制在64KB內(nèi),這是在一般的PC平臺(tái)開發(fā)中很少遇到的。根據(jù)應(yīng)用的不同,我們可以采用包括算法、程序設(shè)計(jì)方法和技巧等方面的各種內(nèi)存受限的開發(fā)方法,不能一一盡述。這里將講述C51在存儲(chǔ)管理方式上不同于ANSI-C的特殊的地方。首先以下面的例子來了解C51是如何給不同類型的變量分配存儲(chǔ)器的。為了產(chǎn)生短小和快速的代碼,C51缺省把函數(shù)看作不可重入的,不使用堆棧來管理函數(shù)。對(duì)上面例子中的所有變量,包括函數(shù)fun1里面的a,b和函數(shù)fun2里面的a,b,C51都在外部數(shù)據(jù)存儲(chǔ)器里分配不同的空間。這是C51與ANSI-C不同的地方,也是相同的代碼在C51編譯器和ANSI-C編譯器上有不同行為的原因。C1這種缺省的不可重入函數(shù)處理方式一方面令那些利用堆棧的程序設(shè)計(jì)方法如遞歸函數(shù)出錯(cuò);另一方面它為函數(shù)中的自動(dòng)變量分配不同的空間也浪費(fèi)了大量寶貴的外部數(shù)據(jù)存儲(chǔ)器空間。對(duì)于大型的應(yīng)用來說,我們更趨向使用與ANSI-C一致的堆棧方式。這時(shí)候,我們可以使用C51的特殊保留字reentrance把函數(shù)聲明為可再入函數(shù),C51編譯器使用堆棧方式來管理可再入函數(shù)的變量。在上面例子中應(yīng)用reentrance后代碼的如下:現(xiàn)在,編譯器只為全局變量g、fun1里面的靜態(tài)變量sa和fun1里面的靜態(tài)變量sa在XDATA分配不同的空間。而對(duì)于fun1和fun2的參數(shù)變量b和自動(dòng)變量a,則使用在XDATA中的模擬堆??臻g,在程序運(yùn)行時(shí)才自動(dòng)分配。這樣,我們就節(jié)省了大量的自動(dòng)變量的空間。要注意的是,中斷函數(shù)不可以使用reentrance。另外,上面例子不直接使用保留字reentrance是為了方便在非C51下試調(diào)代碼,在非C51的編譯環(huán)境下,我們只要把例子中的首行改為#defineCOMPILER_REENTRANCE就可以避免非C51編譯器不認(rèn)識(shí)C51的特殊保留字reentrance的錯(cuò)誤了。3.3公共區(qū)域ct的生成外部程序存儲(chǔ)器放置連接器產(chǎn)生的公共區(qū)域代碼和組代碼。公共區(qū)域中的代碼可以在任何時(shí)候由所有代碼組使用。這些代碼包括:復(fù)位和中斷向量、常數(shù)、C51中斷函數(shù)、組切換跳轉(zhuǎn)表和庫函數(shù)。其實(shí),公共區(qū)域與每個(gè)組的代碼共享64KB的尋址空間,連接器缺省把公共區(qū)域放在64KB空間的低端,如圖1所示。而且公共區(qū)域在每個(gè)64KB中的起始地址和內(nèi)容完全一樣,所以叫做公共區(qū)域。這樣,實(shí)際上,程序代碼可用的最大空間=組數(shù)目×64KB-(組數(shù)目-1)×公共區(qū)域大小??梢?為了獲取更多的代碼空間,就要盡可能減少公共區(qū)域的大小。分析公共區(qū)域的代碼后,可以從三個(gè)方面減少代碼。1用一個(gè)中斷函數(shù)C51編寫的中斷函數(shù)必需放在公共區(qū)域里,但是在中斷函數(shù)里面可以調(diào)用任何組的函數(shù)。我們可以利用中斷函數(shù)的這個(gè)特性,把中斷函數(shù)寫成只有一個(gè)函數(shù)調(diào)用的外殼函數(shù)的形式,把實(shí)際工作交給組代碼里的函數(shù)完成。這個(gè)方法可以減少中斷函數(shù)的大小,但是必須考慮組切換的時(shí)間(50個(gè)機(jī)器周期)是否滿足中斷函數(shù)處理時(shí)間的要求。2減少庫函數(shù)的大小因?yàn)閹旌瘮?shù)的調(diào)用有時(shí)需要采用一些特殊的調(diào)用方式,這些方式有時(shí)會(huì)受到組間切換的影響,所以連接程序BL51總是庫函數(shù)段放置在公共區(qū)域,程序員也無法重新定位庫函數(shù)段到其他地方。要減少庫函數(shù)段的大小,就要減少使用的庫函數(shù)的數(shù)目。我們需要了解某個(gè)庫函數(shù)在哪些組里被調(diào)用,還有被調(diào)用的次數(shù)。我們應(yīng)該盡量把被多個(gè)組調(diào)用,而且被調(diào)用頻率最高的庫函數(shù)保留在公共區(qū)域;考慮重寫那些只是在單個(gè)組里被調(diào)用或使用頻率很低的庫函數(shù)。通過重寫這些庫函數(shù),我們可以根據(jù)自己要求去裁剪原來庫函數(shù)的功能,使得執(zhí)行代碼更小。另外,我們還可以自由擺放重寫后函數(shù)的位置,一般是放在發(fā)生調(diào)用的那一組里,以減少公共區(qū)域的大小。3調(diào)整傳輸字符缺省情況下,程序中的所有字符串常量會(huì)被安排在公共區(qū)域里。這種安排的好處是程序員可以像ANSI-C的習(xí)慣一樣放心地傳遞字符串常量的指針來調(diào)用函數(shù),不需要擔(dān)心C51特殊的跨組調(diào)用問題。因?yàn)槊總€(gè)64KB的代碼組都有公共區(qū)域的代碼,而且定位地址是一致的。但是在大型開發(fā),特別是涉及人機(jī)用戶界面相關(guān)的開發(fā)中,程序中會(huì)存在大量的字符串常量,如果按照以上的缺省配置方式來存放,這些字符串將占用大量的公共區(qū)域空間。為了減少公共區(qū)域中字符串常量的大小,我們可以調(diào)整的BL51設(shè)定,把常量放在指定的組,而不放在公共區(qū)域里面。例如,我們要把文件file1.c中的常量放在組1,在KeilC集成開發(fā)環(huán)境下,選擇Project菜單下Optionsfortarget,然后在BL51Misc頁下的Misccontrols中,把file1.c的常量段?CO?FILE1加到BANK1()的括號(hào)中。在把常量放在獨(dú)立的組以后,我們就必須考慮跨組調(diào)用的問題。3.4組切換時(shí)的pstC51的指針不帶有代碼組的信息,不能辨識(shí)是指向哪個(gè)代碼組的,在發(fā)生代碼組切換的時(shí)候,這些指針就會(huì)出現(xiàn)問題。如以下的例子:如圖2所示,假設(shè)函數(shù)fun1(void)在組1,display(char*pstr)函數(shù)在組0,并根據(jù)上面所述的方法把字符串常量放置在組1,連接器分配給常量“中文”的起始地址是1000H。在程序運(yùn)行的時(shí)候,程序把常量“中文”的起始地址1000H壓入堆棧,調(diào)用display,因?yàn)閐isplay在組0,所以程序發(fā)生組切換,由當(dāng)前組1切換到組0,在display函數(shù)里面,程序讀出剛剛壓入的地址信息1000H并賦予pstr,這時(shí)候pstr指向的地址是組0的1000H地址,而不是組1的1000H,所以display顯示的結(jié)果是不正確的。為了解決常量字符串指針的跨組調(diào)用的問題,我們先把常量字符串拷貝到外部數(shù)據(jù)存儲(chǔ)器,然后傳遞指向外部數(shù)據(jù)存儲(chǔ)器字符串的指針給需要切換組調(diào)用的函數(shù)。如圖2所示。使用這個(gè)方法后上例的代碼修改如下:另外,其他指向代碼組的指針,如指向函數(shù)的指針都存在同樣的問題。不過函數(shù)指針使用得比較少,一般可以通過調(diào)整函數(shù)所在的代碼組來解決。此外,出于提高性能和減少錯(cuò)誤的考慮,我們通常希望組切換盡量少發(fā)生,這就涉及到如何把組代碼分配到64KB-公共區(qū)域代碼大小的若干個(gè)組里去了。這時(shí)候我們采用軟件工程的方法,把軟件按功能劃分為模塊,較大的模塊劃分為更小的子模塊。然后分析各個(gè)模塊、子模塊間的耦合度,把耦合最大的模塊盡量放在同一個(gè)組里。這屬于靜態(tài)分析的方法。另外,我們還可以對(duì)程序進(jìn)行動(dòng)態(tài)分析,把軟件運(yùn)行時(shí)經(jīng)常執(zhí)行的代碼放在同一個(gè)組里面。經(jīng)過這樣劃分和整理以后,一方面使得軟件架構(gòu)條理清晰,一方面減少了跨組調(diào)用的情況。3.5動(dòng)態(tài)內(nèi)存池的自適應(yīng)內(nèi)容分配對(duì)于大型應(yīng)用來說,在很多情況下都會(huì)用到C語言的動(dòng)態(tài)內(nèi)存分配庫函數(shù)。因?yàn)镃51是為資源相對(duì)寶貴的單片機(jī)而設(shè)的,所以C51動(dòng)態(tài)內(nèi)存分配函數(shù)的使用也與一般的C語言有所不同。首先,考慮到單片機(jī)硬件和應(yīng)用的獨(dú)特性,C51的動(dòng)態(tài)內(nèi)存分配函數(shù)不單以函數(shù)庫的形式提供的,同時(shí)還提供源程序。源代碼分別在KeilC安裝路徑下的\C51\Lib目錄下的init_mem.c、malloc.c、alloc.c、realloc.c和free.c文件里。用戶可以根據(jù)自己的需要編寫自己的內(nèi)存分配函數(shù)來替換這些庫函數(shù)。當(dāng)然,用戶也可以把這些文件拷貝出來加入自己的工程中,以減少公共區(qū)域的大小。其次,在使用C51的所有動(dòng)態(tài)內(nèi)存管理函數(shù)(malloc,alloc,realloc,free,)前,必須先初始化動(dòng)態(tài)內(nèi)存池,其函數(shù)原型是:voidinit_mempool(voidxdata*p,unsignedintsize);其中p是動(dòng)態(tài)內(nèi)存池的開始地址,size是動(dòng)態(tài)內(nèi)存池的大小。函數(shù)的功能是從外部數(shù)據(jù)存儲(chǔ)器里面劃出一塊內(nèi)存建立動(dòng)態(tài)內(nèi)存池,并交由動(dòng)態(tài)內(nèi)存分配函數(shù)管理,程序員必須保證動(dòng)態(tài)內(nèi)存池不會(huì)與其他的內(nèi)存區(qū)域相互覆蓋,相互改寫內(nèi)容。實(shí)際應(yīng)用中的問題是如何確定動(dòng)態(tài)內(nèi)存池的位置。我們提供以下兩個(gè)方法方法一:把動(dòng)態(tài)內(nèi)存池建立在變量分配堆棧的上部,與堆棧共用同一空間,如圖3所示。先任意填寫init_mempool()函數(shù)調(diào)用中的內(nèi)存池開始地址或填寫地址0X0000,在編譯連接通過后,利用連接器生成的m51文件分析外部數(shù)據(jù)存儲(chǔ)器的使用情況,確定C51變量分配堆棧的頂端地址,也就是外部數(shù)據(jù)存儲(chǔ)器的最后空閑區(qū)域的開始地址。然后把init_mempool()的開始地址改為堆棧的頂端地址。最后再重新編譯連接一次。這個(gè)方法的一個(gè)弊端是,隨著程序的修改增減,變量分配堆棧的頂端會(huì)發(fā)生改變,所以每次程序的更改,都要重復(fù)以上的步驟。方法二:如果只是模塊A需要使用動(dòng)態(tài)內(nèi)存分配,那么動(dòng)態(tài)內(nèi)存池可以與其他不和模塊A同時(shí)運(yùn)作的模塊來共享一部分內(nèi)存。例如,模塊A需要5KB的內(nèi)存池用作動(dòng)態(tài)分配,而模塊B要用到3個(gè)2KB的緩沖區(qū)。我們可以依照如下代碼來定義模塊B緩沖區(qū)和初始化內(nèi)存池。其示意圖如圖4所示:4參數(shù)返回值和貯存前閥值的傳遞關(guān)系在單片機(jī)開發(fā)中,底層的硬件中斷和驅(qū)動(dòng)等的例程往往用匯編語言來實(shí)現(xiàn)。在大型的嵌入式開發(fā)中,C語言代碼調(diào)用底層的匯編語言代碼。要解決C語言與匯編語言之間的調(diào)用,最重要的是了解它們之間的函數(shù)名的命名規(guī)則和函數(shù)參數(shù)傳遞規(guī)則和返回值傳遞規(guī)則。C51程序模塊編譯成目標(biāo)文件后,其中的函數(shù)名依據(jù)其定義的性質(zhì)不同會(huì)轉(zhuǎn)換為不同的函數(shù)名。對(duì)于不傳遞參數(shù)或參數(shù)不通過寄存器傳遞的函數(shù),其函數(shù)名不改變。voidfunc(void)轉(zhuǎn)變后函數(shù)名為FUNC。對(duì)于參數(shù)通過寄存器傳遞的函數(shù),轉(zhuǎn)變后函數(shù)名在原來的名字前加′_′。voidfunc(intt)轉(zhuǎn)變后函數(shù)名為_FUNC。函數(shù)參數(shù)傳遞和寄存器的對(duì)應(yīng)關(guān)系,一般按參數(shù)從左到右的順序填寫寄存器R7到R0。char類型占1byte,先填R7,第二個(gè)char類型填R5。int類型占2bytes,按高低位先填R6、R7,第二個(gè)int類型填R4、R5。float和double類型占4bytes,按高低位填R4、R5、R6、R7。一般指針占3bytes,存儲(chǔ)器類型在R3,高位在R2,低位在R1。函數(shù)返回值和寄存器之間的對(duì)應(yīng)關(guān)系與參數(shù)傳遞的對(duì)應(yīng)關(guān)系差不多。以函數(shù)charVoiceOperation(charmode,intid,char*str)為例,R7存放char類型參數(shù)mode,R4、R5存放int類型參數(shù)id,R1、R2、R3存放char*類型參數(shù)str,函數(shù)的返回值存放在R7。根據(jù)上面的參數(shù)和返回值傳遞規(guī)則,用匯編編寫函數(shù)_VoiceOperation。在C語言中聲明函數(shù)VoiceOperation為外部函數(shù),然后就可以在C語言中調(diào)用匯編語言實(shí)現(xiàn)的VoiceOperation。5調(diào)試模塊的實(shí)現(xiàn)調(diào)試是軟件開

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(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ǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論