PIC單片機C語言編程教程_第1頁
PIC單片機C語言編程教程_第2頁
PIC單片機C語言編程教程_第3頁
PIC單片機C語言編程教程_第4頁
PIC單片機C語言編程教程_第5頁
免費預覽已結束,剩余46頁可下載查看

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、PICPIC 單片機 C C 語言編程簡介用 C C 語言來開發單片機系統軟件最大的好處是編寫代碼效率高、軟件調試直觀、維護升級方便、代碼的重復利用率高、便于跨平臺的代碼移植等等,因此 C C 語言編程在單片機系統設計中已得到越來越廣泛的運用。針對 PICPIC 單片機的軟件開發,同樣可以用 C C 語言實現。但在單片機上用 C 語言寫程序和在 PC 機上寫程序絕對不能簡單等同。現在的 PC 機資源十分豐富,運算能力強大,因此程序員在寫 PC 機的應用程序時幾乎不用關心編譯后的可執行代碼在運行過程中需要占用多少系統資源,也基本不用擔心運行效率有多高。寫單片機的 C 程序最關鍵的一點是單片機內的

2、資源非常有限,控制的實時性要求又很高,因此,如果沒有對單片機體系結構和硬件資源作詳盡的了解,以筆者的愚見認為是無法寫出高質量實用的 C 語言程序。這就是為什么前面所有章節中的的示范代碼全部用基礎的匯編指令實現的原因,希望籍此能使讀者對 PIC 單片機的指令體系和硬件資源有深入了解,在這基礎之上再來討論 C 語言編程,就有水到渠成的感覺。本書圍繞中檔系列 PIC 單片機來展開討論,Microchip 公司自己沒有針對中低檔系列 PIC單片機的 C 語言編譯器,但很多專業的第三方公司有眾多支持 PIC 單片機的 C 語言編譯器提供,常見的有 Hitech、CCS、IAR、Bytecraft 等公司

3、。其中筆者最常用的是 Hitech 公司的PICC 編譯器,它穩定可靠,編譯生成的代碼效率高,在用 PIC 單片機進行系統設計和開發的工程師群體中得到廣泛認可。其正式完全版軟件需要購置,但在其網站上有限時的試用版供用戶評估。另外,Hitech 公司針對廣大 PIC 的業余愛好者和初學者還提供了完全免費的學習版 PICC-Lite 編譯器套件,它的使用方式和完全版相同,只是支持的 PIC 單片機型號限制在 PIC16F84、PIC16F877 和 PIC16F628 等幾款。這幾款 Flash 型的單片機因其所具備的豐富的片上資源而最適用于單片機學習入門,因此筆者建議感興趣的讀者可從 PICC-

4、Lite 入手掌握 PIC 單片機的 C 語言編程。在此列出幾個主要的針對 PIC 單片機的 C 編譯器相關連接網址,供讀者參考:Hitech-PICC:IAR:CCS: Hitech-PICC 編譯器的一些基本概念,由于篇幅所限將不涉及 C 語言的標準語法和基礎知識介紹,因為在這些方面都有大量的書籍可以參考。重點突出針對 PIC 單片機的特點而所需要特別注意的地方。11.2Hitech-PICC 編譯器PICC 基本上符合 ANSI 標準,除了一點:它不支持函數的遞歸調用。其主要原因是因為 PIC 單片機特殊的堆棧結構。在前面介紹 PIC 單片機架構時已經詳細說明了 PIC 單片機中的堆棧是

5、硬件實現的,其深度已隨芯片而固定,無法實現需要大量堆棧操作的遞歸算法;另外在 PIC 單片機中實現軟件堆棧的效率也不是很高,為此,PICC 編譯器采用一種叫做靜態覆蓋”的技術以實現對 C 語言函數中的局部變量分配固定的地址空間。經這樣處理后產生出的機器代碼效率很高,按筆者實際使用的體會,當代碼量超過 4K 字后,C 語言編譯出的代碼長度和全部用匯編代碼實現時的差別已經不是很大(bsf0 x20,70 x20,3if(tmp&0 xfe)=btfsc0 x20,0即所有只對變量中某一位操作的 C 語句代碼將被直接編譯成匯編的位操作指令。雖然編程時可以不用太關心,但如果能了解編譯器是如何工

6、作的,那將有助于引導我們寫出高效簡介的 C 語言原程序。在有些應用中需要將一組位變量放在同一個字節中以便需要時一次性地進行讀寫,這一功能可以通過定義一個位域結構和一個字節變量的聯合來實現,例如:=bcfunionstructunsignedb0:1;unsignedb1:1;unsignedb2:1;unsignedb3:1;unsignedb4:1;unsignedb5:1;unsigned:2;最高兩位保留oneBit;unsignedcharallBits;myFlag;例 11-3 定義位變量于同一字節需要存取其中某一位時可以myFlag.oneBit.b3=1;/b3 位置 1一次性

7、將全部位清零時可以當程序中把非位變量進行強制類型轉換成位變量時,要注意編譯器只對普通變量的最低位做判別:如果最低位是 0,則轉換成位變量 0;如果最低位是 1,則轉換成位變量 1。而標myFlag.allBits=0;/全部位變量清 0準的 ANSI-C 做法是判整個變量值是否為 0。另外,函數可以返回一個位變量,實際上此返回的位變量將存放于單片機的進位位中帶出返回。PICC 中的浮點數PICC 中描述浮點數是以 IEEE-754 標準格式實現的。此標準下定義的浮點數為 32 位長,在單片機中要用 4 個字節存儲。為了節約單片機的數據空間和程序空間,PICC 專門提供了一種長度為 24 位的截

8、短型浮點數,它損失了浮點數的一點精度,但浮點運算的效率得以提高。在程序中定義的 float 型標準浮點數的長度固定為 24 位,雙精度 double 型浮點數一般也是 24 位長,但可以在程序編譯選項中選擇 double 型浮點數為 32 位,以提高計算的精度。一般控制系統中關心的是單片機的運行效率,因此在精度能夠滿足的前提下盡量選擇24 位的浮點數運算。PICC 中變量的絕對定位首先必須強調,在用 C 語言寫程序時變量一般由編譯器和連接器最后定位,在寫程序真正需要絕對定位的只是單片機中的那些特殊功能寄存器,而這些寄存器的地址定位在PICC 編譯環境所提供的頭文件中已經實現,無需用戶操心。編程

9、員所要了解的也就是 PICC是如何定義這些特殊功能寄存器和其中的相關控制位的名稱。好在 PICC 的定義標準基本上按照芯片的數據手冊中的名稱描述進行,這樣就秉承了變量命名的一貫性。一個變量絕對定位的例子如下:unsignedchartmpData0 x20;/tmpData 定位在地址 0 x20千萬注意,PICC 對絕對定位的變量不保留地址空間。換句話說,上面變量 tmpData 的地址是 0 x20,但最后 0 x20 處完全有可能又被分配給了其它變量使用,這樣就發生了地址沖突。因此針對變量的絕對定位要特別小心。從筆者的應用經驗看,在一般的程序設計中用戶自定義的變量實在是沒有絕對定位的必要

10、。如果需要,位變量也可以絕對定位。但必須遵循上面介紹的位變量編址的方式。如果一個普通變量已經被絕對定位,那么此變量中的每個數據位就可以用下面的計算方式實現位變量指派:unsignedchartmpData0 x20;/tmpData 定位在地址 0 x20bittmpBit0tmpData*8+0;/tmpBit0 對應于 tmpData 第 0 位之時無需知道所定義的變量具體被放在哪個地址(除了bank 必須聲明)/tmpBit0 對應于 tmpData 第 1 位/tmpBit0 對應于 tmpData 第 2 位如果 tmpData 事先沒有被絕對定位,那就不能用上面的位變量定位方式。P

11、ICC 的其它變量修飾關鍵詞&O1540;extern 一外部變量聲明如果在一個 C 程序文件中要使用一些變量但其原型定義寫在另外的文件中,那么在本文件中必須將這些變量聲明成extern 外部類型。例如程序文件 code1.c 中有如下定義:bank1unsignedcharvar1,var2;/定義了 bank1 中的兩個變量在另外一個程序文件 code2.c 中要對上面定義的變量進行操作,則必須在程序的開頭定義:bittmpBit1tmpData*8+1;bittmpBit2tmpData*8+2;externbanklunsignedcharvarl,var2;&O154

12、0;volatile 一易變型變量聲明PICC 中還有一個變量修飾詞在普通的 C 語言介紹中一般是看不到的,這就是關鍵詞“volatile。顧名思義,它說明了一個變量的值是會隨機變化的,即使程序沒有刻意對它進行任何賦值操作。在單片機中,作為輸入的 IO 端口其內容將是隨意變化的;在中斷內被修改的變量相對主程序流程來講也是隨意變化的;很多特殊功能寄存器的值也將隨著指令的運行而動態改變。所有這種類型的變量必須將它們明確定義成“volatile 類型,例如:volatileunsignedcharSTATUS0 x03;volatilebitcommFlag;“volatil 聯型定義在單片機的 C

13、 語言編程中是如此的重要,是因為它可以告訴編譯器的優化處理器這些變量是實實在在存在的,在優化過程中不能無故消除。假定你的程序定義了一個變量并對其作了一次賦值,但隨后就再也沒有對其進行任何讀寫操作,如果是非 volatile 型變量,優化后的結果是這個變量將有可能被徹底刪除以節約存儲空間。另外一種情形是在使用某一個變量進行連續的運算操作時,這個變量的值將在第一次操作時被復制到聲明位于 bankl 的外部變量中間臨時變量中,如果它是非 volatile 型變量,則緊接其后的其它操作將有可能直接從臨時變量中取數以提高運行效率,顯然這樣做后對于那些隨機變化的參數就會出問題。只要將其定義成volatil

14、e 類型后,編譯后的代碼就可以保證每次操作時直接從變量地址處取數。&O1540;const 一常數型變量聲明如果變量定義前冠以“const 類型修飾,那么所有這些變量就成為常數,程序運行過程中不能對其修改。除了位變量,其它所有基本類型的變量或高級組合變量都將被存放在程序空間(ROM 區)以節約數據存儲空間。顯然,被定義在 ROM 區的變量是不能再在程序中對其進行賦值修改的,這也是“const 的本來意義。實際上這些數據最終都將以“retlw的指令形式存放在程序空間,但 PICC 會自動編譯生成相關的附加代碼從程序空間讀取這些常數,編程員無需太多操心。例如:constunsignedch

15、arname 口=Thiisademo;/定義一個常量字符串如果定義了“const 類型的位變量,那么這些位變量還是被放置在 RAM 中,但程序不能對其賦值修改。本來,不能修改的位變量沒有什么太多的實際意義,相信大家在實際編程時不會大量用到。按照標準 C 語言的做法,程序在開始運行前首先要把所有定義的但沒有預置初值的變量全部清零。PICC 會在最后生成的機器碼中加入一小段初始化代碼來實現這一變量清零操作,且這一操作將在 main 函數被調用之前執行。問題是作為一個單片機的控制系統有很多變量是不允許在程序復位后被清零的。為了達到這一目的,PICC 提供了“persistent 修飾詞以聲明此類變

16、量無需在復位時自動清零,編程員應該自己決定程序中的那些變量是必須聲明成“persisten 類型,而且須自己判斷什么時候需要對其進行初始化賦值。例如:persistentunsignedcharhour,minute,second;/定義時分秒變量經常用到的是如果程序經上電復位后開始運行,那么需要將 persistent 型的變量初始化,如果是其它形式的復位,例如看門狗引發的復位,則無需對 persistent 型變量作任何修改。PIC 單片機內提供了各種復位的判別標志、用戶程序可依具體設計靈活處理不同的復位情形。PICC 中的指針PICC 中指針的基本概念和標準 C 語法沒有太多的差別。但是

17、在 PIC 單片機這一特定的架構上,指針的定義方式還是有幾點需要特別注意。&O1540;指向 RAM 的指針為了生成高效的代碼,PICC 在編譯 C 原程序時將指向 RAM 的指針操作最終用 FSR 來實現間接尋址。這樣就勢必產生一個問題:FSR 能夠直接連續尋址的范圍是 256 字節(bank0/1或 bank2/3),要覆蓋最大 512 字節的內部數據存儲空間,又該如何讓定義指針?PICC 還是將這一問題留給編程員自己解決:在定義指針時必須明確指定該指針所適用的尋址區域,例如:unsignedchar*ptr0;/定義覆蓋 bank0/1 的指針bank2unsignedchar*

18、ptr1;/定義覆蓋 bank2/3 的指針bank3unsignedchar*ptr2;/定義覆蓋 bank2/3 的指針上面定義了三個指針變量,其中指針沒有任何 bank 限定,缺省就是指向 bank0 和 bank1;和一個指明了 bank2,另一個指明了 bank3,但實際上兩者是一樣的,因為一個指針可以同時覆蓋兩個 bank 的存儲區域。另外,上面三個指針變量自身都存放在 bank0 中。我們將在稍后介紹如何在其它 bank 中存放指針變量。既然定義的指針有明確的 bank 適用區域,在對指針變量賦值時就必須實現類型匹配,下面的指針賦值將產生一個致命錯誤:如果是匯編語言編程,實現指針

19、尋址的方法肯定就是用FSR 寄存器,PICC 也不例外unsignedchar*ptr0;bank2unsignedcharbuff8;程序語句:/定義指向 bank0/1 的指針/定義 bank2 中的一個緩沖區ptr0=buff;錯誤!試圖將 bank2 內的變量地址賦給指向 bank0/1 的指針若出現此類錯誤的指針操作,PICC 在最后連接時會告知類似于下面的信息:Fixupoverflowinexpression(.)同樣的道理,若函數調用時用了指針作為傳遞參數,也必須注意 bank 作用域的匹配,而這點往往容易被忽視。假定有下面的函數實現發送一個字符串的功能:voidSendMes

20、sage(unsignedchar*);那么被發送的字符串必須位于 bank0 或 bank1 中。如果你還要發送位于 bank2 或 bank3 內的字符串,必須再另外單獨寫一個函數:voidSendMessage_2(bank2unsignedchar*);這兩個函數從內部代碼的實現來看可以一模一樣,但傳遞的參數類型不同。按筆者的應用經驗體會,如果你看到了 Tixupoverflow”的錯誤指示,幾乎可以肯定是指針類型不匹配的賦值所至。請重點檢查程序中有關指針的操作。&O1540;指向 ROM 常數的指針如果一組變量是已經被定義在 ROM 區的常數,那么指向它的指針可以這樣定義:c

21、onstunsignedcharcompany=Microchip”;constunsignedchar*romPtr;程序中可以對上面的指針變量賦值和實現取數操作:romPtr=company;/指針賦初值data=*romPtr+;/取指針指向的一個數,然后指針加 1/定義 ROM 中的常數反過來,下面的操作將是一個錯誤,因為該指針指向的是常數型變量,不能賦值*romPtr=data;往指針指向的地址寫一個數&O1540;指向函數的指針單片機編程時函數指針的應用相又祗$少,但作為標準 C 語法的一部分,PICC 同樣支持函數指針調用。如果你對編譯原理有一定的了解,就應該明白在 PI

22、C 單片機這一特定的架構上實現函數指針調用的效率是不高的:PICC 將在 RAM 中建立一個調用返回表,真正的調用和返回過程是靠直接修改 PC 指針來實現的。因此,除非特殊算法的需要,建議大家盡量不要使用函數指針。&O1540;指針的類型修飾前面介紹的指針定義都是最基本的形式。和普通變量一樣,指針定義也可以在前面加上特殊類型的修飾關鍵詞,例如persistent、volatile 等考慮指針本身還要限定其作用域,因此 PICC 中的指針定義初看起來顯得有點復雜,但只要了解各部分的具體含義,理解一個指針的實際用圖就變得很直接。bank 修飾詞的位置含義前面介紹的一些指針有的作用于 ban

23、k0/1,有的作用于 bank2/3,但它們本身的存放位置全部在 bank。顯然,在一個程序設計中指針變量將有可能被定位在任何可用的地址空間,這時,bank 修飾詞出現的位置就是一個關鍵,看下面的例子:/定義指向 bank0/1 的指針,指針變量為于 bank0 中unsignedchar*ptr0;/定義指向 bank2/3 的指針,指針變量為于 bank0 中bank2unsignedchar*ptr0;/定義指向 bank2/3 的指針,指針變量為于 bankl 中bank2unsignedchar*banklptr0;從中可以看出規律:前面的 bank 修飾詞指明了此指針的作用域;后面

24、的 bank 修飾詞定義了此指針變量自身的存放位置。只要掌握了這一法則,你就可以定義任何作用域的指針且可以將指針變量放于任何 bank 中。volatile、persistent 和 const 修飾詞的位置含義如果能理解上面介紹的 bank 修飾詞的位置含義,實際上 volatilepersistent 和 const 這些關鍵詞出現在前后不同位置上的含義規律是和 bank 一詞相一致的。例如:/定義指向 bank0/1 易變型字符變量的指針,指針變量位于 bank0 中且自身為非易變型volatileunsignedchar*ptr0;/定義指向 bank2/3 非易變型字符變量的指針,指

25、針變量位于 bankl 中且自身為易變型bank2unsignedchar*volatilebanklptr0;/定義指向 ROM 區的指針,指針變量本身也是存放于 ROM 區的常數constunsignedchar*constptr0;亦即出現在前面的修飾詞其作用對象是指針所指處的變量;出現在后面的修飾詞其作用對象就是指針變量自己。11.6PICC 中的子程序和函數中檔系列的 PIC 單片機程序空間有分頁的概念,但用 C 語言編程時基本不用太多關心代碼的分頁問題。因為所有函數或子程序調用時的頁面設定(如果代碼超過一個頁面)都由編譯器自動生成的指令實現。PICC 決定了 C 原程序中的一個函數

26、經編譯后生成的機器碼一定會放在同一個程序頁面11.6.1函數的代碼長度限制內。中檔系列的 PIC 單片機其一個程序頁面的長度是 2K 字,換句話說,用 C 語言編寫的任何一個函數最后生成的代碼不能超過 2K 字。一個良好的程序設計應該有一個清晰的組織結構,把不同的功能用不同的函數實現是最好的方法,因此一個函數 2K 字長的限制一般不會對程序代碼的編寫產生太多影響。如果為實現特定的功能確實要連續編寫很長的程序,這時就必須把這些連續的代碼拆分成若干函數,以保證每個函數最后編譯出的代碼不超過一個頁面空間。11.6.2 調用層次的控制中檔系列 PIC 單片機的硬件堆棧深度為 8 級,考慮中斷響應需占用

27、一級堆棧,所有函數調用嵌套的最大深度不要超過 7 級。編程員必須自己控制子程序調用時的嵌套深度以符合這一限制要求。PICC 在最后編譯連接成功后可以生成一個連接定位映射文件(*.map),在此文件中有詳細的函數調用嵌套指示圖“callgraph”,建議大家要留意一下。其信息大致如下(取自于一示范程序的編譯結果):Callgraph:*_mainsize0,0offset0_RightShift_C*_Tasksize0,1offset0Iwtoftftmulsize0,0offset0ftunpack1ftunpack2ftaddsize0,0offset0ftunpack1ftunpack2

28、ftdenorm 例 11-4C 函數調用層次圖上面所舉的信息表明整個程序在正常調用子程序時嵌套最多為兩級(沒有考慮中斷)。因為 main 函數不可能返回,故其不用計算在嵌套級數中。其中有些函數調用是編譯代碼時自動加入的庫函數,這些函數調用從 C 原程序中無法直接看出,但在此嵌套指示圖上則一目了然。PICC 在編譯時將嚴格進行函數調用時的類型檢查。一個良好的習慣是在編寫程序代碼前先聲明所有用到的函數類型。例如:voidTask(void);unsignedcharTemperature(void);voidBIN2BCD(unsignedchar);voidTimeDisplay(unsign

29、edchar,unsignedchar);這些類型聲明確定了函數的入口參數和返回值類型,這樣編譯器在編譯代碼時就能保證生成正確的機器碼。筆者在實際工作中有時碰到一些用戶聲稱發現 C 編譯器生成了錯誤的代碼,最后究其原因就是因為沒有事先聲明函數類型所致。建議大家在編寫一個函數的原代碼時,立即將此函數的類型聲明復制到原文件的起始處,見例 11-1;或是復制到專門的包含頭文件中,再在每個原程序模塊中引用。11.6.4 中斷函數的實現PICC 可以實現 C 語言的中斷服務程序。中斷服務程序有一個特殊的定義方法:voidinterruptISR(void);其中的函數名“ISR 可以改成任意合法的字母或

30、數字組合,但其入口參數和返回參數類型必須是“void 型,亦即沒有入口參數和返回參數,且中間必須有一個關鍵詞ainterrupt中斷函數可以被放置在原程序的任意位置。因為已有關鍵詞“interrupt 聲明,PICC 在最后進行代碼連接時會自動將其定位到 0 x0004 中斷入口處,實現中斷服務響應。編譯器也會實現中斷函數的返回指令“retfie。個簡單的中斷服務示范函數如下:voidinterruptISR(void)/中斷服務程序(if(T0IE&T0IF)(T0IF=0;/在此加入 TMR0 中斷服務判 TMR0 中斷/清除 TMR0 中斷標志if(TMR1IE&TMR1

31、IF)判 TMR1 中斷(TMR1IF0;/在此加入 TMR1 中斷服務)/清除 TMR1 中斷標志/中斷結束并返回例 11-5C 語言中斷函數舉例PICC 會自動加入代碼實現中斷現場的保護,并在中斷結束時自動恢復現場,所以編程員無需象編寫匯編程序那樣加入中斷現場保護和恢復的額外指令語句。但如果在中斷服務程序中需要修改某些全局變量時,是否需要保護這些變量的初值將由編程員自己決定和實施。用 C 語言編寫中斷服務程序必須遵循高效的原則:&O1540;代碼盡量簡短,中斷服務強調的是一個快”字。&O1540;避免在中斷內使用函數調用。雖然 PICC 允許在中斷里調用其它函數,但為了解決

32、遞歸調用的問題,此函數必須為中斷服務獨家專用。既如此,不妨把原本要寫在其它函數內的代碼直接寫在中斷服務程序中。&O1540;避免在中斷內進行數學運算。數學運算將很有可能用到庫函數和許多中間變量,就算不出現遞歸調用的問題,光在中斷入口和出口處為了保護和恢復這些中間臨時變量就需要大量的開銷,嚴重影響中斷服務的效率。中檔系列 PIC 單片機的中斷入口只有一個,因此整個程序中只能有一個中斷服務函數。PICC 提供了較完整的 C 標準庫函數支持,其中包括數學運算函數和字符串操作函數。在程序中使用這些現成的庫函數時需要注意的是入口參數必須在 bank0 中。如果需要用到數學函數,則應在程序前“#i

33、nclude”包含頭文件;如果要使用字符串操作函數,就需要包含“#include”頭文件。在這些頭文件中提供了函數類型的聲明。通過直接查看這些頭文件就可以知道 PICC 提供了哪些標準庫函數。C 語言中常用的格式化打印函數“printf/sprintf 用在單片機的程序中時要特別謹慎。printf/sprintf 是一個非常大的函數,一旦使用,你的程序代碼長度就會增加很多。除非是在編寫試驗性質的代碼,可以考慮使用格式化打印函數以簡化測試程序;一般的最終產品設計都是自己編寫最精簡的代碼實現特定格式的數據顯示和輸出。本來,在單片機應用中輸出的數據格式都相對簡單而且固定,實現起來應該很容易。對于標準

34、 C 語言的控制臺輸入(scanf)/輸出(printf)函數,PICC 需要用戶自己編寫其底層函數 getch()和 putch()。在單片機系統中實現 scanf/printf 本來就沒什么太多意義,如果一定要實現,只要編寫好特定的 getch()和 putch()函數,你就可以通過任何接口輸入或輸11.6.5標準庫函數出格式化的數據。11.7PICC 定義特殊區域值PICC 提供了相關的預處理指令以實現在原程序中定義單片機的配置字和標記單元。定義工作配置字在原程序中定義 PIC 單片機工作配置字的重要性在前面章節中已經闡述。在用 PICC 寫程序時同樣可以在 C 原程序中定義,具體方式如

35、下:_CONFIG(HS&UNPROTECT&PWRTEN&BORDIS&WDTEN);上面的關鍵詞_CONFIG(注意前面有兩個下劃線符)專門用于是芯片配置字的設定,后面括號中的各項配置位符號在特定型號單片機的頭文件中已經定義(注意不是 pic.h頭文件),相互之間用邏輯與操作符組合在一起。這樣定義的配置字信息最后將和程序代碼一起放入同一個 HEX 文件在這里列出了適用于 16F7x 系列單片機配置位符號預定義,其它型號或系列的單片機配置字定義方式類似,使用前查閱一下對應的頭文件即可/*振蕩器配置*/#defineRC#defineHS0 x3FFF/RC 振

36、蕩0 x3FFE/HS 模式#defineXT#defineLP/*看門狗配置*/0 x3FFD/XT 模式0 x3FFC/LP 模式#defineWDTEN0 x3FFF/看門狗打開#defineWDTDIS/*上電延時定時器配置*/#definePWRTEN0 x3FFB/看門狗關閉0 x3FF7/上電延時定時器打開/*低電壓復位配置*/#defineBOREN0 x3FFF/低電壓復位允許#definePWRTDIS0 x3FFF/上電延時定時器關閉#defineBORDIS/*代碼保護配置*/0X3FBF/低電壓復位禁止#defineUNPROTECT0 x3FFF/沒有代碼保護#de

37、finePROTECT0 x3FEF/程序代碼保護例 11-6 頭文件預定義的配置信息符號定義芯片標記單元PIC 單片機中的標記單元定義可以用下面的_IDLOC(注意前面有兩個下劃線符)預處理指令實現,方法如下:IDLOC(1234);其特殊之處是括號內的值全部為 16 進制數,不需要用“0 x 引導。這樣上面的定義就設定了標記單元內容為 01020304。11.8MPLAB-IDE 中實現 PICC 的編譯選項設置在 11.3 節中已經介紹了如何實現 PICC 和 MPLAB-IDE 開發平臺的掛接。一旦項目建立成功、程序編寫完成后即可以通過 MPLAB 環境下的項目管理工具實現程序的編譯、

38、連接和調試。它們的含義分別是:項目維護(Make):MPLAB 檢查項目中的原程序文件,只編譯那些在上次編譯后又被修改過的原程序,最后進行連接;項目重建(BuildAll):項目中的所有原程序文件,不管是否有修改,都將被重新編譯一次,最后進行連接也可以通過 Project 菜單選擇“Mak4 或“BuildAll 實現項目編譯。不管采用何種方式,在啟動編譯過程前一般都要設定一些編譯選項選擇單片機型號在選擇 PICC 作為語言工具并建立了項目后,同樣通過菜單項 Configure&O1616;SelectDevice在 MPLAB 環境中選擇具體單片機型號。請回顧一下例 11-1 的代碼

39、,我們在原程序一開始使用了“#include”實現了相關單片機的一些預定義符號的直接引用,但沒有具體指明是哪一個型號。實際上,“pic.h 買文件只是一個簡單的管理工具(條件判別),它會按照MPLAB 所選擇的特定型號的單片機,把真正對應的頭文件包含進來。有興趣者可以直接用文本編輯工具打開 pic.h 文件查看其是如何根據不同的單片機型號包含對應的頭文件。這樣對編程員而言,程序中只需加上一句include”即可。PICC 普通編譯選項(General)設定參考第三章 3.2.7 節的內容和圖 3-20 的指示說明,啟動編譯選項設定對話框。在使用PICC 語言工具時對話本 I 的內容和用 MPA

40、MS 匯編工具相比完全不同。圖 11-3 為 PICC 編譯環境下普通選項設定的界面O在此界面中用戶唯一能改變的是編譯器查找頭文件時的指定路徑(上如果編譯器安裝沒有問題,在此界面中這些普通選項的設定無需任何改動,編譯器會自動到缺省認定的路徑中(編譯器安裝后的相關路徑)查找編譯所需的各類文件。圖 11-3PICC 普通選項設定圖 11-4PICC 全局選項設定PICC 全局選項設定(PICCGlobal)全局選項將影響項目中所有 C 和匯編原程序的編譯,詳細的設定內容見圖 11-4o 其中必須關注的有:IncludePath),實際&O1540;CompileforMPLABICD:如果

41、你準備用 ICD 調 tC 語言編譯后的代碼,那么此項就必須打鉤選中。這樣編譯后的結果就能保證 ICD 本身使用的芯片資源(一小部分的程序和數據空間)不被應用程序所占用。&O1540;Treat,char?assigned:為了提高編譯后的代碼效率,PICC 缺省認定,char 理變量也是無符號數。如果在設計中需要使用帶符號的,char?變量,此項就應該被選中。&O1540;Floatingpoint,double?width:同樣為了提高編譯后的代碼效率,PICC 缺省認定,double 例的雙精度浮點數變量的實現長度為 24 位(等同于普通 float 型浮點數)。在這里可

42、以選擇使其長度達 32 位。這樣數值計算的精度將得到提高,但代碼長度將增加,計算速度也會降低,所以請在權衡利弊后作出你自己的決定。項目中所有的 C 原程序都將通過 C 編譯器編譯成機器碼,這些選項決定了 C 編譯器是如何工作的。所有選項又分為兩組:普通選項(General)和高級選項(Advanced),分別見圖 11-5A 和 11-5BoC 編譯器的普通選項最重要的就是針對代碼優化的設定。如果沒有特殊原因,應該設定全局優化級別為 9 級(最高級別優化),同時使用匯編級優化,這樣最終得到的代碼效率最高(長度和執行速度兩方面)。按筆者的使用經驗,僅從代碼長度去比較,使用最高級別優化后代碼長度至

43、少可以減少 20%(2K 字以上的程序)。而且 PICC 的優化器相當可靠,一般(A)常用選項(B)高級選項圖 11-5C 編譯器選項設定不會因為使用優化從而使生成的程序出現錯誤。碰到的一些問題也基本都是用戶編寫的原程序有漏洞所導致,例如一些變量應該是 volatile 型但編程員沒有明確定義,在優化前程序可以正常運行,一旦使用優化,程序運行就出現異常。顯然,把出現的這些問題歸罪到編譯器是毫無道理的。使用優化后可能對原程序級的調試帶來一些不便之處。因碼, 例如多處重復的代碼可能會改成同一個子程序調用以節約程序空間,這樣在調試過程中跟蹤原程序時可能會出現程序亂跳的現象,這基本是正常的。若為了強調

44、更直觀的代碼調試11.8.4C 編譯器選項設定(PICCCompiler)PICC 可能會重組編譯后的代過程,你可以將優化級別降低甚至關閉所有優化功能,這樣調試時程序的運行就可以按部就班了。C 編譯器的高級選項設定基本都是針對診斷信息輸出的,和生成的代碼無關。用得相對較多的選項有:&O1540;Generateassemblylistfile:編譯器生成 C 原程序的匯編列表文件(*.lst)。在此文件中列出了每一行 C 原代碼對應的匯編指令,但這些都是優化前的代碼。簡單的一條 C 語句被翻譯成匯編指令后可能有好幾條。有時匯編列表文件可以作為解決問題的輔助手段。如果你懷疑編譯器生成的代

45、碼有錯誤,不妨先產生對應的匯編列表文件,看看在優化前一條 C 語句被編譯后的匯編碼到底是什么。&O1540;Compiletoassemblyonly:這一選項的作用是把&n,bsp;C 原程序編譯成匯編指令文件(*.as),此時將不生成目標文件,也不進行最后的連接定位。這一選項在 C 和匯編混合編程時特別有用。通過解讀 C 程序對應的匯編指令,可以掌握 C 程序中存取變量的具體方法,然后用在自己編寫的匯編指令中。我們將在稍后專門做介紹。11.8.5 連接器選項設定(PICCLinker)連接器 PICCLinker 的選項基本不用作太多的改變,在圖 11-6 的對話框中顯示了

46、可設定的各類項目。其中有兩項有用的信息輸出可以考慮加以利用:&O1540;Generatemapfile:生成連接定位映射文件。在此映射文件中詳細列出了所有程序用到的變量的具體物理地址;所有函數的入口地址;函數相互之間調用的層次關系和深度等。這些信息對于程序的調試將非常有用。此文件將以擴展名“*.map”的形式存放在同一個項目路徑下,需要時可以用任何文本編輯器打開觀察。圖 11-6PICC11-6PICC 連接器選項設定&O1540;Displaymemory-segmentusage:顯示詳細的內存分配和使用情況報告。用戶可以了解到程序空間和數據存儲器空間資源分配的細節。下面

47、列舉了在一個項目編譯后實際的內存使用信息,為方便理解筆者用 7/添加了一些注釋:PsectUsageMap:/程序段定位表Psect|Contents|MemoryRange|powerup|Poweronresetcode|$0000-$0003intentry|Interruptserviceroutine|$0004-$000Cintcode|Interruptserviceroutine|$000D-$002CintretInterruptserviceroutine|$002D-$0035init|Initializationcode|$0036-$003Dend_init|Init

48、ializationcode|$003E-$0040clrtext|Memoryclearingcode|$0041-$0047const3|Stringsandconstantdata|$0048-$0060const|Stringsandconstantdata|$0061-$0071const2|Stringsandconstantdata|$0072-$0076text|Programandlibrarycode|$0576-$0582text|Programandlibrarycode|$0583-$07C7floatte|Arithmeticroutinecode|$07C8-$0

49、7FFrbss0|Bank0RAMvariables|$0021-$0042temp|TemporaryRAMdata|$0043-$0047nvram|PersistentRAMdata|$0048-$004Aintsave|Registerssavedoninterrupt|$004B-$004Dintsave|Registerssavedoninterrupt|$007F-$007Fintsave_1|SavedcopyofWinbank1|$00FF-$00FFrbit_0|Bank0bitvariables|$0100-$0104config|User-programmedCONFI

50、Gbits|$2007-$2007MemoryUsageMap:/程序空間代碼定位地址分布/存儲空間使用情況報告ProgramROM$0000-$0076$0077(119)wordsProgramROM$0576-$07FF$028A(650)words$0301(769)wordstotalProgramROM/bank0 數據空間變量地址分布Bank0RAM$0021-$004D$002D(45)bytesBank0RAM$007F-$007F$002E(/bank1 數據空間變量地址分布Bank1RAM$00FF-$00FF/bank0 數據空間位變量地址分布Bank0Bits$010

51、0-$0104$0005(/配置字地址ConfigData$2007-$2007$0001(Programstatistics:/程序總體資源消耗統計TotalROMused769words(18.8%)TotalRAMused48bytes(25.0%)例 11-7 編譯后程序使用的內存信息11.8.6匯編器選項設定(PICCAssembler)1)bytestotalBank0RAM1)bytestotalBank1RAM5)bitstotalBank0Bits1)wordstotalConfigData/生成代碼字總數和程序空間使用率/使用數據字節數和數據空間使用率$0001(46)bytes$0001(PICC 環境提供了自己的匯編編譯器,它和 Microchip 公司提供的 MPASM 編譯器在原程序的語法表達方面要求稍有不同。另外

溫馨提示

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

評論

0/150

提交評論