版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
王健帶你征服Pic單片
機(jī)PROTUES仿真C語言部作者多年工作經(jīng)驗(yàn)的著作講解最全的單片機(jī)C語言程序王健著337884703@前言這個(gè)教程最大的特色就是用PROTUES軟件,為讀者省去一大筆開支,真正零開支,所用軟件是MPLABIDE8.63和PICC9.8這本書分為兩部分,雖然是C語言,但是也要講一下單片機(jī)的一些基礎(chǔ)知識(shí),第一部分講單片機(jī)的基礎(chǔ)知識(shí),第二部分講C程序PIC單片機(jī)(PeripheralInterfaceController)是一種用來可開發(fā)的去控制外圍設(shè)備的可編程集成電路(IC)。由美國Microchip(微星)公司推出的PIC單片機(jī)系列產(chǎn)品,首先采用了RISC結(jié)構(gòu)的嵌入式微控制器,其高速度、低電壓、低功耗、大電流LCD驅(qū)動(dòng)能力和低價(jià)位OTP技術(shù)等都體現(xiàn)出單片機(jī)產(chǎn)業(yè)的新趨勢(shì)?,F(xiàn)在PIC系列單片機(jī)在世界單片機(jī)市場(chǎng)的份額排名中已逐年升位,尤其在8位單片機(jī)市場(chǎng),已從1990年的第20位上升到目前的第二位。PIC單片機(jī)從覆蓋市場(chǎng)出發(fā),已有三種(又稱三層次)系列多種型號(hào)的產(chǎn)品問世,所以在全球都可以看到PIC單片機(jī)從電腦的外設(shè)、家電控制、電訊通信、智能儀器、汽車電子到金融電子各個(gè)領(lǐng)域的廣泛應(yīng)用?,F(xiàn)今的PIC單片機(jī)已經(jīng)是世界上最有影響力的嵌入式微控制器之一。
第一部分認(rèn)識(shí)pic單片機(jī)PIC單片機(jī)(PeripheralInterfaceController)是種用來開發(fā)去控制外圍設(shè)備的集成電路(IOo一種具有分散作用(多任務(wù))功能的CPU。與人類相比,大腦就是CPU,PIC共享的部分相當(dāng)于人的神經(jīng)系統(tǒng)。.PIC單片機(jī)是一個(gè)小的計(jì)算機(jī).PIC單片機(jī)有計(jì)算功能和記憶內(nèi)存像CPU并由軟性控制運(yùn)行。然而,處理能力一般,存儲(chǔ)器容量也很有限,這取決于PIC的類型。但是它們的最高操作頻率大約都在20MHz左右,存儲(chǔ)器容量用做寫程序的大約IK—4K字節(jié)。時(shí)鐘頻率與掃描程序的時(shí)間和執(zhí)行程序指令的時(shí)間有關(guān)系。但不能僅以時(shí)鐘頻率來判斷程序處理能力,它還隨處理裝置的體系結(jié)構(gòu)改變(1*)。如果是同樣的體系結(jié)構(gòu),時(shí)鐘頻率較高的處理能力會(huì)較強(qiáng)。這里用字來解釋程序容量。用一個(gè)指令(2*)表示一個(gè)字。通常用主芭(3*)來表示存儲(chǔ)器(4*)容量。一個(gè)字節(jié)有8位,每位由1或0組成。PIC16F84A單片機(jī)的指令由14位構(gòu)成。當(dāng)把1K個(gè)字轉(zhuǎn)換成位為:1xl,024x14
=14,336位。再轉(zhuǎn)換為字節(jié)為:14,336/(8x1,024)=1.75Ko在計(jì)算存儲(chǔ)器的容量時(shí),我們規(guī)定1G生苴=1,024M字節(jié),1M字節(jié)=1,024K字節(jié),1K字節(jié)=1,024位.它們不是以1000為倍數(shù),因?yàn)檫@是用二進(jìn)制計(jì)算的緣故。1*計(jì)算機(jī)的物理結(jié)構(gòu),包括組織結(jié)構(gòu)、容量、該計(jì)算機(jī)的CPU、存儲(chǔ)器以及輸入輸出設(shè)備間的互連。經(jīng)常特指CPU的組織結(jié)構(gòu),包括它的寄存器、標(biāo)志、總統(tǒng)、算術(shù)邏輯部件、指令譯碼與執(zhí)行機(jī)制以及定時(shí)和控制部件。2*指出某種操作并標(biāo)識(shí)其操作數(shù)(如果有操作數(shù)的話)的一種語言構(gòu)造3*作為一個(gè)單位來操作(運(yùn)算)的一個(gè)二進(jìn)制字符串,通常比計(jì)算機(jī)的一個(gè)字短。4*處理機(jī)內(nèi)的所有可尋址存儲(chǔ)空間以及用于執(zhí)行指令的其它內(nèi)存儲(chǔ)器。在計(jì)算存儲(chǔ)器的容量時(shí),我們規(guī)定1G字節(jié)=1,024M字節(jié),1M字節(jié)=l,024K字節(jié),1K字節(jié):1,024字節(jié).它們不是以io。。為倍數(shù),因?yàn)檫@是用ma制計(jì)算的緣故。用PIC單片機(jī)使電路做的很小巧變得可能。因?yàn)镻IC單片機(jī)可以把計(jì)算部分、內(nèi)存、輸入和輸出等都做在一個(gè)芯片內(nèi)。所以她工作起來效率很高、功能也
自由定義還可以靈活的適應(yīng)不同的控制要求,而不必去更換不同的IC。這樣電路才有可能做的很小巧。PIC單片機(jī)型號(hào)命名規(guī)則PICXXXXXXXX(X)-XXX/XX12345678.前綴:PICMICROCHIP公司產(chǎn)品代號(hào),特別地:dsPIC為集成DSP功能的新型PIC單片機(jī).系列號(hào):10、12、16、18、24、30、33、32,其中PIC10、PIC12、PIC16、PIC18為8位單片機(jī)PIC24、dsPIC30.dsPIC33為16位單片機(jī)PIC32為32位單片機(jī).器件型號(hào)(類型):CCMOS電路CRCMOSROMLC小功率CMOS電路LCS小功率保護(hù)AA1.8VLCR小功率CMOSROMLV低電壓F快閃可編程存儲(chǔ)器HC高速CMOSFRFLEXROM.改進(jìn)類型或選擇54A、58A、61、62、620、621622、63、64、65、71、73、7442、43、44等.晶體標(biāo)不:LP小功率晶體,RC電阻電容,XT標(biāo)準(zhǔn)晶體/振蕩器HS高速晶體.頻率標(biāo)不:-022MHZ,-044MHZ,-1010MHZ,-1616MHZ-2020MHZ,-2525MHZ,-3333MHZ.溫度范圍:空白0℃至70℃,I-45℃至85℃,E-40℃至125℃.封裝形式:LPLCC封裝JW陶瓷熔封雙列直插,有窗口P塑料雙列直插PQ塑料四面引線扁平封裝W大圓片SL14腿微型封裝-150milJN陶瓷熔封雙列直插,無窗口SM8腿微型封裝-207milSN8腿微型封裝-150milVS超微型封裝8mmX13.4mmSO微型封裝-300milST薄型縮小的微型封裝-4.4nunSP橫向縮小型塑料雙列直插CL68腿陶瓷四面引線,帶窗口SS縮小型微型封裝PT薄型四面引線扁平封裝TS薄型微型封裝8mmX20mmTQ薄型四面引線扁平封裝當(dāng)今單片機(jī)廠商琳瑯滿目,產(chǎn)品性能各異。針對(duì)具體情況,我們應(yīng)選何種型號(hào)呢?首先,我們來弄清兩個(gè)概念:集中指令集(CISC)和精簡(jiǎn)指令集(RISC)。采用CISC結(jié)構(gòu)的單片機(jī)數(shù)據(jù)線和指令線分時(shí)復(fù)用,即所謂馮.諾伊曼結(jié)構(gòu)。它的指令豐富,功能較強(qiáng),但取指令和取數(shù)據(jù)不能同時(shí)進(jìn)行,速度受限,價(jià)格亦高。采用RISC結(jié)構(gòu)的單片機(jī)數(shù)據(jù)線和指令線分離,即所謂哈佛結(jié)構(gòu)。這使得取指令和取數(shù)據(jù)可同時(shí)進(jìn)行,且由于一般指令線寬于數(shù)據(jù)線,使其指令較同類CISC單片機(jī)指令包含更多的處理信息,執(zhí)行效率更高,速度亦更快。同時(shí),這種單片機(jī)指令多為單字節(jié),程序存儲(chǔ)器的空間利用率大大提高,有利于實(shí)現(xiàn)超小型化。屬于CISC結(jié)構(gòu)的單片機(jī)有Intel8051系列、Motorola和M68HC系列、Atmel的AT89系列、臺(tái)灣Winbond(華邦)W78系列、荷蘭Pilips的PCF80C51系列等;屬于RISC結(jié)構(gòu)的有Microchip公司的PIC系列、Zilog的Z86系列、Atmel的AT90S系列、韓國三星公司的KS57c系列4位單片機(jī)、臺(tái)灣義隆的EM-78系列等。一般來說,控制關(guān)系較簡(jiǎn)單的小家電,可以采用RISC型單片機(jī);控制關(guān)系較復(fù)雜的場(chǎng)合,如通訊產(chǎn)品、工業(yè)控制系統(tǒng)應(yīng)采用CISC單片機(jī)。不過,RISC單片機(jī)的迅速完善,使其佼佼者在控制關(guān)系復(fù)雜的場(chǎng)合也毫不遜色。根據(jù)程序存儲(chǔ)方式的不同,單片機(jī)可分為EPROM、OTP(一次可編程)、QTP(掩膜)三種。我國一開始都采用ROMless型單片機(jī)(片內(nèi)無ROM,需片外配EPROM),對(duì)單片機(jī)的普及起了很大作用,但這種強(qiáng)調(diào)接口的單片機(jī)無法廣泛應(yīng)用,甚至走入了誤區(qū)。如單片機(jī)的應(yīng)用一味強(qiáng)調(diào)接口,外接I/O及存儲(chǔ)器,便失去了單片機(jī)的特色。目前單片機(jī)大都將程序存儲(chǔ)體置于其內(nèi),給應(yīng)用帶來了極大的方便。值得一提的是,以往OTP型單片機(jī)的價(jià)格是QTP的3倍,而現(xiàn)在已降至1.5—L2倍,選用OTP型以免訂貨周期、批量的麻煩是可取的。PIC系列單片機(jī)的優(yōu)勢(shì)自從我2006年接觸PIC單片機(jī)以來,便一直熱衷于這種單片機(jī)的開發(fā)與應(yīng)用PIC最大的特點(diǎn)是不搞單純的功能堆積,而是從實(shí)際出發(fā),重視產(chǎn)品的性能與價(jià)格比,靠發(fā)展多種型號(hào)來滿足不同層次的應(yīng)用要求。就實(shí)際而言,不同的應(yīng)用對(duì)單片機(jī)功能和資源的需求也是不同的。比如,一個(gè)摩托車的點(diǎn)火器需要一個(gè)I/O較少、RAM及程序存儲(chǔ)空間不大、可靠性較高的小型單片機(jī),若采用40腳且功能強(qiáng)大的單片機(jī),投資大不說,使用起來也不方便。PIC系列從低到高有幾十個(gè)型號(hào),可以滿足各種需要。其中,PIC12c508單片機(jī)僅有8個(gè)引腳,是世界上最小的單片機(jī)。該型號(hào)有512字節(jié)ROM、25字節(jié)RAM、一個(gè)8位定時(shí)器、一根輸入線、5根I/O線,市面售價(jià)在3-6元人人民幣。這樣一款單片機(jī)在象摩托車點(diǎn)火器這樣的應(yīng)用無疑是非常適合。PIC的高檔型號(hào),如PIC16c74(尚不是最高檔型號(hào))有40個(gè)引腳,其內(nèi)部資源為ROM共4K、192字節(jié)RAM、8路A/D、3個(gè)8位定時(shí)器、2個(gè)CCP模塊、三個(gè)串行口、1個(gè)并行口、11個(gè)中斷源、33個(gè)I/O腳。這樣一個(gè)型號(hào)可以和其它品牌的高檔型號(hào)媲美。精簡(jiǎn)指令使其執(zhí)行效率大為提高。PIC系列8位CMOS單片機(jī)具有獨(dú)特的RISC結(jié)構(gòu),數(shù)據(jù)總線和指令總線分離的哈佛總線(Harvard)結(jié)構(gòu),使指令具有單字長(zhǎng)的特性,且允許指令碼的位數(shù)可多于8位的數(shù)據(jù)位數(shù),這與傳統(tǒng)的采用CISC結(jié)構(gòu)的8位單片機(jī)相比,可以達(dá)到2:1的代碼壓縮,速度提高4倍。產(chǎn)品上市零等待(Zerotimetomarket)0采用PIC的低價(jià)OTP型芯片,可使單片機(jī)在其應(yīng)用程序開發(fā)完成后立刻使該產(chǎn)品上市。PIC有優(yōu)越開發(fā)環(huán)境。OTP單片機(jī)開發(fā)系統(tǒng)的實(shí)時(shí)性是一個(gè)重要的指標(biāo),象普通51單片機(jī)的開發(fā)系統(tǒng)大都采用高檔型號(hào)仿真低檔型號(hào),其實(shí)時(shí)性不盡理想。PIC在推出一款新型號(hào)的同時(shí)推出相應(yīng)的仿真芯片,所有的開發(fā)系統(tǒng)由專用的仿真芯片支持,實(shí)時(shí)性非常好。就我個(gè)人的經(jīng)驗(yàn)看,還沒有出現(xiàn)過仿真結(jié)果與實(shí)際運(yùn)行結(jié)果不同的情況。其引腳具有防瞬態(tài)能力,通過限流電阻可以接至220V交流電源,可直接與繼電器控制電路相連,無須光電耦合器隔離,給應(yīng)用帶來極大方便。徹底的保密性。PIC以保密熔絲來保護(hù)代碼,用戶在燒入代碼后熔斷熔絲,別人再也無法讀出,除非恢復(fù)熔絲。目前,PIC采用熔絲深埋工藝,恢復(fù)熔絲的可能性極小。自帶看門狗定時(shí)器,可以用來提高程序運(yùn)行的可靠性。睡眠和低功耗模式。雖然PIC在這方面已不能與新型的TI—MSP430相比,但在大多數(shù)應(yīng)用場(chǎng)合還是能滿足需要的。Microchip基于精簡(jiǎn)指令集計(jì)算(RISC)的PlCmicro系列單片機(jī)是為要求高性能而低價(jià)格的用戶設(shè)計(jì)的。PlCmicro系列單片機(jī)家族由130多種產(chǎn)品組成,集多種存儲(chǔ)器配置,低電壓低功率,小引腳及易于使用等多種特點(diǎn)于一身。在我們8位MCU引腳的微小空間里封裝有大量的信息。隨著您設(shè)計(jì)的復(fù)雜化,您所寫的程序代碼以后可以輕易地轉(zhuǎn)換到具有更多外圍資源的較大的MicrochipMCU中去。PlCmicroMCU家族中的所有產(chǎn)品都是無間隙過渡的,在嵌入式設(shè)計(jì)中可完全向上兼容。如果您已經(jīng)知道設(shè)計(jì)應(yīng)用產(chǎn)品所需的單片機(jī)規(guī)格,您就可通過Microchip的參數(shù)搜索引擎按照相應(yīng)的條件進(jìn)行搜索并選用相應(yīng)的產(chǎn)品。在您的選擇過程中所需用到的條件為:編程存儲(chǔ)器大小,數(shù)據(jù)RAM,存儲(chǔ)器類型以及封裝類型。如果您對(duì)Microchip的PlCmicroMCU還不熟悉的話,以下介紹將幫助您了解。PlCmicroMCU將高性能,低價(jià)格,封裝尺寸小,提供最高性價(jià)比等特點(diǎn)集于一身,提供5個(gè)家族的8位單片機(jī)產(chǎn)品,以最好地滿足您的需要。PIC12CXXX家族:8引腳12/14位程序詞PIC12CXXX家族產(chǎn)品為Microchip功能強(qiáng)大的基于RISC的PlCmicro系列8引腳DIP及SOIC封裝。PIC12CXXX產(chǎn)品具有12或14位寬指令集,2.5V低運(yùn)行電壓,小封裝引腳,中斷處理,深硬件堆棧,多通道以及EEPR0M數(shù)據(jù)存儲(chǔ)器。這些智能級(jí)特性由于價(jià)格與尺寸的原因在以前的產(chǎn)品中是不具備的。PIC16c5X家族:12位程序詞PIC16C5X家族具有全套基礎(chǔ)產(chǎn)品,為您提供最有效的價(jià)格解決方案。PIC16c5X產(chǎn)品具備12位寬指令集,目前提供14,18,20及28引腳封裝。在選用SOIC與SSOP封裝時(shí),產(chǎn)品的引腳所占據(jù)的空間是最小的。低至2.0V運(yùn)行的低壓OTPMCU使產(chǎn)品成為電池驅(qū)動(dòng)應(yīng)用產(chǎn)品的理想選擇。另外,PIC16HV5XX在直接應(yīng)用電池時(shí)最高可運(yùn)行至15VoPIC16CXXX家族:14位程序詞在推出了新的PIC16CXXX家族成員后,Microchip現(xiàn)已在該產(chǎn)業(yè)中具備向單片機(jī)提供最高性能的12位模擬數(shù)字轉(zhuǎn)換器能力的供應(yīng)商。PIC16CXXX家族可提供從18引腳至68引腳封裝,以及由低級(jí)至高級(jí)的外圍集成的一系列產(chǎn)品。該家族具備14位寬指令集,中斷處理能力及8級(jí)硬件深堆棧。PIC16XXX家族提供了高性能及多功能的中檔應(yīng)用產(chǎn)品,以適應(yīng)當(dāng)今市場(chǎng)的價(jià)格競(jìng)爭(zhēng)。PIC17CXXX家族:16位程序詞PIC17CXXX家族將PlCmicroMCU的高性能RISC結(jié)構(gòu)擴(kuò)展為16位指令詞,增強(qiáng)型指令集與強(qiáng)大的矢量中斷處理能力。強(qiáng)大的隊(duì)列式精確在片外設(shè)特性提供了能適應(yīng)更多應(yīng)用場(chǎng)合的各種性能。PIC18CXXX家族:增強(qiáng)型16位程序詞PIC18CXXX家族產(chǎn)品具有高性能,CMOS,集成了模擬數(shù)字(A/D)轉(zhuǎn)換器的全靜態(tài)MCU等特點(diǎn)。所有PIC18CXXX的MCU均應(yīng)用了先進(jìn)的RISCoPIC18CXXX具備增強(qiáng)型中心特性,32位深堆棧,以及內(nèi)外多中斷源。Harvard系列中的分離指令與數(shù)據(jù)總線允許16位寬指令詞與獨(dú)立8位寬數(shù)據(jù)。兩級(jí)指令通道允許所有指令在一個(gè)周期內(nèi)執(zhí)行,除非子程序中設(shè)定必須在兩個(gè)周期內(nèi)完成。精簡(jiǎn)指令集共有77條指令。另外,一個(gè)大寄存器組使采用了結(jié)構(gòu)性創(chuàng)新的MCU達(dá)到10MIPS的極高的性能。PIC18CXXX家族具備的特殊特性能減少外部組件以降低成本,增強(qiáng)系統(tǒng)可靠性并降低功耗。這些特性包括可編程低壓檢測(cè)(LVD)及可編程Brown-Out檢測(cè)(BOD)PIC單片機(jī)C語言編程簡(jiǎn)介用C語言來開發(fā)單片機(jī)系統(tǒng)軟件最大的好處是編寫代碼效率高、軟件調(diào)試直觀、維護(hù)升級(jí)方便、代碼的重復(fù)利用率高、便于跨平臺(tái)的代碼移植等等,因此c語言編程在單片機(jī)系統(tǒng)設(shè)計(jì)中已得到越來越廣泛的運(yùn)用。針對(duì)PIC單片機(jī)的軟件開發(fā),同樣可以用C語百實(shí)現(xiàn)。但在單片機(jī)上用C語言寫程序和在PC機(jī)上寫程序絕對(duì)不能簡(jiǎn)單等同。現(xiàn)在的PC機(jī)資源十分豐富,運(yùn)算能力強(qiáng)大,因此程序員在寫PC機(jī)的應(yīng)用程序時(shí)幾乎不用關(guān)心編譯后的可執(zhí)行代碼在運(yùn)行過程中需要占用多少系統(tǒng)資源,也基本不用擔(dān)心運(yùn)行效率有多高。寫單片機(jī)的C程序最關(guān)鍵的一點(diǎn)是單片機(jī)內(nèi)的資源非常有限,控制的實(shí)時(shí)性要求又很高,因此,如果沒有對(duì)單片機(jī)體系結(jié)構(gòu)和硬件資源作詳盡的了解,以筆者的愚見認(rèn)為是無法寫出高質(zhì)量實(shí)用的C語言程序。這就是為什么前面所有章節(jié)中的的示范代碼全部用基礎(chǔ)的匯編指令實(shí)現(xiàn)的原因,希望籍此能使讀者對(duì)PIC單片機(jī)的指令體系和硬件資源有深入了解,在這基礎(chǔ)之上再來討論c語言編程,就有水到渠成的感覺。本書圍繞中檔系列PIC單片機(jī)來展開討論,Microchip公司自己沒有針對(duì)中低檔系列PIC單片機(jī)的C語言編譯器,但很多專業(yè)的第三方公司有眾多支持PIC單片機(jī)的C語言編譯器提供,常見的有Hitech、CCS>IAR、Bytecraft等公司。其中筆者最常用的是Hitech公司的PICC編譯器,它穩(wěn)定可靠,編譯生成的代碼效率高,在用PIC單片機(jī)進(jìn)行系統(tǒng)設(shè)計(jì)和開發(fā)的工程師群體中得到廣泛認(rèn)可。其正式完全版軟件需要購
置,但在其網(wǎng)站上有限時(shí)的試用版供用戶評(píng)估。另外,Hitech公司針對(duì)廣大PIC的業(yè)余愛好者和初學(xué)者還提供了完全免費(fèi)的學(xué)習(xí)版PICC-Lite編譯器套件,它的使用方式和完全版相同,只是支持的PIC單片機(jī)型號(hào)限制在PIC16F84、PIC16F877和PIC16F628等幾款。這幾款Flash型的單片機(jī)因其所具備的豐富的片上資源而最適用于單片機(jī)學(xué)習(xí)入門,因此筆者建議感興趣的讀者可從PICC-Lite入手掌握PIC單片機(jī)的C語言編程。在此列出幾個(gè)主要的針對(duì)PIC單片機(jī)的C編譯器相關(guān)連接網(wǎng)址,供讀者參考:Hitech-PICC:Hitech-PICC:IAR:CCS:/picc.shtmlByteCraft:www.bytecraft,com/mpccaps.html本章將介紹Hitech-PICC編譯器的一些基本概念,由于篇幅所限將不涉及C語言的標(biāo)準(zhǔn)語法和基礎(chǔ)知識(shí)介紹,因?yàn)樵谶@些方面都有大量的書籍可以參考。重點(diǎn)突出針對(duì)PIC單片機(jī)的特點(diǎn)而所需要特別注意的地方。11.2Hitech-PICC編譯器PICC基本上符合ANSI標(biāo)準(zhǔn),除了一點(diǎn):它不支持函數(shù)的遞歸調(diào)用。其主要原因是因?yàn)镻ic單片機(jī)特殊的堆棧結(jié)構(gòu)。在前面介紹PIC單片機(jī)架構(gòu)時(shí)已經(jīng)詳細(xì)說明了PIC單片機(jī)中的堆棧是硬件實(shí)現(xiàn)的,其深度已隨芯片而固定,無法實(shí)現(xiàn)需要大量堆棧操作的遞歸算法;另外在PIC單片機(jī)中實(shí)現(xiàn)軟件堆棧的效率也不是很高,為此,PICC編譯器采用一種叫做“靜態(tài)覆蓋”的技術(shù)以實(shí)現(xiàn)對(duì) c語言函數(shù)中的局部變量分配固定的地址空間。經(jīng)這樣處理后產(chǎn)生出的機(jī)器代碼效率很高,按筆者實(shí)際使用的體會(huì),當(dāng)代碼量超過4K字后,C語言編譯出的代碼長(zhǎng)度和全部用匯編代碼實(shí)現(xiàn)時(shí)的差別已經(jīng)不是很大(<10%),當(dāng)然前提是在整個(gè)C代碼編寫過程中須時(shí)時(shí)處處注意所編寫語句的效率,而如果沒有對(duì)PIC單片機(jī)的內(nèi)核結(jié)構(gòu)、各功能模塊及其匯編指令深入了解,要做到這點(diǎn)是很難的。11.3MPLAB-IDE內(nèi)掛接PICCPICC編譯器可以直接掛接在MPLAB-IDE集成開發(fā)平臺(tái)下,實(shí)現(xiàn)一體化的編譯連接和原代碼調(diào)試。使用MPLAB-IDE內(nèi)的調(diào)試工具ICE2000>ICD2和軟件模擬器都可以實(shí)現(xiàn)原代碼級(jí)的程序調(diào)試,非常方便。首先必須在你的計(jì)算機(jī)中安裝PICC編譯器,無論是完全版還是學(xué)習(xí)版都可以和MPLAB-IDE掛接。安裝成功后可以進(jìn)入IDE,選擇菜單項(xiàng)ProjectSetLanguageToolLocations…,打開語言工具掛接設(shè)置對(duì)話框,如圖11-1所示:圖11-1MPLAB-IDE語言工具設(shè)置對(duì)話框在對(duì)話框中選擇“HI-TECHPICCToolsuite”欄,展開可執(zhí)行文件組“Executable”后,列出了將被MPLAB-IDE 后臺(tái)調(diào)用的編譯器所用到的所有可執(zhí)行文件,其中有匯編編譯器“PPCCAssembler">C原程序編譯器“PICCCompiler”和連接定位程序“PICCLinker”。同時(shí)在此列表中還顯示了對(duì)應(yīng)的可執(zhí)行程序名,請(qǐng)注意在這里都是都是C.EXE"。用鼠標(biāo)分別點(diǎn)擊選中這三項(xiàng)可執(zhí)行文件,觀察對(duì)話框下面“Location”一欄中顯示的文件路徑,用“Browse…”按紐,從計(jì)算機(jī)中已經(jīng)安裝的PICC編譯器文件夾中選擇PICC.EXE文件。實(shí)際上PICC.EXE只是一個(gè)調(diào)度管理程序,它會(huì)按照所輸入的文件擴(kuò)展名自動(dòng)調(diào)用對(duì)應(yīng)的編譯器和連接器,用戶要注意的是C語言原程序擴(kuò)展名用“.c”,匯編原程序用“.as”即可。工具掛接完成后,在建立項(xiàng)目時(shí)可以選擇語言工具為“HI-TECHPICC”,具體步驟可以參閱第三章3.1.3節(jié),此處不再重復(fù)。項(xiàng)目建立完成后可以加入C或匯編原程序,也可以加入已有的庫文件或已經(jīng)編譯的目標(biāo)文件。最常見的是只加入C原程序。用C語言編程的好處是可以實(shí)現(xiàn)模塊化編程。程序編寫者應(yīng)盡量把相互獨(dú)立的控制任務(wù)用多個(gè)獨(dú)立的c原程序文件實(shí)現(xiàn),如果程序量較大,一般不要把所有的代碼寫在一個(gè)文件內(nèi)。圖11-2列出的是筆者建立的一個(gè)項(xiàng)目中所有C原程序模塊,其中主控、數(shù)值計(jì)算、12c總線操作、命令按鍵處理和液晶顯示驅(qū)動(dòng)等不同的功能分別在不同的獨(dú)立的原程序模塊中實(shí)現(xiàn)。圖11-2C語言多模塊編程PIC單片機(jī)的C語言原程序基本框架基于PICC編譯環(huán)境編寫PIC單片機(jī)程序的基本方式和標(biāo)準(zhǔn)C程序類似,程序一般由以下幾個(gè)主要部分組成:&01540; 在程序的最前面用#include預(yù)處理指令引用包含頭文件,其中必須包含一個(gè)編譯器提供的“pic.h”文件,實(shí)現(xiàn)單片機(jī)內(nèi)特殊寄存器和其它特殊符號(hào)的聲明;
&01540;用&01540;用“_CONFIG”預(yù)處理指令定義芯片的配置位;&01540; 聲明本模塊內(nèi)被調(diào)用的所有函數(shù)的類型,PICC將對(duì)所調(diào)用的函數(shù)進(jìn)行嚴(yán)格的類型匹配檢查;&01540; 定義全局變量或符號(hào)替換;&01540; 實(shí)現(xiàn)函數(shù)(子程序),特別注意main函數(shù)必須是一個(gè)沒有返回的死循環(huán)。下面的例11-1為一個(gè)C原程序的范例,供大家參考。ftinclude 〃包含單片機(jī)內(nèi)部資源預(yù)定義ftinclude“pc68.h”〃包含自定義頭文件〃定義芯片工作時(shí)的配置位CONFIG(HS&PROTECT&PWRTEN&BOREN&WDTDIS);〃聲明本模塊中所調(diào)用的函數(shù)類型voidSetSFR(void);voidClock(void);voidKeyScan(void);voidMeasure(void);voidLCDTest(void);voidLCDDisp(unsignedchar);〃定義變量unsignedcharsecond,minute,hour;bitflagl,flag2;〃函數(shù)和子程序voidmain(void){SetSFR();PORTC=0x00;TMR1H+:TMR1H_CONST;LED1=LED_OFF;LCD_Test();〃程序工作主循環(huán)while(1){asm("clrwdt");Clock();KeyScan();Measure();SetSFRO;〃清看門狗〃更新時(shí)鐘〃掃描鍵盤〃數(shù)據(jù)測(cè)量〃刷新特殊功能寄存器11.5PICC中的變量定義例11-1C語言原程序框架舉例.1PICC中的基本變量類型PICC遵循Little-endian標(biāo)準(zhǔn),多字節(jié)變量的低字節(jié)放在存儲(chǔ)空間的低地址,高字節(jié)放在IW]地址。PICC中的高級(jí)變量基于表11-1的基本變量,除了bit型位變量外,PICC完全支持?jǐn)?shù)組、結(jié)構(gòu)和聯(lián)合等復(fù)合型高級(jí)變量,這和標(biāo)準(zhǔn)的C語言所支持的高級(jí)變量類型沒有什么區(qū)別。例如:數(shù)組:unsignedintdata[10];結(jié)構(gòu):structcommlnData{unsignedcharinBuff[8];unsignedchargetPtr,putPtr;};聯(lián)合:unionintByte{unsignedcharc⑵;unsignedinti;};例11-2C語言高級(jí)變量舉例PICC對(duì)數(shù)據(jù)寄存器bank的管理為了使編譯器產(chǎn)生最高效的機(jī)器碼,PICC把單片機(jī)中數(shù)據(jù)寄存器的bank問題交由編程員自己管理,因此在定義用戶變量時(shí)你必須自己決定這些變量具體放在哪一個(gè)bank中。如果沒有特別指明,所定義的變量將被定位在bankO,例如下面所定義的這些變量:unsignedcharbuffer[32];bitflagl,flag2;floatval[8];除了bankO內(nèi)的變量聲明時(shí)不需特殊處理外,定義在其它bank內(nèi)的變量前面必須加上相應(yīng)的bank序號(hào),例如:banklunsignedcharbuffer[32]; 〃變量定位在bankl中bank2bitflagl,flag2;bank3floatval[8];〃變量定位在bank2中〃變量定位在bank3中中檔系列PIC單片機(jī)數(shù)據(jù)寄存器的一個(gè)bank大小為128字節(jié),刨去前面若干字節(jié)的特殊功能寄存器區(qū)域,在C語言中某一bank內(nèi)定義的變量字節(jié)總數(shù)不能超過可用RAM字節(jié)數(shù)。如果超過bank容量,在最后連接時(shí)會(huì)報(bào)錯(cuò),大致信息如下:Error[000] :Can'tfind0xl2Cwordsforpsectrbss_linsegmentBANK1連接器告訴你總共有0xl2C(300)個(gè)字節(jié)準(zhǔn)備放到bankl中但bankl容量不夠。顯然,只有把一部分原本定位在bankl中的變量改放到其它bank中才能解決此問題。雖然變量所在的bank定位必須由編程員自己決定,但在編寫原程序時(shí)進(jìn)行變量存取操作前無需再特意編寫設(shè)定bank的指令。C編譯器會(huì)根據(jù)所操作的對(duì)象自動(dòng)生成對(duì)應(yīng)bank設(shè)定的匯編指令。為避免頻繁的bank切換以提高代碼效率,盡量把實(shí)現(xiàn)同一任務(wù)的變量定位在同一個(gè)bank內(nèi);對(duì)不同bank內(nèi)的變量進(jìn)行讀寫操作時(shí)也盡量把位于相同bank內(nèi)的變量歸并在一起進(jìn)行連續(xù)操作。PICC中的局部變量PICC把所有函數(shù)內(nèi)部定義的auto型局部變量放在bankOo為節(jié)約寶貴的存儲(chǔ)空間,它采用了一種被叫做“靜態(tài)覆蓋”的技術(shù)來實(shí)現(xiàn)局部變量的地址分配。其大致的原理是在編譯器編譯原代碼時(shí)掃描整個(gè)程序中函數(shù)調(diào)用的嵌套關(guān)系和層次,算出每個(gè)函數(shù)中的局部變量字
節(jié)數(shù),然后為每個(gè)局部變量分配一個(gè)固定的地址,且按調(diào)用嵌套的層次關(guān)系各變量的地址可以相互重疊。利用這一技術(shù)后所有的動(dòng)態(tài)局部變量都可以按已知的固定地址地進(jìn)行直接尋址,用PIC匯編指令實(shí)現(xiàn)的效率最高,但這時(shí)不能出現(xiàn)函數(shù)遞歸調(diào)用。PICC在編譯時(shí)會(huì)嚴(yán)格檢查遞歸調(diào)用的問題并認(rèn)為這是一個(gè)嚴(yán)重錯(cuò)誤而立即終止編譯過程。既然所有的局部變量將占用banko的存儲(chǔ)空間,因此用戶自己定位在bankO內(nèi)的變量字節(jié)數(shù)將受到一定的限制,在實(shí)際使用時(shí)需注意。11.5.511.5.5PICC中的位變量bit型位變量只能是全局的或靜態(tài)的。PICC將把定位在同一bank內(nèi)的8個(gè)位變量合并成一個(gè)字節(jié)存放于一個(gè)固定地址。因此所有針對(duì)位變量的操作將直接使用PIC單片機(jī)的位操作匯編指令高效實(shí)現(xiàn)?;诖?,位變量不能是局部自動(dòng)型變量,也無法將其組合成復(fù)合型高級(jí)變量。PICC對(duì)整個(gè)數(shù)據(jù)存儲(chǔ)空間實(shí)行位編址,0x000單元的第0位是位地址0x0000,以此后推,每個(gè)字節(jié)有8個(gè)位地址。編制位地址的意義純粹是為了編譯器最后產(chǎn)生匯編級(jí)位操作指令而用,對(duì)編程人員來說基本可以不管。但若能了解位變量的位地址編址方式就可以在最后程序調(diào)試時(shí)方便地查找自己所定義的位變量,如果一個(gè)位變量flagl被編址為0x123,那么實(shí)際的存儲(chǔ)空間位于:字節(jié)地址=0x123/8=0x24位偏移=0xl23%8=3即flagl位變量位于地址為0x24字節(jié)的第3位。在程序調(diào)試時(shí)如果要觀察flagl的變化,必須觀察地址為0x24的字節(jié)而不是0xl23oPIC單片機(jī)的位操作指令是非常高效的。因此,PICC在編譯原代碼時(shí)只要有可能,對(duì)普通變量的操作也將以最簡(jiǎn)單的位操作指令來實(shí)現(xiàn)。假設(shè)一個(gè)字節(jié)變量tmp最后被定位在地址0x20,那么tmp|-0x80tmp&=0xf7=>bsf=>bcf0x20,70x20,3if(tmp&Oxfe)=>btfsc0x20,0即所有只對(duì)變量中某一位操作的C語句代碼將被直接編譯成匯編的位操作指令。雖然編程時(shí)可以不用太關(guān)心,但如果能了解編譯器是如何工作的,那將有助于引導(dǎo)我們寫出高效簡(jiǎn)介的C語言原程序。在有些應(yīng)用中需要將一組位變量放在同一個(gè)字節(jié)中以便需要時(shí)一次性地進(jìn)行讀寫,這一功能可以通過定義一個(gè)位域結(jié)構(gòu)和一個(gè)字節(jié)變量的聯(lián)合來實(shí)現(xiàn),例如:union{struct{unsignedbO:1;unsignedbl:1;unsignedb2:1;unsignedb3:1;unsignedb4:1;unsignedb5:1;unsigned:2;〃最高兩位保留}oneBit;unsignedcharallBits;}myFlag;例11-3 定義位變量于同一字節(jié)需要存取其中某一位時(shí)可以myFlag.oneBit.b3=l;//b3位置1一次性將全部位清零時(shí)可以myFlag.allBits=0; 〃全部位變量清0當(dāng)程序中把非位變量進(jìn)行強(qiáng)制類型轉(zhuǎn)換成位變量時(shí),要注意編譯器只對(duì)普通變量的最低位做判別:如果最低位是0,則轉(zhuǎn)換成位變量0;如果最低位是1,則轉(zhuǎn)換成位變量lo而標(biāo)準(zhǔn)的ANSI-C做法是判整個(gè)變量值是否為0o另外,函數(shù)可以返回一個(gè)位變量,實(shí)際上此返回的位變量將存放于單片機(jī)的進(jìn)位位中帶出返回。11.5.6PICC中的浮點(diǎn)數(shù)PICC中描述浮點(diǎn)數(shù)是以IEEE-754標(biāo)準(zhǔn)格式實(shí)現(xiàn)的。此標(biāo)準(zhǔn)下定義的浮點(diǎn)數(shù)為32位長(zhǎng),在單片機(jī)中要用4個(gè)字節(jié)存儲(chǔ)。為了節(jié)約單片機(jī)的數(shù)據(jù)空間和程序空間,PICC專門提供了
一種長(zhǎng)度為24位的截短型浮點(diǎn)數(shù),它損失了浮點(diǎn)數(shù)的一點(diǎn)精度,但浮點(diǎn)運(yùn)算的效率得以提高。在程序中定義的float型標(biāo)準(zhǔn)浮點(diǎn)數(shù)的長(zhǎng)度固定為24位,雙精度double型浮點(diǎn)數(shù)一般也是24位長(zhǎng),但可以在程序編譯選項(xiàng)中選擇double型浮點(diǎn)數(shù)為32位,以提高計(jì)算的精度。一般控制系統(tǒng)中關(guān)心的是單片機(jī)的運(yùn)行效率,因此在精度能夠滿足的前提下盡量選擇24位的浮點(diǎn)數(shù)運(yùn)算。11.5.7PICC11.5.7PICC中變量的絕對(duì)定位首先必須強(qiáng)調(diào),在用c語言寫程序時(shí)變量一般由編譯器和連接器最后定位,在寫程序之時(shí)無需知道所定義的變量具體被放在哪個(gè)地址(除了bank必須聲明)。真正需要絕對(duì)定位的只是單片機(jī)中的那些特殊功能寄存器,而這些寄存器的地址定位在PICC編譯環(huán)境所提供的頭文件中已經(jīng)實(shí)現(xiàn),無需用戶操心。編程員所要了解的也就是PICC是如何定義這些特殊功能寄存器和其中的相關(guān)控制位的名稱。好在PICC的定義標(biāo)準(zhǔn)基本上按照芯片的數(shù)據(jù)手冊(cè)中的名稱描述進(jìn)行,這樣就秉承了變量命名的一貫性。一個(gè)變量絕對(duì)定位的例子如下:unsignedchartmpData@0x20;//tmpData定位在地址0x20千萬注意,PICC對(duì)絕對(duì)定位的變量不保留地址空間。換句話說,上面變量tmpData的地址是0x20,但最后0x20處完全有可能又被分配給了其它變量使用,這樣就發(fā)生了地址沖突。因此針對(duì)變量的絕對(duì)定位要特別小心。從筆者的應(yīng)用經(jīng)驗(yàn)看,在一般的程序設(shè)計(jì)中用戶自定義的變量實(shí)在是沒有絕對(duì)定位的必要。如果需要,位變量也可以絕對(duì)定位。但必須遵循上面介紹的位變量編址的方式。如果一個(gè)普通變量已經(jīng)被絕對(duì)定位,那么此變量中的每個(gè)數(shù)據(jù)位就可以用下面的計(jì)算方式實(shí)現(xiàn)位變
量指派://tmpData定位在地址unsignedchartmpData@0x20//tmpData定位在地址0x20bittmpBitO@tmpData*8+0;//tmpBitObittmpBitO@tmpData*8+0;//tmpBitO對(duì)應(yīng)于tmpData第0位//tmpBitO對(duì)應(yīng)于//tmpBitO//tmpBitO對(duì)應(yīng)于//tmpBitO對(duì)應(yīng)于tmpData第1位bittmpBit2@tmpData*8+2;tmpData第2位如果tmpData事先沒有被絕對(duì)定位,那就不能用上面的位變量定位方式。
11.5.8PICC11.5.8PICC的其它變量修飾關(guān)鍵詞&01540;extern一外部變量聲明如果在一個(gè)C程序文件中要使用一些變量但其原型定義寫在另外的文件中,那么在本文件中必須將這些變量聲明成"extern”外部類型。例如程序文件codel.c中有如下定義:banklunsignedcharvarl,var2;〃定義了bankl中的兩個(gè)變量在另外一個(gè)程序文件code2.c中要對(duì)上面定義的變量進(jìn)行操作,則必須在程序的開頭定義:externbanklunsignedcharvarl,var2; 〃聲明位于bankl的外部變量&01540;volatile一易變型變量聲明PICC中還有一個(gè)變量修飾詞在普通的C語言介紹中一般是看不到的,這就是關(guān)鍵詞"volatile"o顧名思義,它說明了一個(gè)變量的值是會(huì)隨機(jī)變化的,即使程序沒有刻意對(duì)它進(jìn)行任何賦值操作。在單片機(jī)中,作為輸入的10端口其內(nèi)容將是隨意變化的;在中斷內(nèi)被修改的變量相對(duì)主程序流程來講也是隨意變化的;很多特殊功能寄存器的值也將隨著指令的運(yùn)行而動(dòng)態(tài)改變。所有這種類型的變量必須將它們明確定義成“volatile”類型,例如:volatileunsignedcharSTATUS@0x03;volatilebitcommFlag;"volatile"類型定義在單片機(jī)的 C語言編程中是如此的重要,是因?yàn)樗梢愿嬖V編譯器的優(yōu)化處理器這些變量是實(shí)實(shí)在在存在的,在優(yōu)化過程中不能無故消除。假定你的程序定義了一個(gè)變量并對(duì)其作了一次賦值,但隨后就再也沒有對(duì)其進(jìn)行任何讀寫操作,如果是非volatile型變量,優(yōu)化后的結(jié)果是這個(gè)變量將有可能被徹底刪除以節(jié)約存儲(chǔ)空間。另外一種情形是在使用某一個(gè)變量進(jìn)行連續(xù)的運(yùn)算操作時(shí),這個(gè)變量的值將在第一次操作時(shí)被復(fù)制到中間臨時(shí)變量中,如果它是非volatile型變量,則緊接其后的其它操作將有可能直接從臨時(shí)變量中取數(shù)以提高運(yùn)行效率,顯然這樣做后對(duì)于那些隨機(jī)變化的參數(shù)就會(huì)出問題。只要將其定義成volatile類型后,編譯后的代碼就可以保證每次操作時(shí)直接從變量地址處取數(shù)。
&01540;const&01540;const—常數(shù)型變量聲明如果變量定義前冠以“const”類型修飾,那么所有這些變量就成為常數(shù),程序運(yùn)行過程中不能對(duì)其修改。除了位變量,其它所有基本類型的變量或高級(jí)組合變量都將被存放在程序空間(ROM區(qū))以節(jié)約數(shù)據(jù)存儲(chǔ)空間。顯然,被定義在ROM區(qū)的變量是不能再在程序中對(duì)其進(jìn)行賦值修改的,這也是“const”的本來意義。實(shí)際上這些數(shù)據(jù)最終都將以“retlw”的指令形式存放在程序空間,但PICC會(huì)自動(dòng)編譯生成相關(guān)的附加代碼從程序空間讀取這些常數(shù),編程員無需太多操心。例如:constunsignedcharname口=“Thisisademo";//定義一個(gè)常量字符串如果定義了“const”類型的位變量,那么這些位變量還是被放置在RAM中,但程序不能對(duì)其賦值修改。本來,不能修改的位變量沒有什么太多的實(shí)際意義,相信大家在實(shí)際編程時(shí)不會(huì)大量用到。&01540;persistent一 非初始化變量聲明按照標(biāo)準(zhǔn)C語言的做法,程序在開始運(yùn)行前首先要把所有定義的但沒有預(yù)置初值的變量全部清零。PICC會(huì)在最后生成的機(jī)器碼中加入一小段初始化代碼來實(shí)現(xiàn)這一變量清零操作,且這一操作將在main函數(shù)被調(diào)用之前執(zhí)行。問題是作為一個(gè)單片機(jī)的控制系統(tǒng)有很多變量是不允許在程序復(fù)位后被清零的。為了達(dá)到這一目的,PICC提供了“persistent”修飾詞以聲明此類變量無需在復(fù)位時(shí)自動(dòng)清零,編程員應(yīng)該自己決定程序中的那些變量是必須聲明成“persisten”類型,而且須自己判斷什么時(shí)候需要對(duì)其進(jìn)行初始化賦值。例如:persistentunsignedcharhour,minute,second;〃定義時(shí)分秒變量經(jīng)常用到的是如果程序經(jīng)上電復(fù)位后開始運(yùn)行,那么需要將persistent型的變量初始化,如果是其它形式的復(fù)位,例如看門狗引發(fā)的復(fù)位,則無需對(duì)persistent型變量作任何修改。PIC單片機(jī)內(nèi)提供了各種復(fù)位的判別標(biāo)志,用戶程序可依具體設(shè)計(jì)靈活處理不同的復(fù)位情形。11.5.9PICC中的指針PICC中指針的基本概念和標(biāo)準(zhǔn)C語法沒有太多的差別。但是在PIC單片機(jī)這一特定的架構(gòu)上,指針的定義方式還是有幾點(diǎn)需要特別注意。&01540;指向RAM的指針如果是匯編語言編程,實(shí)現(xiàn)指針尋址的方法肯定就是用FSR寄存器,PICC也不例外。為了生成高效的代碼,PICC在編譯C原程序時(shí)將指向RAM的指針操作最終用FSR來實(shí)現(xiàn)間接尋址。這樣就勢(shì)必產(chǎn)生一個(gè)問題:FSR能夠直接連續(xù)尋址的范圍是256字節(jié)(bankO/1或bank2/3),要覆蓋最大512字節(jié)的內(nèi)部數(shù)據(jù)存儲(chǔ)空間,又該如何讓定義指針?PICC還是將這一問題留給編程員自己解決:在定義指針時(shí)必須明確指定該指針?biāo)m用的尋址區(qū)域,例如:unsignedchar*ptrO;〃①定義覆蓋bankO/1的指針bank2unsignedchar*ptrl;〃②定義覆蓋bank2/3的指針bank3unsignedchar*ptr2;〃③定義覆蓋bank2/3的指針上面定義了三個(gè)指針變量,其中①指針沒有任何bank限定,缺省就是指向bankO和bankl;②和③一個(gè)指明了bank2,另一個(gè)指明了bank3,但實(shí)際上兩者是一樣的,因?yàn)橐粋€(gè)指針可以同時(shí)覆蓋兩個(gè)bank的存儲(chǔ)區(qū)域。另外,上面三個(gè)指針變量自身都存放在bankO中。我們將在稍后介紹如何在其它bank中存放指針變量。既然定義的指針有明確的bank適用區(qū)域,在對(duì)指針變量賦值時(shí)就必須實(shí)現(xiàn)類型匹配,F(xiàn)面的指針賦值將產(chǎn)生一個(gè)致命錯(cuò)誤:unsignedchar*ptrO;bank2unsignedcharbuff[8];程序語句:〃定義指向bankO/1的指針〃定義bank2中的一個(gè)緩沖區(qū)ptrO二buff;〃錯(cuò)誤!試圖將bank2內(nèi)的變量地址賦給指向bankO/1的指針若出現(xiàn)此類錯(cuò)誤的指針操作,PICC在最后連接時(shí)會(huì)告知類似于下面的信息:Fixupoverflowinexpression(...)同樣的道理,若函數(shù)調(diào)用時(shí)用了指針作為傳遞參數(shù),也必須注意bank作用域的匹配,而這點(diǎn)往往容易被忽視。假定有下面的函數(shù)實(shí)現(xiàn)發(fā)送一個(gè)字符串的功能:voidSendMessage(unsignedchar*);那么被發(fā)送的字符串必須位于bankO或bankl中。如果你還要發(fā)送位于bank2或bank3內(nèi)的字符串,必須再另外單獨(dú)寫一個(gè)函數(shù):voidSendMessage_2(bank2unsignedchar*);這兩個(gè)函數(shù)從內(nèi)部代碼的實(shí)現(xiàn)來看可以一模一樣,但傳遞的參數(shù)類型不同。按筆者的應(yīng)用經(jīng)驗(yàn)體會(huì),如果你看到了“Fixupoverflow"的錯(cuò)誤指示,幾乎可以肯定是指針類型不匹配的賦值所至。請(qǐng)重點(diǎn)檢查程序中有關(guān)指針的操作。&01540;指向ROM常數(shù)的指針如果一組變量是已經(jīng)被定義在ROM區(qū)的常數(shù),那么指向它的指針可以這樣定義:constunsignedcharcompany[]=vMicrochipvconstunsignedchar*romPtr;程序中可以對(duì)上面的指針變量賦值和實(shí)現(xiàn)取數(shù)操作:romPtr=company;〃指針賦初值data=*romPtr++;〃取指針指向的一個(gè)數(shù),然后指針加1〃定義ROM中的常數(shù)〃定義指向ROM的指針反過來,下面的操作將是一個(gè)錯(cuò)誤,因?yàn)樵撝羔樦赶虻氖浅?shù)型變量,不能賦值。*romPtr=data;〃往指針指向的地址寫一個(gè)數(shù)&01540; 指向函數(shù)的指針單片機(jī)編程時(shí)函數(shù)指針的應(yīng)用相對(duì)較少,但作為標(biāo)準(zhǔn)C語法的一部分,PICC同樣支持函數(shù)指針調(diào)用。如果你對(duì)編譯原理有一定的了解,就應(yīng)該明白在PIC單片機(jī)這一特定的架構(gòu)上實(shí)現(xiàn)函數(shù)指針調(diào)用的效率是不高的:PICC將在RAM中建立一個(gè)調(diào)用返回表,真正的調(diào)用和返回過程是靠直接修改PC指針來實(shí)現(xiàn)的。因此,除非特殊算法的需要,建議大家盡量不要使用函數(shù)指針。&01540; 指針的類型修飾前面介紹的指針定義都是最基本的形式。和普通變量一樣,指針定義也可以在前面加上特殊類型的修飾關(guān)鍵詞,例如“persistent”、"volatile"等??紤]指針本身還要限定其作用域,因此PICC中的指針定義初看起來顯得有點(diǎn)復(fù)雜,但只要了解各部分的具體含義,理解一個(gè)指針的實(shí)際用圖就變得很直接。㈠bank修飾詞的位置含義前面介紹的一些指針有的作用于bankO/1,有的作用于bank2/3,但它們本身的存放位置全部在bankOo顯然,在一個(gè)程序設(shè)計(jì)中指針變量將有可能被定位在任何可用的地址空間,這時(shí),bank修飾詞出現(xiàn)的位置就是一個(gè)關(guān)鍵,看下面的例子:〃定義指向bankO/1的指針,指針變量為于bankO中unsignedchar*ptrO;〃定義指向bank2/3的指針,指針變量為于bankO中bank2unsignedchar*ptrO;〃定義指向bank2/3的指針,指針變量為于bankl中bank2unsignedchar*banklptrO;從中可以看出規(guī)律:前面的bank修飾詞指明了此指針的作用域;后面的bank修飾詞定義了此指針變量自身的存放位置。只要掌握了這一法則,你就可以定義任何作用域的指針且可以將指針變量放于任何bank中。㈡volatile、persistent和const修飾詞的位置含義如果能理解上面介紹的bank修飾詞的位置含義,實(shí)際上volatile>persistent和const這些關(guān)鍵詞出現(xiàn)在前后不同位置上的含義規(guī)律是和bank一詞相一致的。例如:〃定義指向bankO/1易變型字符變量的指針,指針變量位于bankO中且自身為非易變型volatileunsignedchar*ptrO;〃定義指向bank2/3非易變型字符變量的指針,指針變量位于bankl中且自身為易變型bank2unsignedchar*volatilebanklptrO;〃定義指向ROM區(qū)的指針,指針變量本身也是存放于ROM區(qū)的常數(shù)constunsignedchar*constptrO;亦即出現(xiàn)在前面的修飾詞其作用對(duì)象是指針?biāo)柑幍淖兞?;出現(xiàn)在后面的修飾詞其作用對(duì)象就是指針變量自己。11.6PICC中的子程序和函數(shù)中檔系列的PIC單片機(jī)程序空間有分頁的概念,但用C語言編程時(shí)基本不用太多關(guān)心代碼的分頁問題。因?yàn)樗泻瘮?shù)或子程序調(diào)用時(shí)的頁面設(shè)定(如果代碼超過一個(gè)頁面)都由編譯器自動(dòng)生成的指令實(shí)現(xiàn)。11.6.1函數(shù)的代碼長(zhǎng)度限制PICC決定了C原程序中的一個(gè)函數(shù)經(jīng)編譯后生成的機(jī)器碼一定會(huì)放在同一個(gè)程序頁面內(nèi)。中檔系列的PIC單片機(jī)其一個(gè)程序頁面的長(zhǎng)度是2K字,換句話說,用C語言編寫的任何一個(gè)函數(shù)最后生成的代碼不能超過2K字。一個(gè)良好的程序設(shè)計(jì)應(yīng)該有一個(gè)清晰的組織結(jié)構(gòu),把不同的功能用不同的函數(shù)實(shí)現(xiàn)是最好的方法,因此一個(gè)函數(shù)2K字長(zhǎng)的限制一般不會(huì)對(duì)程序代碼的編寫產(chǎn)生太多影響。如果為實(shí)現(xiàn)特定的功能確實(shí)要連續(xù)編寫很長(zhǎng)的程序,這時(shí)就必須把這些連續(xù)的代碼拆分成若干函數(shù),以保證每個(gè)函數(shù)最后編譯出的代碼不超過一個(gè)頁面空間。11.6.2調(diào)用層次的控制中檔系列PIC單片機(jī)的硬件堆棧深度為8級(jí),考慮中斷響應(yīng)需占用一級(jí)堆棧,所有函數(shù)調(diào)用嵌套的最大深度不要超過7級(jí)。編程員必須自己控制子程序調(diào)用時(shí)的嵌套深度以符合這一限制要求。PICC在最后編譯連接成功后可以生成一個(gè)連接定位映射文件(*.map),在此文件中有詳細(xì)的函數(shù)調(diào)用嵌套指示圖“callgraph”,建議大家要留意一下。其信息大致如下(取自于一示范程序的編譯結(jié)果):Callgraph:mainsize0,0offset0RightShiftC_Tasksize0,1offset0Iwtoftftmulsize0,0offset0ftunpacklftunpack2ftaddsize0,0offset0ftunpacklftunpack2ftdenorm例11-4C函數(shù)調(diào)用層次圖上面所舉的信息表明整個(gè)程序在正常調(diào)用子程序時(shí)嵌套最多為兩級(jí)(沒有考慮中斷)。因?yàn)閙ain函數(shù)不可能返回,故其不用計(jì)算在嵌套級(jí)數(shù)中。其中有些函數(shù)調(diào)用是編譯代碼時(shí)自動(dòng)加入的庫函數(shù),這些函數(shù)調(diào)用從C原程序中無法直接看出,但在此嵌套指示圖上則一目了然。11.6.3 函數(shù)類型聲明PICC在編譯時(shí)將嚴(yán)格進(jìn)行函數(shù)調(diào)用時(shí)的類型檢查。一個(gè)良好的習(xí)慣是在編寫程序代碼前先聲明所有用到的函數(shù)類型。例如:voidTask(void);unsignedcharTemperature(void);voidBIN2BCD(unsignedchar);voidTimeDisplay(unsignedchar,unsignedchar);這些類型聲明確定了函數(shù)的入口參數(shù)和返回值類型,這樣編譯器在編譯代碼時(shí)就能保證生成正確的機(jī)器碼。筆者在實(shí)際工作中有時(shí)碰到一些用戶聲稱發(fā)現(xiàn)C編譯器生成了錯(cuò)誤的代碼,最后究其原因就是因?yàn)闆]有事先聲明函數(shù)類型所致。建議大家在編寫一個(gè)函數(shù)的原代碼時(shí),立即將此函數(shù)的類型聲明復(fù)制到原文件的起始處,見例11T;或是復(fù)制到專門的包含頭文件中,再在每個(gè)原程序模塊中引用。
11.6.4中斷函數(shù)的實(shí)現(xiàn)11.6.4中斷函數(shù)的實(shí)現(xiàn)PICC可以實(shí)現(xiàn)C語言的中斷服務(wù)程序。中斷服務(wù)程序有一個(gè)特殊的定義方法:voidinterruptISR(void);其中的函數(shù)名“ISR”可以改成任意合法的字母或數(shù)字組合,但其入口參數(shù)和返回參數(shù)類型必須是“void”型,亦即沒有入口參數(shù)和返回參數(shù),且中間必須有一個(gè)關(guān)鍵詞"interrupt”。中斷函數(shù)可以被放置在原程序的任意位置。因?yàn)橐延嘘P(guān)鍵詞uinterruptn聲明,PICC在最后進(jìn)行代碼連接時(shí)會(huì)自動(dòng)將其定位到0x0004中斷入口處,實(shí)現(xiàn)中斷服務(wù)響應(yīng)。編譯器也會(huì)實(shí)現(xiàn)中斷函數(shù)的返回指令“retfie"。一個(gè)簡(jiǎn)單的中斷服務(wù)示范函數(shù)如下:voidinterruptISR(void)〃中斷服務(wù)程序if(TOIE&&TOIF)TOIF二0;〃在此加入TMR0中斷服務(wù)〃判TMRO中斷〃清除TMRO中斷標(biāo)志if(TMR1IE&&TMR1IF)〃判TMR1中斷TMR1IFO;〃在此加入TMR1中斷服務(wù)//清除TMR1中斷標(biāo)志〃中斷結(jié)束并返回例11-5C語言中斷函數(shù)舉例Pice會(huì)自動(dòng)加入代碼實(shí)現(xiàn)中斷現(xiàn)場(chǎng)的保護(hù),并在中斷結(jié)束時(shí)自動(dòng)恢復(fù)現(xiàn)場(chǎng),所以編程員無需象編寫匯編程序那樣加入中斷現(xiàn)場(chǎng)保護(hù)和恢復(fù)的額外指令語句。但如果在中斷服務(wù)程序中需要修改某些全局變量時(shí),是否需要保護(hù)這些變量的初值將由編程員自己決定和實(shí)施。用C語言編寫中斷服務(wù)程序必須遵循高效的原則:&01540; 代碼盡量簡(jiǎn)短,中斷服務(wù)強(qiáng)調(diào)的是一個(gè)“快”字。&01540; 避免在中斷內(nèi)使用函數(shù)調(diào)用。雖然PICC允許在中斷里調(diào)用其它函數(shù),但為了解決
遞歸調(diào)用的問題,此函數(shù)必須為中斷服務(wù)獨(dú)家專用。既如此,不妨把原本要寫在其它函數(shù)內(nèi)的代碼直接寫在中斷服務(wù)程序中。&01540; 避免在中斷內(nèi)進(jìn)行數(shù)學(xué)運(yùn)算。數(shù)學(xué)運(yùn)算將很有可能用到庫函數(shù)和許多中間變量,就算不出現(xiàn)遞歸調(diào)用的問題,光在中斷入口和出口處為了保護(hù)和恢復(fù)這些中間臨時(shí)變量就需要大量的開銷,嚴(yán)重影響中斷服務(wù)的效率。中檔系列PIC單片機(jī)的中斷入口只有一個(gè),因此整個(gè)程序中只能有一個(gè)中斷服務(wù)函數(shù)。11.6.5標(biāo)準(zhǔn)庫函數(shù)11.6.5標(biāo)準(zhǔn)庫函數(shù)PICC提供了較完整的C標(biāo)準(zhǔn)庫函數(shù)支持,其中包括數(shù)學(xué)運(yùn)算函數(shù)和字符串操作函數(shù)。在程序中使用這些現(xiàn)成的庫函數(shù)時(shí)需要注意的是入口參數(shù)必須在bankO中。如果需要用到數(shù)學(xué)函數(shù),則應(yīng)在程序前 “include”包含頭文件;如果要使用字符串操作函數(shù),就需要包含“include”頭文件。在這些頭文件中提供了函數(shù)類型的聲明。通過直接查看這些頭文件就可以知道PICC提供了哪些標(biāo)準(zhǔn)庫函數(shù)。C語言中常用的格式化打印函數(shù)“printf/sprintf”用在單片機(jī)的程序中時(shí)要特別謹(jǐn)慎。printf/sprintf是一個(gè)非常大的函數(shù),一旦使用,你的程序代碼長(zhǎng)度就會(huì)增加很多。除非是在編寫試驗(yàn)性質(zhì)的代碼,可以考慮使用格式化打印函數(shù)以簡(jiǎn)化測(cè)試程序;一般的最終產(chǎn)品設(shè)計(jì)都是自己編寫最精簡(jiǎn)的代碼實(shí)現(xiàn)特定格式的數(shù)據(jù)顯示和輸出。本來,在單片機(jī)應(yīng)用中輸出的數(shù)據(jù)格式都相對(duì)簡(jiǎn)單而且固定,實(shí)現(xiàn)起來應(yīng)該很容易。對(duì)于標(biāo)準(zhǔn)C語言的控制臺(tái)輸入(scanf)/輸出(printf)函數(shù),PICC需要用戶自己編寫其底層函數(shù)getch()和putchOo在單片機(jī)系統(tǒng)中實(shí)現(xiàn)scanf/printf本來就沒什么太多意義,如果一定要實(shí)現(xiàn),只要編寫好特定的getch()和putchO函數(shù),你就可以通過任何接口輸入或輸
出格式化的數(shù)據(jù)。11.7PICC定義特殊區(qū)域值PICC提供了相關(guān)的預(yù)處理指令以實(shí)現(xiàn)在原程序中定義單片機(jī)的配置字和標(biāo)記單元。.1定義工作配置字在原程序中定義PIC單片機(jī)工作配置字的重要性在前面章節(jié)中已經(jīng)闡述。在用PICC寫程序時(shí)同樣可以在C原程序中定義,具體方式如下:—CONFIG(HS&UNPROTECT&PWRTEN&BORDIS&WDTEN);上面的關(guān)鍵詞“_CONFIG”(注意前面有兩個(gè)下劃線符)專門用于是芯片配置字的設(shè)定,后面括號(hào)中的各項(xiàng)配置位符號(hào)在特定型號(hào)單片機(jī)的頭文件中已經(jīng)定義(注意不是pic.h頭文件),相互之間用邏輯“與”操作符組合在一起。這樣定義的配置字信息最后將和程序代碼一起放入同一個(gè)HEX文件。在這里列出了適用于16F7x系列單片機(jī)配置位符號(hào)預(yù)定義,其它型號(hào)或系列的單片機(jī)配置字定義方式類似,使用前查閱一下對(duì)應(yīng)的頭文件即可。/*振蕩器配置*/ftdefineRCttdefineHS0x3FFF//RC振蕩0x3FFE//HS模式ttdefineXT#defineLP/*看門狗配置*/0x3FFD//XT模式0x3FFC//LP模式
ttdefineWDTDIS/*上電延時(shí)定時(shí)器配置*/#definePWRTEN0x3FFB//看門狗關(guān)閉0x3FF7//上電延時(shí)定時(shí)器打開#definePWRTDIS延時(shí)定時(shí)器關(guān)閉0x3FFF//上電/*低電壓復(fù)位配置*/#defineBOREN0x3FFF#defineBOREN0x3FFF//低電壓復(fù)位允許ttdefineBORDIS/*代碼保護(hù)配置*/0x3FBF//低電壓復(fù)位禁止沒有代碼保護(hù)ttdefineUNPROTECT0x3FFF//沒有代碼保護(hù)^definePROTECT代碼保護(hù)0x3FEF//程序例11-6頭文件預(yù)定義的配置信息符號(hào)11.7.2定義芯片標(biāo)記單元PIC單片機(jī)中的標(biāo)記單元定義可以用下面的_IDLOC(注意前面有兩個(gè)下劃線符)預(yù)處理指令實(shí)現(xiàn),方法如下:_IDLOC(1234);其特殊之處是括號(hào)內(nèi)的值全部為16進(jìn)制數(shù),不需要用“Ox”引導(dǎo)。這樣上面的定義就設(shè)定了標(biāo)記單元內(nèi)容為01020304。11.8MPLAB-IDE中實(shí)現(xiàn)PICC的編譯選項(xiàng)設(shè)置在H.3節(jié)中已經(jīng)介紹了如何實(shí)現(xiàn)PICC和MPLAB-IDE開發(fā)平臺(tái)的掛接。一旦項(xiàng)目建立成功、程序編寫完成后即可以通過MPLAB環(huán)境下的項(xiàng)目管理工具實(shí)現(xiàn)程序的編譯、連接和調(diào)試。它們的含義分別是:一項(xiàng)目維護(hù)(Make):MPLAB檢查項(xiàng)目中的原程序文件,只編譯那些在上次編譯后又被修改過的原程序,最后進(jìn)行連接;一項(xiàng)目重建(BuildAll):項(xiàng)目中的所有原程序文件,不管是否有修改,都將被重新編譯一次,最后進(jìn)行連接。也可以通過Project菜單選擇“Make”或“BuildAU”實(shí)現(xiàn)項(xiàng)目編譯。不管采用何種方式,在啟動(dòng)編譯過程前一般都要設(shè)定一些編譯選項(xiàng)。11.8.1 選擇單片機(jī)型號(hào)在選擇PICC作為語言工具并建立了項(xiàng)目后,同樣通過菜單項(xiàng)Configure&01616;SelectDevice在MPLAB環(huán)境中選擇具體單片機(jī)型號(hào)。請(qǐng)回顧一下例11-1的代碼,我們?cè)谠绦蛞婚_始使用了“include”實(shí)現(xiàn)了相關(guān)單片機(jī)的一些預(yù)定義符號(hào)的直接引用,但沒有具體指明是哪一個(gè)型號(hào)。實(shí)際上,“Pic.h”頭文件只是一個(gè)簡(jiǎn)單的管理工具(條件判別),它會(huì)按照MPLAB所選擇的特定型號(hào)的單片機(jī),把真正對(duì)應(yīng)的頭文件包含進(jìn)來。有興趣者可以直接用文本編輯工具打開pic.h文件查看其是如何根據(jù)不同的單片機(jī)型號(hào)包含對(duì)應(yīng)的頭文件。這樣對(duì)編程員而言,程序中只需加上一句"include”即可。參考第三章3.2.7節(jié)的內(nèi)容和圖3-20的指示說明,啟動(dòng)編譯選項(xiàng)設(shè)定對(duì)話框。在使用PICC語言工具時(shí)對(duì)話框的內(nèi)容和用MPAMS匯編工具相比完全不同。圖11-3為PICC編譯環(huán)境下普通選項(xiàng)設(shè)定的界面。在此界面中用戶唯一能改變的是編譯器查找頭文件時(shí)的指定路徑(IncludePath),實(shí)際上如果編譯器安裝沒有問題,在此界面中這些普通選項(xiàng)的設(shè)定無需任何改動(dòng),編譯器會(huì)自動(dòng)到缺省認(rèn)定的路徑中(編譯器安裝后的相關(guān)路徑)查找編譯所需的各類文件。圖11-3PICC普通選項(xiàng)設(shè)定 圖11-4PICC全局選項(xiàng)設(shè)定3PICC全局選項(xiàng)設(shè)定(PICCGlobal)全局選項(xiàng)將影響項(xiàng)目中所有C和匯編原程序的編譯,詳細(xì)的設(shè)定內(nèi)容見圖11-4。其中必須關(guān)注的有:&01540;CompileforMPLABICD:如果你準(zhǔn)備用ICD調(diào)試C語言編譯后的代碼,那么此項(xiàng)就必須打鉤選中。這樣編譯后的結(jié)果就能保證ICD本身使用的芯片資源(一小部分的程序和數(shù)據(jù)空間)不被應(yīng)用程序所占用。&01540;Treat'char'assigned:為了提高編譯后的代碼效率,PICC缺省認(rèn)定‘char'型變量也是無符號(hào)數(shù)。如果在設(shè)計(jì)中需要使用帶符號(hào)的‘char,型變量,此項(xiàng)就應(yīng)該被選中。&01540;Floatingpoint'double'width:同樣為了提高編譯后的代碼效率,PICC 缺省認(rèn)定?double,型的雙精度浮點(diǎn)數(shù)變量的實(shí)現(xiàn)長(zhǎng)度為24位(等同于普通float型浮點(diǎn)數(shù))。在這里可以選擇使其長(zhǎng)度達(dá)32位。這樣數(shù)值計(jì)算的精度將得到提高,但代碼長(zhǎng)度將增加,計(jì)算速度也會(huì)降低,所以請(qǐng)?jiān)跈?quán)衡利弊后作出你自己的決定。項(xiàng)目中所有的C原程序都將通過C編譯器編譯成機(jī)器碼,這些選項(xiàng)決定了C編譯器是如何工作的。所有選項(xiàng)又分為兩組:普通選項(xiàng)(General)和高級(jí)選項(xiàng)(Advanced),分別見圖11-5A和ll-5BoC編譯器的普通選項(xiàng)最重要的就是針對(duì)代碼優(yōu)化的設(shè)定。如果沒有特殊原因,應(yīng)該設(shè)定全局優(yōu)化級(jí)別為9級(jí)(最高級(jí)別優(yōu)化),同時(shí)使用匯編級(jí)優(yōu)化,這樣最終得到的代碼效率最高(長(zhǎng)度和執(zhí)行速度兩方面)。按筆者的使用經(jīng)驗(yàn),僅從代碼長(zhǎng)度去比較,使用最高級(jí)別優(yōu)化后代碼長(zhǎng)度至少可以減少20%(2K字以上的程序)。而且PICC的優(yōu)化器相當(dāng)可靠,一般(A) 常用選項(xiàng)(B)高級(jí)選項(xiàng)圖11-5C編譯器選項(xiàng)設(shè)定不會(huì)因?yàn)槭褂脙?yōu)化從而使生成的程序出現(xiàn)錯(cuò)誤。碰到的一些問題也基本都是用戶編寫的原程序有漏洞所導(dǎo)致,例如一些變量應(yīng)該是volatile型但編程員沒有明確定義,在優(yōu)化前程序可以正常運(yùn)行,一旦使用優(yōu)化,程序運(yùn)行就出現(xiàn)異常。顯然,把出現(xiàn)的這些問題歸罪到編譯器是毫無道理的。使用優(yōu)化后可能對(duì)原程序級(jí)的調(diào)試帶來一些不便之處。因PICC可能會(huì)重組編譯后的代碼,例如多處重復(fù)的代碼可能會(huì)改成同一個(gè)子程序調(diào)用以節(jié)約程序空間,這樣在調(diào)試過程中跟蹤原程序時(shí)可能會(huì)出現(xiàn)程序亂跳的現(xiàn)象,這基本是正常的。若為了強(qiáng)調(diào)更直觀的代碼調(diào)試過程,你可以將優(yōu)化級(jí)別降低甚至關(guān)閉所有優(yōu)化功能,這樣調(diào)試時(shí)程序的運(yùn)行就可以按部就班了。C編譯器的高級(jí)選項(xiàng)設(shè)定基本都是針對(duì)診斷信息輸出的,和生成的代碼無關(guān)。用得相對(duì)較多的選項(xiàng)有:&01540;Generateassemblylistfile:編譯器生成C原程序的匯編列表文件(*.1st)。在此文件中列出了每一行c原代碼對(duì)應(yīng)的匯編指令,但這些都是優(yōu)化前的代碼。簡(jiǎn)單的一條C語句被翻譯成匯編指令后可能有好幾條。有時(shí)匯編列表文件可以作為解決問題的輔助手段。如果你懷疑編譯器生成的代碼有錯(cuò)誤,不妨先產(chǎn)生對(duì)應(yīng)的匯編列表文件,看看在優(yōu)化前一條c語句被編譯后的匯編碼到底是什么。&01540;Compiletoassemblyonly:這一選項(xiàng)的作用是把&n,bsp;C原程序編譯成匯編指令文件(*.as),此時(shí)將不生成目標(biāo)文件,也不進(jìn)行最后的連接定位。這一選項(xiàng)在C和匯編混合編程時(shí)特別有用。通過解讀C程序?qū)?yīng)的匯編指令,可以掌握c程序中存取變量的具體方法,然后用在自己編寫的匯編指令中。我們將在稍后專門做介紹。11.8.5 連接器選項(xiàng)設(shè)定(PICCLinker)連接器PICCLinker的選項(xiàng)基本不用作太多的改變,在圖11-6的對(duì)話框中顯示了可設(shè)定的各類項(xiàng)目。其中有兩項(xiàng)有用的信息輸出可以考慮加以利用:&01540;Generatemapfile:生成連接定位映射文件。在此映射文件中詳細(xì)列出了所有程序用到的變量的具體物理地址;所有函數(shù)的入口地址;函數(shù)相互之間調(diào)用的層次關(guān)系和深度等。這些信息對(duì)于程序的調(diào)試將非常有用。此文件將以擴(kuò)展名的形式存放在同一個(gè)項(xiàng)目路徑下,需要時(shí)可以用任何文本編輯器打開觀察。圖11-6PICC連接器選項(xiàng)設(shè)定&01540;Displaymemory-segmentusage:顯示詳細(xì)的內(nèi)存分配和使用情況報(bào)告。用戶可以了解到程序空間和數(shù)據(jù)存儲(chǔ)器空間資源分配的細(xì)節(jié)。下面列舉了在一個(gè)項(xiàng)目編譯后實(shí)際的內(nèi)存使用信息,為方便理解筆者用“〃”添加了一些注釋:PsectUsageMap: 〃程序段定位表Psect|Contents |MemoryRangepowerup|Poweronresetcode | $0000-$0003intentry|Interruptserviceroutine$0004-$000Cintcode |Interruptserviceroutine |$000D-$002Cintret |Interruptserviceroutine |$002D-$0035init|Initializationcode | $0036-$003Dendinit|Initializationcode |$003E-$0040clrtext|Memoryclearingcode $0041-$0047
const3$0060Stringsandconstantdata$0048-const$0071Stringsandconstantdata$0061-const2$0076Stringsandconstantdata$0072-text$0582Programandlibrarycode|$0576-text$07C7ProgramandlibrarycodeI$0583-float_te$07FFArithmeticroutinecode$07C8-rbssO$0042Bank0RAMvariables$0021-tempTemporaryRAMdata$0043$0047nvram PersistentRAMdata |$0048-$004Aintsave Registerssavedoninterrupt $004B-$004Dintsave Registerssavedoninterrupt $007F-$007Fintsavel|SavedcopyofWinbank1 |$00FF-$00FFrbitO|Bank0bitvariables|$0100-$0104config|User-programmedCONFIGbits|$2007-$2007MemoryUsageMap:〃程序空間代碼定位地址分布〃存儲(chǔ)空間使用情況報(bào)告119)wordsProgramROM$0000-$0076$119)wordsProgramROM$0576-$07FF$028A( 650)words$0301( 769)wordstotalProgramROM//bankO數(shù)據(jù)空間變量地址分布Bank 0RAM $0021- $004D $002D( 45)bytesBank 0RAM $007F- $007F $0001( 1)bytes$002E( 46)bytestotalBank0RAM//bankl數(shù)據(jù)空間變量地址分布Bank1RAM$00FF-$00FF $0001( 1)bytestotalBank1RAM//bankO數(shù)據(jù)空間位變量地址分布Bank0Bits$0100-$0104 $0005( 5)bitstotalBank0Bits〃配置字地址ConfigData$2007-$2007 $0001( 1)wordstotalConfigDataProgramstatistics:〃程序總體資源消耗統(tǒng)計(jì)TotalROMused 769words(18.8%) 〃生成代碼字總數(shù)和程序空間使用率TotalRAMused 48bytes(25.0%) 〃使用數(shù)據(jù)字節(jié)數(shù)和數(shù)據(jù)空間使用率
例11-7例11-7編譯后程序使用的內(nèi)存信息11.8.6 匯編器選項(xiàng)設(shè)定(PICCAssembler)PICC環(huán)境提供了自己的匯編編譯器,它和Microchip公司提供的MPASM編譯器在原程序的語法表達(dá)方面要求稍有不同。另外,PICC的匯編編譯器要求輸入原程序文件的擴(kuò)展名是“*.as",而MPASM缺省認(rèn)定的原程序以“*.asm”為擴(kuò)展名。在基于PICC編譯環(huán)境下開發(fā)PIC單片機(jī)的C語言應(yīng)用程序時(shí)基本無需關(guān)心其匯編編譯器,除非是在混合語言編程時(shí)用匯編語言編寫完整的匯編原程序模塊文件。其編譯選項(xiàng)設(shè)定的對(duì)話框見圖11-7,最重要的是優(yōu)化使能控制項(xiàng)“Enableoptimization",一般情況下應(yīng)該使用匯編器的優(yōu)化以節(jié)約程序空間。圖11-7PICC匯編器選項(xiàng)設(shè)定11.9C和匯編混合編程有兩個(gè)原因決定了用C語言進(jìn)行單片機(jī)應(yīng)用程序開發(fā)時(shí)使用匯編語句的必要性:?jiǎn)纹瑱C(jī)的一些特殊指令操作在標(biāo)準(zhǔn)的C語言語法中沒有直接對(duì)應(yīng)的描述,例如PIC單片機(jī)的清看門狗指令"clrwdt”和休眠指令"sleep";單片機(jī)系統(tǒng)強(qiáng)調(diào)的是控制的實(shí)時(shí)性,為了實(shí)現(xiàn)這一要求,有時(shí)必須用匯編指令實(shí)現(xiàn)部分代碼以提高程序運(yùn)行的效率。這樣,一個(gè)項(xiàng)目中就會(huì)出現(xiàn)C和匯編混合編程的情形,我們?cè)诖擞懻撘恍┗旌暇幊痰幕痉椒ê图记?。嵌入行?nèi)匯編的方法在C原程序中直接嵌入?yún)R編指令是最直接最容易的方法。如果只需要嵌入少量幾條的匯編指令,PICC提供了一個(gè)類似于函數(shù)的語句:asm("clrwdt");雙引號(hào)中可以編寫任何一條PIC的標(biāo)準(zhǔn)匯編指令。例如:for(;;){asm("clrwdt");〃清看門狗Task();
ClockRun0;asm("sleep");asm(nop);}〃休眠〃空操作延時(shí)例11-8例11-8逐行嵌入?yún)R編的方式如果需要編寫一段連續(xù)的匯編指令,PICC支持另外一種語法描述:用法asm”開始匯編指令段,用“#endasm”結(jié)束。例如下面的一段嵌入?yún)R編指令實(shí)現(xiàn)了將 0x20~0x7F間的RAM全部清零:#asmmovlw 0x20movwf _FSRclrf _INDFincf _FSR,fbtfss _FSR,7goto $-3ttendasm例11-9 整段嵌入?yún)R編的方式匯編指令尋址C語言定義的全局變量C語言中定義的全局或靜態(tài)變量尋址是最容易的,因?yàn)檫@些變量的地址已知且固定。按C語言的語法標(biāo)準(zhǔn),所有C中定義的符號(hào)在編譯后將自動(dòng)在前面添加一下劃線符,因此,若要在匯編指令中尋址C語言定義的各類變量,一定要在變量前加上一 符號(hào),我們?cè)谏厦胬?1-9中已經(jīng)體現(xiàn)了這一變量引用的法則,因?yàn)镕SR和INDF等所有特殊寄存器是以C語言語法定義的,因此匯編中需要對(duì)其尋址時(shí)前面必須添加下劃線。對(duì)于C語言中用戶自定義的全局變量,用行內(nèi)匯編指令尋址時(shí)也同樣必須加上下面的例11T0說明了具體的引用方法:volatileunsignedchartmp; 〃定義位于bankO的字符型全局變量voidTest(void){#asmclrf_STATUSmovlw0x10movwftmpttendasmif(tmp==0xl0){}〃測(cè)試程序〃開始行內(nèi)匯編〃選擇bankO〃設(shè)定初值//tmp=OxlO〃結(jié)束行內(nèi)匯編〃開始C語言程序
例11T0例11T0行內(nèi)匯編尋址C全局變量(位于bankO)上面的例子說明了匯編指令中尋址C語言所定義變量的基本方法。PICC在編譯處理嵌入的行內(nèi)匯編指令時(shí)將會(huì)原封不動(dòng)地把這些指令復(fù)制成最后的機(jī)器碼。所有對(duì)C編譯器所作的優(yōu)化設(shè)定對(duì)這些行內(nèi)匯編指令而言將不起任何作用。編程員必須自己負(fù)責(zé)編寫最高效的匯編代碼,同時(shí)處理變量所在的bank設(shè)定。對(duì)于定義在其它bank中的變量,還必須在匯編指令中加以明確指示,見例11-11的代碼范例。volatilebanklunsignedchartmpBankl;〃定義位于bankl的字符型全局變量volatilebank2unsignedchartmpBank2;〃定義位于bank2的字符型全局變量〃定義位volatilebank3unsignedchartmpBank3;〃定義位于bank3的字符型全局變量voidTest(void)(#asmbcf _STATUS,6bsf _STATUS,5movlw0x10movwftmpBankl0x80bsf _STATUS,6movlw0x20〃測(cè)試程序〃開始行內(nèi)匯編〃選擇bankl〃設(shè)定初值//tmpBankl=OxlO〃選擇bank2〃設(shè)定初值//tmpBank2=0x20//tmpBank2=0x20bsfSTATUS,5bsfSTATUS,5movlw0x30〃選擇bank3〃
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 圓周接力課件教學(xué)課件
- 2024乙丙雙方關(guān)于智能家居系統(tǒng)安裝與維護(hù)的合同
- 2024保險(xiǎn)合同保險(xiǎn)標(biāo)的及屬性規(guī)定
- 2024年司機(jī)配駕汽車租賃合同標(biāo)準(zhǔn)版
- 2024年度工程建設(shè)項(xiàng)目融資擔(dān)保合同
- 2024年居住區(qū)綠化托管協(xié)議
- 2024年廣告制作委托合同
- 2024年展覽廳知識(shí)產(chǎn)權(quán)保護(hù)合同
- 2024國有土地使用權(quán)合同解釋國有土地使用權(quán)收購合同
- 2024年度汽車銷售業(yè)績(jī)獎(jiǎng)勵(lì)合同
- 雙塔精餾正常操作雙塔精餾正常操作
- 振蕩指標(biāo)MACD(波段操作精解)
- 2024年四川航空股份有限公司招聘筆試參考題庫含答案解析
- 醫(yī)學(xué)檢驗(yàn)專業(yè)職業(yè)規(guī)劃書
- 喘證診療方案臨床療效評(píng)價(jià)總結(jié)分析
- 慈善協(xié)會(huì)各項(xiàng)管理制度
- 外研版小學(xué)英語六年級(jí)上每課時(shí)教學(xué)反思
- 語法講解一般將來時(shí)課件
- 品牌獨(dú)家代理合作協(xié)議
- 食材、副食品配送方案技術(shù)標(biāo)
- 危大工程清單及安全管理措施(樣表)
評(píng)論
0/150
提交評(píng)論