單片機PROTUES仿真c語言_第1頁
單片機PROTUES仿真c語言_第2頁
單片機PROTUES仿真c語言_第3頁
單片機PROTUES仿真c語言_第4頁
單片機PROTUES仿真c語言_第5頁
已閱讀5頁,還剩180頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

王健帶你征服Pic單片

機PROTUES仿真C語言

部作者多年工作經(jīng)驗的著作

講解最全的單片機C語言程序

王健著

337884703@

前言

這個教程最大的特色就是用PROTUES軟件,為讀者省去

一大筆開支,真正零開支,所用軟件是MPLABIDE8.63和

PICC9.8

這本書分為兩部分,雖然是C語言,但是也要講一下單片機

的一些基礎(chǔ)知識,第一部分講單片機的基礎(chǔ)知識,第二部分

講C程序

PIC單片機(PeripheralInterfaceController)是一

種用來可開發(fā)的去控制外圍設(shè)備的可編程集成電路(IC)。

由美國Microchip(微星)公司推出的PIC單片機系列產(chǎn)品,

首先采用了RISC結(jié)構(gòu)的嵌入式微控制器,其高速度、低電

壓、低功耗、大電流LCD驅(qū)動能力和低價位0TP技術(shù)等都體

現(xiàn)出單片機產(chǎn)業(yè)的新趨勢?,F(xiàn)在PIC系列單片機在世界單片

機市場的份額排名中已逐年升位,尤其在8位單片機市場,

已從1990年的第20位上升到目前的第二位。PIC單片機從

覆蓋市場出發(fā),已有三種(又稱三層次)系列多種型號的產(chǎn)品

問世,所以在全球都可以看到PIC單片機從電腦的外設(shè)、家

電控制、電訊通信、智能儀器、汽車電子到金融電子各個領(lǐng)

域的廣泛應(yīng)用。現(xiàn)今的PIC單片機已經(jīng)是世界上最有影響力

的嵌入式微控制器之一。

第一部分認(rèn)識pic單片機

PIC單片機(PeripheralInterfaceController)是一

種用來開發(fā)去控制外圍設(shè)

備的集成電路(IC)o一種具有分散作用(多任務(wù))功能

的CPU。與人類相比,大腦就是CPU,PIC共享的部分相當(dāng)

于人的神經(jīng)系統(tǒng)。

2.PIC單片機是一個小的計算機

3.PIC單片機有計算功能和記憶內(nèi)存像CPU并由軟件

控制運行。然而,處理能力一般,存儲器容量也很有限,

這取決于PIC的類型。但是它們的最高操作頻生大約都在

20MHz左右,存儲器容量用做寫程序的大約IK—4K字節(jié)。

時鐘頻率與掃描程序的時間和執(zhí)行程序指令的時間

有關(guān)系。但不能僅以時林頻莖來判斷程序處理能力,它還

隨處理裝置的體系結(jié)構(gòu)改變(1*)。如果是同樣的體系結(jié)

構(gòu),時鐘頻率較高的處理能力會較強。

這里用字來解釋程序容量。用一個指令(2*)表示一

個字。通常用字苴(3*)來表示存儲器(4*)容量。一個

字節(jié)有8位,每位由1或0組成。PIC16F84A單片機的指

令由14位構(gòu)成。當(dāng)把1K個字轉(zhuǎn)換成位為:1xl,024x14

=14,336位。再轉(zhuǎn)換為字節(jié)為:14,336/(8x1,024)二

1.75KO在計算存儲器的容量時,我們規(guī)定1G寶芭=

1,02圳字節(jié),1M字節(jié)=l,024K字節(jié),1K字節(jié)二1,024

位.它們不是以1000為倍數(shù),因為這是用二進(jìn)制計算的

緣故。

1*計算機的物理結(jié)構(gòu),包括組織結(jié)構(gòu)、容量、該計算

機的CPU、存儲器以及輸入輸出設(shè)備間的互連。經(jīng)常特指

CPU的組織結(jié)構(gòu),包括它的寄存器、標(biāo)志、總線、算術(shù)邏輯

部件、指令譯碼與執(zhí)行機制以及定時和控制部件。

2*指出某種操作并標(biāo)識其操徒數(shù).(如果有操作數(shù)的話)

的一種語言構(gòu)造

3*作為一個單位來操作(運算)的一個二進(jìn)制字符串,

通常比計算機的一個字短。

4*處理機內(nèi)的所有可尋址存儲空間以及用于執(zhí)行指

令的其它內(nèi)存儲器。

在計算存儲器的容量時,我們規(guī)定1G字節(jié)二

1,024M字節(jié),1M字節(jié)=l,024K字節(jié),1K字節(jié):1,024

字節(jié).它們不是以1000為倍數(shù),因為這是用二進(jìn)制計算

的緣故。

用PIC單片機使電路做的很小巧變得可能。

因為PIC單片機可以把計算部分、內(nèi)存、輸入和輸出

等都做在一個芯片內(nèi)。所以她工作起來效率很高、功能也

自由定義還可以靈活的適應(yīng)不同的控制要求,而不必去更

換不同的IC。這樣電路才有可能做的很小巧。

PIC單片機型號命名規(guī)則

PICXXXXXXXX(X)-XXX/XX

12345678

1.前綴:PICMICROCHIP公司產(chǎn)品代號,特別地:dsPIC

為集成DSP功能的新型PIC單片機

2.系列號:10、12、16、18、24、30、33、32,其中

PIC10、PIC12.PIC16,PIC18為8位單片機

PIC24、dsPIC30,dsPIC33為16位單片機

PIC32為32位單片機

3.器件型號(類型):

CCMOS電路

CRCMOSROM

LC小功率CMOS電路

LCS小功率保護(hù)

AA1.8V

LCR小功率CMOSROM

LV低電壓

F快閃可編程存儲器

HC高速CMOS

FRFLEXROM

4.改進(jìn)類型或選擇

54A、58A、61、62、620、621

622、63、64、65、71、73、74

42、43、44等

5.晶體標(biāo)示:

LP小功率晶體,

RC電阻電容,

XT標(biāo)準(zhǔn)晶體/振蕩器

HS高速晶體

6.頻率標(biāo)示:

-022MHZ,

-044MHZ,

-1010MHZ,

-1616MHZ

-2020MHZ,

-2525MHZ,

-3333MHZ

7.溫度范圍:

空白0℃至70℃,

I-45℃至85℃,

E-40°。至125℃

8.封裝形式:

LPLCC封裝

JW陶瓷熔封雙列直插,有窗口

P塑料雙列直插

PQ塑料四面引線扁平封裝

W大圓片

SL14腿微型封裝-150mil

JN陶瓷熔封雙列直插,無窗口

SM8腿微型封裝-207mil

SN8腿微型封裝T50mil

VS超微型封裝8nlmX13.4mm

SO微型封裝-300mil

ST薄型縮小的微型封裝-4.4頻

SP橫向縮小型塑料雙列直插

CL68腿陶瓷四面引線,帶窗口

SS縮小型微型封裝

PT薄型四面引線扁平封裝

TS薄型微型封裝8nlmX20mm

TQ薄型四面引線扁平封裝

當(dāng)今單片機廠商琳瑯滿目,產(chǎn)品性能各異。針對具體情況,

我們應(yīng)選何種型號呢?首先,我們來弄清兩個概念:集中指

令集(CISC)和精簡指令集(RISC)。采用CISC結(jié)構(gòu)的單片

機數(shù)據(jù)線和指令線分時復(fù)用,即所謂馮.諾伊曼結(jié)構(gòu)。它的

指令豐富,功能較強,但取指令和取數(shù)據(jù)不能同時進(jìn)行,速

度受限,價格亦高。采用RISC結(jié)構(gòu)的單片機數(shù)據(jù)線和指令

線分離,即所謂哈佛結(jié)構(gòu)。這使得取指令和取數(shù)據(jù)可同時進(jìn)

行,且由于一般指令線寬于數(shù)據(jù)線,使其指令較同類CISC

單片機指令包含更多的處理信息,執(zhí)行效率更高,速度亦更

快。同時,這種單片機指令多為單字節(jié),程序存儲器的空間

利用率大大提高,有利于實現(xiàn)超小型化。屬于CISC結(jié)構(gòu)的

單片機有Intel8051系列、Motorola和M68HC系列、Atmel

的AT89系列、臺灣Winbond(華邦)W78系列、荷蘭Pilips

的PCF80C51系列等;屬于RISC結(jié)構(gòu)的有Microchip公司的

PIC系列、Zilog的Z86系列、Atmel的AT90S系列、韓國三

星公司的KS57C系列4位單片機、臺灣義隆的EM-78系列等。

一般來說,控制關(guān)系較簡單的小家電,可以采用RISC型單

片機;控制關(guān)系較復(fù)雜的場合,如通訊產(chǎn)品、工業(yè)控制系統(tǒng)

應(yīng)采用CISC單片機。不過,RISC單片機的迅速完善,使其

佼佼者在控制關(guān)系復(fù)雜的場合也毫不遜色。

根據(jù)程序存儲方式的不同,單片機可分為EPROM、OTP(一次

可編程)、QTP(掩膜)三種。我國一開始都采用ROMless型

單片機(片內(nèi)無ROM,需片外配EPROM),對單片機的普及起

了很大作用,但這種強調(diào)接口的單片機無法廣泛應(yīng)用,甚至

走入了誤區(qū)。如單片機的應(yīng)用一味強調(diào)接口,外接I/O及存

儲器,便失去了單片機的特色。目前單片機大都將程序存儲

體置于其內(nèi),給應(yīng)用帶來了極大的方便。值得一提的是,以

往OTP型單片機的價格是QTP的3倍,而現(xiàn)在已降至1.5-

1.2倍,選用OTP型以免訂貨周期、批量的麻煩是可取的。

PIC系列單片機的優(yōu)勢

自從我2006年接觸PIC單片機以來,便一直熱衷于這種單

片機的開發(fā)與應(yīng)用

PIC最大的特點是不搞單純的功能堆積,而是從實際出

發(fā),重視產(chǎn)品的性能與價格比,靠發(fā)展多種型號來滿足不同

層次的應(yīng)用要求。就實際而言,不同的應(yīng)用對單片機功能和

資源的需求也是不同的。比如,一個摩托車的點火器需要一

個I/O較少、RAM及程序存儲空間不大、可靠性較高的小型

單片機,若采用40腳且功能強大的單片機,投資大不說,

使用起來也不方便。PIC系列從低到高有幾十個型號,可以

滿足各種需要。其中,PIC12c508單片機僅有8個引腳,是

世界上最小的單片機。該型號有512字節(jié)ROM、25字節(jié)RAM、

一個8位定時器、一根輸入線、5根I/O線,市面售價在3

-6元人人民幣。這樣一款單片機在象摩托車點火器這樣的

應(yīng)用無疑是非常適合。PIC的高檔型號,如PIC16c74(尚不

是最高檔型號)有40個引腳,其內(nèi)部資源為ROM共4K、192

字節(jié)RAM8路A/D、3個8位定時器、2個CCP模塊、三個

串行口、1個并行口、11個中斷源、33個I/O腳。這樣一個

型號可以和其它品牌的高檔型號媲美。

精簡指令使其執(zhí)行效率大為提高。PIC系列8位CMOS單

片機具有獨特的RISC結(jié)構(gòu),數(shù)據(jù)總線和指令總線分離的哈

佛總線(Harvard)結(jié)構(gòu),使指令具有單字長的特性,且允

許指令碼的位數(shù)可多于8位的數(shù)據(jù)位數(shù),這與傳統(tǒng)的采用

CISC結(jié)構(gòu)的8位單片機相比,可以達(dá)到2:1的代碼壓縮,速

度提高4倍。

產(chǎn)品上市零等待(Zerotimetomarket)o采用PIC的

低價OTP型芯片,可使單片機在其應(yīng)用程序開發(fā)完成后立刻

使該產(chǎn)品上市。

Pic有優(yōu)越開發(fā)環(huán)境。OTP單片機開發(fā)系統(tǒng)的實時性是

一個重要的指標(biāo),象普通51單片機的開發(fā)系統(tǒng)大都采用高

檔型號仿真低檔型號,其實時性不盡理想。PIC在推出一款

新型號的同時推出相應(yīng)的仿真芯片,所有的開發(fā)系統(tǒng)由專用

的仿真芯片支持,實時性非常好。就我個人的經(jīng)驗看,還沒

有出現(xiàn)過仿真結(jié)果與實際運行結(jié)果不同的情況。

其引腳具有防瞬態(tài)能力,通過限流電阻可以接至220V交

流電源,可直接與繼電器控制電路相連,無須光電耦合器隔

離,給應(yīng)用帶來極大方便。

徹底的保密性。PIC以保密熔絲來保護(hù)代碼,用戶在燒

入代碼后熔斷熔絲,別人再也無法讀出,除非恢復(fù)熔絲。目

前,PIC采用熔絲深埋工藝,恢復(fù)熔絲的可能性極小。

自帶看門狗定時器,可以用來提高程序運行的可靠性。

睡眠和低功耗模式。雖然PIC在這方面已不能與新型的

TI-MSP430相比,但在大多數(shù)應(yīng)用場合還是能滿足需要的。

Microchip基于精簡指令集計算(RISC)的PlCmicro系列單

片機是為要求高性能而低價格的用戶設(shè)計的。PlCmicro系列

單片機家族由130多種產(chǎn)品組成,集多種存儲器配置,低電

壓低功率,小引腳及易于使用等多種特點于一身。在我們8

位MCU引腳的微小空間里封裝有大量的信息。隨著您設(shè)計的

復(fù)雜化,您所寫的程序代碼以后可以輕易地轉(zhuǎn)換到具有更多

外圍資源的較大的MicrochipMCU中去。PlCmicroMCU家族

中的所有產(chǎn)品都是無間隙過渡的,在嵌入式設(shè)計中可完全向

上兼容。如果您已經(jīng)知道設(shè)計應(yīng)用產(chǎn)品所需的單片機規(guī)格,

您就可通過Microchip的參數(shù)搜索引擎按照相應(yīng)的條件進(jìn)行

搜索并選用相應(yīng)的產(chǎn)品。在您的選擇過程中所需用到的條件

為:編程存儲器大小,數(shù)據(jù)RAM,存儲器類型以及封裝類型。

如果您對Microchip的PlCmicroMCU還不熟悉的話,以下

介紹將幫助您了解。PlCmicroMCU將高性能,低價格,封裝

尺寸小,提供最高性價比等特點集于一身,提供5個家族的

8位單片機產(chǎn)品,以最好地滿足您的需要。

PIC12CXXX家族:8引腳12/14位程序詞

PIC12CXXX家族產(chǎn)品為Microchip功能強大的基于RISC的

PlCmicro系列8引腳DIP及S0IC封裝。PIC12CXXX產(chǎn)品具

有12或14位寬指令集,2.5V低運行電壓,小封裝引腳,中

斷處理,深硬件堆棧,多通道以及EEPR0M數(shù)據(jù)存儲器。這

些智能級特性由于價格與尺寸的原因在以前的產(chǎn)品中是不

具備的。

PIC16c5X家族:12位程序詞

PIC16C5X家族具有全套基礎(chǔ)產(chǎn)品,為您提供最有效的價格解

決方案。PIC16c5X產(chǎn)品具備12位寬指令集,目前提供14,

18,20及28引腳封裝。在選用S0IC與SS0P封裝時,產(chǎn)品

的引腳所占據(jù)的空間是最小的。低至2.0V運行的低壓0TP

MCU使產(chǎn)品成為電池驅(qū)動應(yīng)用產(chǎn)品的理想選擇。另外,

PIC16HV5XX在直接應(yīng)用電池時最高可運行至15Vo

PIC16CXXX家族:14位程序詞

在推出了新的PIC16CXXX家族成員后,Microchip現(xiàn)已在該

產(chǎn)業(yè)中具備向單片機提供最高性能的12位模擬數(shù)字轉(zhuǎn)換器

能力的供應(yīng)商。PIC16CXXX家族可提供從18引腳至68引腳

封裝,以及由低級至高級的外圍集成的一系列產(chǎn)品。該家族

具備14位寬指令集,中斷處理能力及8級硬件深堆棧。

PIC16XXX家族提供了高性能及多功能的中檔應(yīng)用產(chǎn)品,以適

應(yīng)當(dāng)今市場的價格競爭。

PIC17CXXX家族:16位程序詞

PIC17CXXX家族將PlCmicroMCU的高性能RISC結(jié)構(gòu)擴展為

16位指令詞,增強型指令集與強大的矢量中斷處理能力。強

大的隊列式精確在片外設(shè)特性提供了能適應(yīng)更多應(yīng)用場合

的各種性能。

PIC18CXXX家族:增強型16位程序詞

PIC18CXXX家族產(chǎn)品具有高性能,CMOS,集成了模擬數(shù)

字(A/D)轉(zhuǎn)換器的全靜態(tài)MCU等特點。所有PIC18CXXX的

MCU均應(yīng)用了先進(jìn)的RISCoPIC18CXXX具備增強型中心特性,

32位深堆棧,以及內(nèi)外多中斷源。Harvard系列中的分離指

令與數(shù)據(jù)總線允許16位寬指令詞與獨立8位寬數(shù)據(jù)。兩級

指令通道允許所有指令在一個周期內(nèi)執(zhí)行,除非子程序中設(shè)

定必須在兩個周期內(nèi)完成。精簡指令集共有77條指令。另

外,一個大寄存器組使采用了結(jié)構(gòu)性創(chuàng)新的MCU達(dá)到10MIPS

的極高的性能。PIC18CXXX家族具備的特殊特性能減少外部

組件以降低成本,增強系統(tǒng)可靠性并降低功耗。這些特性包

括可編程低壓檢測(LVD)及可編程Brown-Out檢測(BOD)

PIC單片機C語言編程簡介

用C語言來開發(fā)單片機系統(tǒng)軟件最大的好處是編寫代碼

效率高、軟件調(diào)試直觀、維護(hù)升級方便、

代碼的重復(fù)利用率高、便于跨平臺的代碼移植等等,因此C

語言編程在單片機系統(tǒng)設(shè)計中已得到越

來越廣泛的運用。針對PIC單片機的軟件開發(fā),同樣可以

用c語言實現(xiàn)。

但在單片機上用c語言寫程序和在PC機上寫程序絕對不

能簡單等同。現(xiàn)在的PC機資

源十分豐富,運算能力強大,因此程序員在寫PC機的應(yīng)用

程序時幾乎不用關(guān)心編譯后的可

執(zhí)行代碼在運行過程中需要占用多少系統(tǒng)資源,也基本不用

擔(dān)心運行效率有多高。寫單片機

的C程序最關(guān)鍵的一點是單片機內(nèi)的資源非常有限,控制

的實時性要求又很高,因此,如

果沒有對單片機體系結(jié)構(gòu)和硬件資源作詳盡的了解,以筆者

的愚見認(rèn)為是無法寫出高質(zhì)量實

用的C語言程序。這就是為什么前面所有章節(jié)中的的示范

代碼全部用基礎(chǔ)的匯編指令實現(xiàn)

的原因,希望籍此能使讀者對PIC單片機的指令體系和

硬件資源有深入了解,在這基礎(chǔ)之

上再來討論C語言編程,就有水到渠成的感覺。

本書圍繞中檔系列PIC單片機來展開討論,Microchip公

司自己沒有針對中低檔系列PIC

單片機的C語言編譯器,但很多專業(yè)的第三方公司有眾多

支持PIC單片機的C語言編譯器

提供,常見的有Hitech、CCS、IAR、Bytecraft等公司。

其中筆者最常用的是Hitech公司的

PICC編譯器,它穩(wěn)定可靠,編譯生成的代碼效率高,在用

PIC單片機進(jìn)行系統(tǒng)設(shè)計和開發(fā)

的工程師群體中得到廣泛認(rèn)可。其正式完全版軟件需要購

置,但在其網(wǎng)站上有限時的試用版

供用戶評估。另外,Hitech公司針對廣大PIC的業(yè)余愛好

者和初學(xué)者還提供了完全免費的學(xué)

習(xí)版PICC-Lite編譯器套件,它的使用方式和完全版相同,

只是支持的PIC單片機型號限制

在PIC16F84、PIC16F877和PIC16F628等幾款。這幾款

Flash型的單片機因其所具備的豐富

的片上資源而最適用于單片機學(xué)習(xí)入門,因此筆者建議感興

趣的讀者可從PICC-Lite入手掌

握PIC單片機的C語言編程。

在此列出幾個主要的針對PIC單片機的C編譯器相關(guān)連

接網(wǎng)址,供讀者參考:

Hitech-PICC:

IAR:

CCS:/picc.shtml

ByteCraft:www.bytecraft,com/mpccaps.html

本章將介紹Hitech-PICC編譯器的一些基本概念,由于篇

幅所限將不涉及C語言的標(biāo)準(zhǔn)

語法和基礎(chǔ)知識介紹,因為在這些方面都有大量的書籍可以

參考。重點突出針對PIC單片

機的特點而所需要特別注意的地方。

11.2

Hitech-PICC編譯器

PICC基本上符合ANSI標(biāo)準(zhǔn),除了一點:它不支持函數(shù)的

遞歸調(diào)用。其主要原因是因

為Pic單片機特殊的堆棧結(jié)構(gòu)。在前面介紹PIC單片機架

構(gòu)時已經(jīng)詳細(xì)說明了PIC單片機

中的堆棧是硬件實現(xiàn)的,其深度已隨芯片而固定,無法實現(xiàn)

需要大量堆棧操作的遞歸算法;

另外在PIC單片機中實現(xiàn)軟件堆棧的效率也不是很高,為

此,PICC編譯器采用一種叫做“靜

態(tài)覆蓋”的技術(shù)以實現(xiàn)對C語言函數(shù)中的局部變量分

配固定的地址空間。經(jīng)這樣處理后產(chǎn)

生出的機器代碼效率很高,按筆者實際使用的體會,當(dāng)代碼

量超過4K字后,C語言編譯出

的代碼長度和全部用匯編代碼實現(xiàn)時的差別已經(jīng)不是很大

(<10%),當(dāng)然前提是在整個C

代碼編寫過程中須時時處處注意所編寫語句的效率,而如果

沒有對PIC單片機的內(nèi)核結(jié)構(gòu)、

各功能模塊及其匯編指令深入了解,要做到這點是很難的。

11.3

MPLAB-IDE內(nèi)掛接PICC

PICC編譯器可以直接掛接在MPLAB-IDE集成開發(fā)平臺下,

實現(xiàn)一體化的編譯連接和

原代碼調(diào)試。使用MPLAB-IDE內(nèi)的調(diào)試工具ICE2000.ICD2

和軟件模擬器都可以實現(xiàn)原

代碼級的程序調(diào)試,非常方便。

首先必須在你的計算機中安裝PICC編譯器,無論是完全版還

是學(xué)習(xí)版都可以和

MPLABTDE掛接。安裝成功后可以進(jìn)入IDE,選擇菜單項

ProjectSetLanguageTool

Locations---,打開語言工具掛接設(shè)置對話框,如圖11-1所

示:

圖11-1MPLAB-IDE語言工具設(shè)置對話框

在對話框中選擇wHI-TECHPICCToolsuite”欄,展開可執(zhí)

行文件組“Executable”后,

列出了將被MPLAB-IDE后臺調(diào)用的編譯器所用到的所

有可執(zhí)行文件,其中有匯編編譯器

“PICCAssembler"、C原程序編譯器“PICCCompiler”

和連接定位程序"PICCLinker”。同

時在此列表中還顯示了對應(yīng)的可執(zhí)行程序名,請注意在這里

都是“PICC.EXE"。用鼠標(biāo)分別

點擊選中這三項可執(zhí)行文件,觀察對話框下面“Location”

一欄中顯示的文件路徑,用

“Browse…”按紐,從計算機中已經(jīng)安裝的PICC編譯器文

件夾中選擇PICC.EXE文件。實

際上PICC.EXE只是一個調(diào)度管理程序,它會按照所輸入的

文件擴展名自動調(diào)用對應(yīng)的編譯

器和連接器,用戶要注意的是C語言原程序擴展名用

“.c”,匯編原程序用“.as”即可。

工具掛接完成后,在建立項目時可以選擇語言工具為

uHI-TECHPICC”,具體步驟可以

參閱第三章3.1.3節(jié),此處不再重復(fù)。項目建立完成后可

以加入C或匯編原程序,也可以加

入已有的庫文件或已經(jīng)編譯的目標(biāo)文件。最常見的是只加入

C原程序。用C語言編程的好

處是可以實現(xiàn)模塊化編程。程序編寫者應(yīng)盡量把相互獨立的

控制任務(wù)用多個獨立的C原程序文件實

現(xiàn),如果程序量較大,一般不要把所有的代碼寫在一個文件

內(nèi)。

圖11-2列出的是筆者建立的一個項目中所有C原程序模

塊,其中主控、數(shù)值計算、12c總線操

作、命令按鍵處理和液晶顯示驅(qū)動等不同的功能分別在不同

的獨立的原程序模塊中實現(xiàn)。

圖H-2c語言多模塊編程

11.4PIC單片機的C語言原程序基本框架

基于PICC編譯環(huán)境編寫PIC單片機程序的基本方式和標(biāo)

準(zhǔn)C程序類似,程序一般由以

下幾個主要部分組成:

&01540;在程序的最前面用#include預(yù)處理指令引用

包含頭文件,其中必須包含一個編譯器

提供的“pic.h”文件,實現(xiàn)單片機內(nèi)特殊寄存器和其它特

殊符號的聲明;

&01540;用“—CONFIG”預(yù)處理指令定義芯片的配置

位;

&01540;聲明本模塊內(nèi)被調(diào)用的所有函數(shù)的類型,PICC

將對所調(diào)用的函數(shù)進(jìn)行嚴(yán)格的類型

匹配檢查;

&01540;定義全局變量或符號替換;

&01540;實現(xiàn)函數(shù)(子程序),特別注意main函數(shù)必

須是一個沒有返回的死循環(huán)。

下面的例11T為一個C原程序的范例,供大家參考。

ttinclude〃包含單片機內(nèi)部資源預(yù)定義

ttinclude“pc68.h”〃包含自定義頭文件

〃定義芯片工作時的配置位

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)

(

SetSFRO;

PORTC=0x00;

TMR1H+=TMR1H_CONST;

LED1=LED_OFF;

LCD_Test();

〃程序工作主循環(huán)

while(1){

asm("clrwdt”);

Clock();

KeyScan();

Measure();

SetSFRO;

)

〃清看門狗

〃更新時鐘

〃掃描鍵盤

〃數(shù)據(jù)測量

〃刷新特殊功能寄存器

11.5

PICC中的變量定義

例n-ic語言原程序框架舉例

11.5.1PICC中的基本變量類型

PICC遵循Little-endian標(biāo)準(zhǔn),多字節(jié)變量的低字節(jié)放

在存儲空間的低地址,高字節(jié)放

在「司地址。

11.5.2PICC中的高級變量

基于表11-1的基本變量,除了bit型位變量外,PICC完

全支持?jǐn)?shù)組、結(jié)構(gòu)和聯(lián)合等復(fù)

合型高級變量,這和標(biāo)準(zhǔn)的C語言所支持的高級變量類型

沒有什么區(qū)別。例如:

數(shù)組:unsignedintdata[10];

結(jié)構(gòu):structcommlnData{

unsignedcharinBuff[8];

unsignedchargetPtr,putPtr;

);

聯(lián)合:unionint_Byte{

unsignedcharc[2];

unsignedinti;

};

例11~2C語言高級變量舉例

11.5.3PICC對數(shù)據(jù)寄存器bank的管理

為了使編譯器產(chǎn)生最高效的機器碼,PICC把單片機中數(shù)據(jù)

寄存器的bank問題交由編程

員自己管理,因此在定義用戶變量時你必須自己決定這些變

量具體放在哪一個bank中。如

果沒有特別指明,所定義的變量將被定位在bankO,例如下

面所定義的這些變量:

unsignedcharbuffer[32];

bitflagl,flag2;

floatval[8];

除了bankO內(nèi)的變量聲明時不需特殊處理外,定義在其它

bank內(nèi)的變量前面必須加上

相應(yīng)的bank序號,例如:

banklunsignedcharbuffer[32];〃變量定位在

bankl中

bank2bitflagl,flag2;

bank3floatval[8];

〃變量定位在bank2中

〃變量定位在bank3中

中檔系列PIC單片機數(shù)據(jù)寄存器的一個bank大小為128

字節(jié),刨去前面若干字節(jié)的特

殊功能寄存器區(qū)域,在C語言中某一bank內(nèi)定義的變量

字節(jié)總數(shù)不能超過可用RAM字節(jié)

數(shù)。如果超過bank容量,在最后連接時會報錯,大致信息

如下:

Error[000]:Can'tfind0xl2Cwordsforpsectrbssl

insegmentBANK1

連接器告訴你總共有0xl2C(300)個字節(jié)準(zhǔn)備放到bankl

中但bankl容量不夠。顯然,只

有把一部分原本定位在bankl中的變量改放到其它bank

中才能解決此問題。

雖然變量所在的bank定位必須由編程員自己決定,但在編

寫原程序時進(jìn)行變量存取操

作前無需再特意編寫設(shè)定bank的指令。C編譯器會根據(jù)所

操作的對象自動生成對應(yīng)bank設(shè)

定的匯編指令。為避免頻繁的bank切換以提高代碼效率,

盡量把實現(xiàn)同一任務(wù)的變量定位

在同一個bank內(nèi);對不同bank內(nèi)的變量進(jìn)行讀寫操作時

也盡量把位于相同bank內(nèi)的變量

歸并在一起進(jìn)行連續(xù)操作。

11.5.4PICC中的局部變量

PICC把所有函數(shù)內(nèi)部定義的auto型局部變量放在

bankOo為節(jié)約寶貴的存儲空間,它

采用了一種被叫做“靜態(tài)覆蓋”的技術(shù)來實現(xiàn)局部變量的

地址分配。其大致的原理是在編譯

器編譯原代碼時掃描整個程序中函數(shù)調(diào)用的嵌套關(guān)系和層

次,算出每個函數(shù)中的局部變量字

節(jié)數(shù),然后為每個局部變量分配一個固定的地址,且按調(diào)用

嵌套的層次關(guān)系各變量的地址可

以相互重疊。利用這一技術(shù)后所有的動態(tài)局部變量都可以按

已知的固定地址地進(jìn)行直接尋

址,用PIC匯編指令實現(xiàn)的效率最高,但這時不能出現(xiàn)函

數(shù)遞歸調(diào)用。PICC在編譯時會嚴(yán)

格檢查遞歸調(diào)用的問題并認(rèn)為這是一個嚴(yán)重錯誤而立即終

止編譯過程。

既然所有的局部變量將占用banko的存儲空間,因此用戶

自己定位在bankO內(nèi)的變量字

節(jié)數(shù)將受到一定的限制,在實際使用時需注意。

11.5.5PICC中的位變量

bit型位變量只能是全局的或靜態(tài)的。PICC將把定位在同

一bank內(nèi)的8個位變量合并

成一個字節(jié)存放于一個固定地址。因此所有針對位變量的操

作將直接使用PIC單片機的位

操作匯編指令高效實現(xiàn)?;诖?,位變量不能是局部自動型

變量,也無法將其組合成復(fù)合型

高級變量。

PICC對整個數(shù)據(jù)存儲空間實行位編址,0x000單元的第0

位是位地址0x0000,以此后

推,每個字節(jié)有8個位地址。編制位地址的意義純粹是為

了編譯器最后產(chǎn)生匯編級位操作指

令而用,對編程人員來說基本可以不管。但若能了解位變量

的位地址編址方式就可以在最后

程序調(diào)試時方便地查找自己所定義的位變量,如果一個位變

量flagl被編址為0x123,那么

實際的存儲空間位于:

字節(jié)地址=0x123/8=0x24

位偏移=0xl23%8=3

即flagl位變量位于地址為0x24字節(jié)的第3位。在程序

調(diào)試時如果要觀察flagl的變化,必

須觀察地址為0x24的字節(jié)而不是0xl23o

PIC單片機的位操作指令是非常高效的。因此,PICC在編

譯原代碼時只要有可能,對

普通變量的操作也將以最簡單的位操作指令來實現(xiàn)。假設(shè)一

個字節(jié)變量tmp最后被定位在

地址0x20,那么

tmp|=0x80

tmp&二0xf7

=>bsf

=>bcf

0x20,7

0x20,3

if(tmp&Oxfe)

=>btfsc0x20,0

即所有只對變量中某一位操作的C語句代碼將被直接編譯

成匯編的位操作指令。雖然編程

時可以不用太關(guān)心,但如果能了解編譯器是如何工作的,那

將有助于引導(dǎo)我們寫出高效簡介

的C語言原程序。

在有些應(yīng)用中需要將一組位變量放在同一個字節(jié)中以便需

要時一次性地進(jìn)行讀寫,這一

功能可以通過定義一個位域結(jié)構(gòu)和一個字節(jié)變量的聯(lián)合來

實現(xiàn),例如:

union{

struct{

unsignedbO:1;

unsignedbl:1;

unsignedb2:1;

unsignedb3:1;

unsignedb4:1;

unsignedb5:1;

unsigned:2;〃最高兩位保留

}oneBit;

unsignedcharallBits;

}myFlag;

例n-3定義位變量于同一字節(jié)

需要存取其中某一位時可以

myFlag.oneBit.b3=l;//b3位置1

一次性將全部位清零時可以

myFlag.allBits=0;〃全部位變量清0

當(dāng)程序中把非位變量進(jìn)行強制類型轉(zhuǎn)換成位變量時,要注意

編譯器只對普通變量的最低

位做判別:如果最低位是0,則轉(zhuǎn)換成位變量0;如果最低

位是1,則轉(zhuǎn)換成位變量lo而標(biāo)

準(zhǔn)的ANSI-C做法是判整個變量值是否為0o另外,函數(shù)可

以返回一個位變量,實際上此返

回的位變量將存放于單片機的進(jìn)位位中帶出返回。

11.5.6PICC中的浮點數(shù)

PICC中描述浮點數(shù)是以IEEE-754標(biāo)準(zhǔn)格式實現(xiàn)的。此標(biāo)

準(zhǔn)下定義的浮點數(shù)為32位長,

在單片機中要用4個字節(jié)存儲。為了節(jié)約單片機的數(shù)據(jù)空

間和程序空間,PICC專門提供了

一種長度為24位的截短型浮點數(shù),它損失了浮點數(shù)的一點

精度,但浮點運算的效率得以提

高。在程序中定義的float型標(biāo)準(zhǔn)浮點數(shù)的長度固定為24

位,雙精度double型浮點數(shù)一般

也是24位長,但可以在程序編譯選項中選擇double型浮

點數(shù)為32位,以提高計算的精度。

一般控制系統(tǒng)中關(guān)心的是單片機的運行效率,因此在精度能

夠滿足的前提下盡量選擇

24位的浮點數(shù)運算。

11.5.7PICC中變量的絕對定位

首先必須強調(diào),在用C語言寫程序時變量一般由編譯器

和連接器最后定位,在寫程序

之時無需知道所定義的變量具體被放在哪個地址(除了

bank必須聲明)。

真正需要絕對定位的只是單片機中的那些特殊功能寄存器,

而這些寄存器的地址定位在

PICC編譯環(huán)境所提供的頭文件中已經(jīng)實現(xiàn),無需用戶操心。

編程員所要了解的也就是PICC

是如何定義這些特殊功能寄存器和其中的相關(guān)控制位的名

稱。好在PICC的定義標(biāo)準(zhǔn)基本上

按照芯片的數(shù)據(jù)手冊中的名稱描述進(jìn)行,這樣就秉承了變量

命名的一貫性。一個變量絕對定

位的例子如下:

unsignedchartmpData@0x20;//tmpData定位在地址

0x20

千萬注意,PICC對絕對定位的變量不保留地址空間。換句

話說,上面變量tmpData的

地址是0x20,但最后0x20處完全有可能又被分配給了其

它變量使用,這樣就發(fā)生了地址沖

突。因此針對變量的絕對定位要特別小心。從筆者的應(yīng)用經(jīng)

驗看,在一般的程序設(shè)計中用戶

自定義的變量實在是沒有絕對定位的必要。

如果需要,位變量也可以絕對定位。但必須遵循上面介紹的

位變量編址的方式。如果一

個普通變量已經(jīng)被絕對定位,那么此變量中的每個數(shù)據(jù)位就

可以用下面的計算方式實現(xiàn)位變

量指派:

unsignedchartmpData@0x20;//tmpData定位在地址

0x20

bittmpBitO@tmpData*8+0;//tmpBitO對應(yīng)于

tmpData第0位

bittmpBitl@tmpData*8+l;//tmpBitO對應(yīng)于

tmpData第1位

bittmpBit2@tmpData*8+2;//tmpBitO對應(yīng)于

tmpData第2位

如果tmpData事先沒有被絕對定位,那就不能用上面的位

變量定位方式。

11.5.8PICC的其它變量修飾關(guān)鍵詞

&01540;extern一外部變量聲明

如果在一個C程序文件中要使用一些變量但其原型定義

寫在另外的文件中,那么在本

文件中必須將這些變量聲明成"extern”外部類型。例如程

序文件codel.c中有如下定義:

banklunsignedcharvarl,var2;

〃定義了bankl中的兩個變量

在另外一個程序文件code2.c中要對上面定義的變量進(jìn)行

操作,則必須在程序的開頭定義:

externbanklunsignedcharvarl,var2;〃聲明

位于bankl的外部變量

&01540;volatile一易變型變量聲明

PICC中還有一個變量修飾詞在普通的C語言介紹中一

般是看不到的,這就是關(guān)鍵詞

“volatile”。顧名思義,它說明了一個變量的值是會隨機

變化的,即使程序沒有刻意對它進(jìn)

行任何賦值操作。在單片機中,作為輸入的10端口其內(nèi)容

將是隨意變化的;在中斷內(nèi)被修

改的變量相對主程序流程來講也是隨意變化的;很多特殊功

能寄存器的值也將隨著指令的運

行而動態(tài)改變。所有這種類型的變量必須將它們明確定義成

“volatile”類型,例如:

volatileunsignedcharSTATUS@0x03;

volatilebitcommFlag;

"volatile"類型定義在單片機的C語言編程中是

如此的重要,是因為它可以告訴編譯

器的優(yōu)化處理器這些變量是實實在在存在的,在優(yōu)化過程中

不能無故消除。假定你的程序定

義了一個變量并對其作了一次賦值,但隨后就再也沒有對其

進(jìn)行任何讀寫操作,如果是非

volatile型變量,優(yōu)化后的結(jié)果是這個變量將有可能被徹

底刪除以節(jié)約存儲空間。另外一種

情形是在使用某一個變量進(jìn)行連續(xù)的運算操作時,這個變量

的值將在第一次操作時被復(fù)制到

中間臨時變量中,如果它是非volatile型變量,則緊接其

后的其它操作將有可能直接從臨時

變量中取數(shù)以提高運行效率,顯然這樣做后對于那些隨機變

化的參數(shù)就會出問題。只要將其

定義成volatile類型后,編譯后的代碼就可以保證每次操

作時直接從變量地址處取數(shù)。

&01540;const—常數(shù)型變量聲明

如果變量定義前冠以“const”類型修飾,那么所有這些變

量就成為常數(shù),程序運行過

程中不能對其修改。除了位變量,其它所有基本類型的變量

或高級組合變量都將被存放在程

序空間(ROM區(qū))以節(jié)約數(shù)據(jù)存儲空間。顯然,被定義在ROM

區(qū)的變量是不能再在程序

中對其進(jìn)行賦值修改的,這也是“const”的本來意義。實

際上這些數(shù)據(jù)最終都將以“retlw”

的指令形式存放在程序空間,但PICC會自動編譯生成相關(guān)

的附加代碼從程序空間讀取這些

常數(shù),編程員無需太多操心。例如:

constunsignedcharname口=“Thisisademo";//定

義一個常量字符串

如果定義了“const”類型的位變量,那么這些位變量還

是被放置在RAM中,但程序

不能對其賦值修改。本來,不能修改的位變量沒有什么太多

的實際意義,相信大家在實際編

程時不會大量用到。

&01540;persistent一非初始化變量聲明

按照標(biāo)準(zhǔn)C語言的做法,程序在開始運行前首先要把所

有定義的但沒有預(yù)置初值的變

量全部清零。PICC會在最后生成的機器碼中加入一小段初

始化代碼來實現(xiàn)這一變量清零操

作,且這一操作將在main函數(shù)被調(diào)用之前執(zhí)行。問題是作

為一個單片機的控制系統(tǒng)有很多

變量是不允許在程序復(fù)位后被清零的。為了達(dá)到這一目的,

PICC提供了“persistent”修飾

詞以聲明此類變量無需在復(fù)位時自動清零,編程員應(yīng)該自己

決定程序中的那些變量是必須聲

明成“persisted類型,而且須自己判斷什么時候需要對

其進(jìn)行初始化賦值。例如:

persistentunsignedcharhour,minute,second;〃定義

時分秒變量

經(jīng)常用到的是如果程序經(jīng)上電復(fù)位后開始運行,那么需要將

persistent型的變量初始化,

如果是其它形式的復(fù)位,例如看門狗引發(fā)的復(fù)位,則無需對

persistent型變量作任何修改。

PIC單片機內(nèi)提供了各種復(fù)位的判別標(biāo)志,用戶程序可依

具體設(shè)計靈活處理不同的復(fù)位情

形。

11.5.9PICC中的指針

PICC中指針的基本概念和標(biāo)準(zhǔn)C語法沒有太多的差別。但

是在PIC單片機這一特定的

架構(gòu)上,指針的定義方式還是有兒點需要特別注意。

&01540;指向RAM的指針

如果是匯編語言編程,實現(xiàn)指針尋址的方法肯定就是用FSR

寄存器,PICC也不例外。

為了生成高效的代碼,PICC在編譯C原程序時將指向RAM

的指針操作最終用FSR來實現(xiàn)

間接尋址。這樣就勢必產(chǎn)生一個問題:FSR能夠直接連續(xù)尋

址的范圍是256字節(jié)(bankO/1

或bank2/3),要覆蓋最大512字節(jié)的內(nèi)部數(shù)據(jù)存儲空間,

又該如何讓定義指針?PICC還是

將這一問題留給編程員自己解決:在定義指針時必須明確指

定該指針?biāo)m用的尋址區(qū)域,例

如:

unsignedchar*ptrO;〃①定義覆蓋bankO/1的指針

bank2unsignedchar*ptrl;〃②定義覆蓋bank2/3的

指針

bank3unsignedchar*ptr2;〃③定義覆蓋bank2/3的

指針

上面定義了三個指針變量,其中①指針沒有任何bank限

定,缺省就是指向bankO和bankl;

②和③一個指明了bank2,另一個指明了bank3,但實際上

兩者是一樣的,因為一個指針可

以同時覆蓋兩個bank的存儲區(qū)域。另外,上面三個指針變

量自身都存放在bankO中。我們

將在稍后介紹如何在其它bank中存放指針變量。

既然定義的指針有明確的bank適用區(qū)域,在對指針變量賦

值時就必須實現(xiàn)類型匹配,

F面的指針賦值將產(chǎn)生一個致命錯誤:

unsignedchar*ptrO;

bank2unsignedcharbuff[8];

程序語句:

〃定義指向bankO/1的指針

〃定義bank2中的一個緩沖區(qū)

ptrO二buff;〃錯誤!試圖將bank2內(nèi)的變量地址賦給

指向bankO/1的指針

若出現(xiàn)此類錯誤的指針操作,PICC在最后連接時會告知類

似于下面的信息:

Fixupoverflowinexpression(...)

同樣的道理,若函數(shù)調(diào)用時用了指針作為傳遞參數(shù),也必須

注意bank作用域的匹配,

而這點往往容易被忽視。假定有下面的函數(shù)實現(xiàn)發(fā)送一個字

符串的功能:

voidSendMessage(unsignedchar*);

那么被發(fā)送的字符串必須位于bankO或bankl中。如果你

還要發(fā)送位于bank2或bank3內(nèi)的

字符串,必須再另外單獨寫一個函數(shù):

voidSendMessage_2(bank2unsignedchar*);

這兩個函數(shù)從內(nèi)部代碼的實現(xiàn)來看可以一模一樣,但傳遞的

參數(shù)類型不同。

按筆者的應(yīng)用經(jīng)驗體會,如果你看到了“Fixupoverflow"

的錯誤指示,幾乎可以肯定

是指針類型不匹配的賦值所至。請重點檢查程序中有關(guān)指針

的操作。

&01540;指向ROM常數(shù)的指針

如果一組變量是已經(jīng)被定義在ROM區(qū)的常數(shù),那么指向它

的指針可以這樣定義:

constunsignedcharcompanyMicrochipv;

constunsignedchar*romPtr;

程序中可以對上面的指針變量賦值和實現(xiàn)取數(shù)操作:

romPtr=company;〃指針賦初值

data=*romPtr++;〃取指針指向的一個數(shù),然后指針加1

〃定義ROM中的常數(shù)

〃定義指向ROM的指針

反過來,下面的操作將是一個錯誤,因為該指針指向的是常

數(shù)型變量,不能賦值。

*romPtr=data;〃往指針指向的地址寫一個數(shù)

&01540;指向函數(shù)的指針

單片機編程時函數(shù)指針的應(yīng)用相對較少,但作為標(biāo)準(zhǔn)c語

法的一部分,PICC同樣支持

函數(shù)指針調(diào)用。如果你對編譯原理有一定的了解,就應(yīng)該明

白在PIC單片機這一特定的架

構(gòu)上實現(xiàn)函數(shù)指針調(diào)用的效率是不高的:PICC將在RAM中

建立一個調(diào)用返回表,真正的

調(diào)用和返回過程是靠直接修改PC指針來實現(xiàn)的。因此,除

非特殊算法的需要,建議大家盡

量不要使用函數(shù)指針。

&01540;指針的類型修飾

前面介紹的指針定義都是最基本的形式。和普通變量一樣,

指針定義也可以在前面加上

特殊類型的修飾關(guān)鍵詞,例如“persistent”、

“volatile”等??紤]指針本身還要限定其作用域,

因此PICC中的指針定義初看起來顯得有點復(fù)雜,但只要了

解各部分的具體含義,理解一個

指針的實際用圖就變得很直接。

㈠bank修飾詞的位置含義

前面介紹的一些指針有的作用于bankO/1,有的作用于

bank2/3,但它們本身的存放位置

全部在bankOo顯然,在一個程序設(shè)計中指針變量將有可能

被定位在任何可用的地址空間,

這時,bank修飾詞出現(xiàn)的位置就是一個關(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修飾詞的位置含義,實際上

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)在前面的修飾詞其作用對象是指針?biāo)柑幍淖兞浚?/p>

出現(xiàn)在后面的修飾詞其作用對象

就是指針變量自己。

11.6

PICC中的子程序和函數(shù)

中檔系列的PIC單片機程序空間有分頁的概念,但用C語

言編程時基本不用太多關(guān)心

代碼的分頁問題。因為所有函數(shù)或子程序調(diào)用時的頁面設(shè)定

(如果代碼超過一個頁面)都由

編譯器自動生成的指令實現(xiàn)。

11.6.1函數(shù)的代碼長度限制

PICC決定了C原程序中的一個函數(shù)經(jīng)編譯后生成的機器

碼一定會放在同一個程序頁面

內(nèi)。中檔系列的PIC單片機其一個程序頁面的長度是2K

字,換句話說,用C語言編寫的任

何一個函數(shù)最后生成的代碼不能超過2K字。一個良好的程

序設(shè)計應(yīng)該有一個清晰的組織結(jié)

構(gòu),把不同的功能用不同的函數(shù)實現(xiàn)是最好的方法,因此一

個函數(shù)2K字長的限制一般不會

對程序代碼的編寫產(chǎn)生太多影響。如果為實現(xiàn)特定的功能確

實要連續(xù)編寫很長的程序,這時

就必須把這些連續(xù)的代碼拆分成若干函數(shù),以保證每個函數(shù)

最后編譯出的代碼不超過一個頁

面空間。

11.6.2調(diào)用層次的控制

中檔系列PIC單片機的硬件堆棧深度為8級,考慮中斷響

應(yīng)需占用一級堆棧,所

有函數(shù)調(diào)用嵌套的最大深度不要超過7級。編程員必須自

己控制子程序調(diào)用時的嵌套深

度以符合這一限制要求。

PICC在最后編譯連接成功后可以生成一個連接定位映射文

件(*.map),在此文件

中有詳細(xì)的函數(shù)調(diào)用嵌套指示圖“callgraph”,建議大家

要留意一下。其信息大致如下

(取自于一示范程序的編譯結(jié)果):

Callgraph:

*_mainsize0,0offset0

RightShiftC

*_Tasksize0,1offset0

Iwtoft

ftmulsize0,0offset0

ftunpack1

ftunpack2

ftaddsize0,0offset0

ftunpack1

ftunpack2

ftdenorm

例n-4c函數(shù)調(diào)用層次圖

上面所舉的信息表明整個程序在正常調(diào)用子程序時嵌套最

多為兩級(沒有考慮中斷)。因為

main函數(shù)不可能返回,故其不用計算在嵌套級數(shù)中。其中

有些函數(shù)調(diào)用是編譯代碼時自動

加入的庫函數(shù),這些函數(shù)調(diào)用從c原程序中無法直接看出,

但在此嵌套指示圖上則一目了

然。

11.6.3函數(shù)類型聲明

PICC在編譯時將嚴(yán)格進(jìn)行函數(shù)調(diào)用時的類型檢查。一個良

好的習(xí)慣是在編寫程序代碼

前先聲明所有用到的函數(shù)類型。例如:

voidTask(void);

unsignedcharTemperature(void);

voidBIN2BCD(unsignedchar);

voidTimeDisplay(unsignedchar,unsignedchar);

這些類型聲明確定了函數(shù)的入口參數(shù)和返回值類型,這樣編

譯器在編譯代碼時就能保證生成

正確的機器碼。筆者在實際工作中有時碰到一些用戶聲稱發(fā)

現(xiàn)C編譯器生成了錯誤的代碼,

最后究其原因就是因為沒有事先聲明函數(shù)類型所致。

建議大家在編寫一個函數(shù)的原代碼時,立即將此函數(shù)的類型

聲明復(fù)制到原文件的起始

處,見例11T;或是復(fù)制到專門的包含頭文件中,再在每

個原程序模塊中引用。

11.6.4中斷函數(shù)的實現(xiàn)

PICC可以實現(xiàn)C語言的中斷服務(wù)程序。中斷服務(wù)程序有一

個特殊的定義方法:

voidinterruptISR(void);

其中的函數(shù)名“ISR”可以改成任意合法的字母或數(shù)字組

合,但其入口參數(shù)和返回參數(shù)類型

必須是“void”型,亦即沒有入口參數(shù)和返回參數(shù),且中間

必須有一個關(guān)鍵詞“interrupt”。

中斷函數(shù)可以被放置在原程序的任意位置。因為已有關(guān)鍵詞

“interrupt”聲明,PICC在

最后進(jìn)行代碼連接時會自動將其定位到0x0004中斷入口

處,實現(xiàn)中斷服務(wù)響應(yīng)。編譯器也

會實現(xiàn)中斷函數(shù)的返回指令“retfie"。一個簡單的中斷服

務(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ù)舉例

PICC會自動加入代碼實現(xiàn)中斷現(xiàn)場的保護(hù),并在中斷結(jié)束

時自動恢復(fù)現(xiàn)場,所以編程

員無需象編寫匯編程序那樣加入中斷現(xiàn)場保護(hù)和恢復(fù)的額

外指令語句。但如果在中斷服務(wù)程

序中需要修改某些全局變量時,是否需要保護(hù)這些變量的初

值將由編程員自己決定和實施。

用C語言編寫中斷服務(wù)程序必須遵循高效的原則:

&01540;代碼盡量簡短,中斷服務(wù)強調(diào)的是一個“快”

字。

&01540;避免在中斷內(nèi)使用函數(shù)調(diào)用。雖然PICC允許

在中斷里調(diào)用其它函數(shù),但為了解決

遞歸調(diào)用的問題,此函數(shù)必須為中斷服務(wù)獨家專用。既如此,

不妨把原本要寫在其

它函數(shù)內(nèi)的代碼直接寫在中斷服務(wù)程序中。

&01540;避免在中斷內(nèi)進(jìn)行數(shù)學(xué)運算。數(shù)學(xué)運算將很有

可能用到庫函數(shù)和許多中間變量,就

算不出現(xiàn)遞歸調(diào)用的問題,光在中斷入口和出口處為了保護(hù)

和恢復(fù)這些中間臨時變

量就需要大量的開銷,嚴(yán)重影響中斷服務(wù)的效率。

中檔系列PIC單片機的中斷入口只有一個,因此整個程序

中只能有一個中斷服務(wù)函數(shù)。

11.6.5標(biāo)準(zhǔn)庫函數(shù)

Pice提供了較完整的C標(biāo)準(zhǔn)庫函數(shù)支持,其中包括數(shù)學(xué)運

算函數(shù)和字符串操作函數(shù)。

在程序中使用這些現(xiàn)成的庫函數(shù)時需要注意的是入口參數(shù)

必須在bankO中。

如果需要用到數(shù)學(xué)函數(shù),則應(yīng)在程序前“include”

包含頭文件;如果要使

用字符串操作函數(shù),就需要包含“include”頭文件。在

這些頭文件中提供了函數(shù)

類型的聲明。通過直接查看這些頭文件就可以知道PICC提

供了哪些標(biāo)準(zhǔn)庫函數(shù)。

C語言中常用的格式化打印函數(shù)“printf/sprintf”用在

單片機的程序中時要特別謹(jǐn)慎。

printf/sprintf是一個非常大的函數(shù),一旦使用,你的程

序代碼長度就會增加很多。除非是在

編寫試驗性質(zhì)的代碼,可以考慮使用格式化打印函數(shù)以簡化

測試程序;一般的最終產(chǎn)品設(shè)計

都是自己編寫最精簡的代碼實現(xiàn)特定格式的數(shù)據(jù)顯示和輸

出。本來,在單片機應(yīng)用中輸出的

數(shù)據(jù)格式都相對簡單而且固定,實現(xiàn)起來應(yīng)該很容易。

對于標(biāo)準(zhǔn)C語言的控制臺輸入(scanf)/輸出(printf)

函數(shù),PICC需要用戶自己編寫

其底層函數(shù)getchO和putchOo在單片機系統(tǒng)中實現(xiàn)

scanf/printf本來就沒什么太多意義,如

果一定要實現(xiàn),只要編寫好特定的getchO和putchO函

數(shù),你就可以通過任何接口輸入或輸

出格式化的數(shù)據(jù)。

11.7

PICC定義特殊區(qū)域值

PICC提供了相關(guān)的預(yù)處理指令以實現(xiàn)在原程序中定義單片

機的配置字和標(biāo)記單元。

11.7.1定義工作配置字

在原程序中定義PIC單片機工作配置字的重要性在前面章

節(jié)中已經(jīng)闡述。在用PICC寫

程序時同樣可以在c原程序中定義,具體方式如下:

_CONFIG(HS&UNPROTECT&PWRTEN&BORDIS&WDTEN);

上面的關(guān)鍵詞“—CONFIG”(注意前面有兩個下劃線符)專

門用于是芯片配置字的設(shè)

定,后面括號中的各項配置位符號在特定型號單片機的頭文

件中已經(jīng)定義(注意不是pic.h

頭文件),相互之間用邏輯“與”操作符組合在一起。這樣

定義的配置字信息最后將和程序

代碼一起放入同一個HEX文件。

在這里列出了適用于16F7x系列單片機配置位符號預(yù)定

義,其它型號或系列的單片機

配置字定義方式類似,使用前查閱一下對應(yīng)的頭文件即可。

/*振蕩器配置*/

#defineRC

^defineHS

0x3FFF//RC振蕩

0x3FFE//HS模式

^defineXT

ttdefineLP

/*看門狗配置*/

Ox3FFD//XT模式

Ox3FFC//LP模式

ttdefineWDTEN0x3FFF//看門狗打開

#defineWDTDIS

/*上電延時定時器配置*/

ftdefinePWRTEN

0x3FFB//看門狗關(guān)閉

0x3FF7//上電延時定時

溫馨提示

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

最新文檔

評論

0/150

提交評論