新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > PIC單片機C語言編程教程(1)

        PIC單片機C語言編程教程(1)

        作者: 時間:2016-11-22 來源:網絡 收藏
        PIC 單片機 C 語言編程簡介

        本文引用地址:http://www.104case.com/article/201611/319595.htm

        C 語言來開發單片機系統軟件最大的好處是編寫代碼效率高、軟件調試直觀、維護升級方便、

        代碼的重復利用率高、便于跨平臺的代碼移植等等,因此 C 語言編程在單片機系統設計中已得到越

        來越廣泛的運用。針對 PIC 單片機的軟件開發,同樣可以用 C 語言實現。

        但在單片機上用 C 語言寫程序和在 PC 機上寫程序絕對不能簡單等同。現在的 PC 機資

        源十分豐富,運算能力強大,因此程序員在寫 PC 機的應用程序時幾乎不用關心編譯后的可

        執行代碼在運行過程中需要占用多少系統資源,也基本不用擔心運行效率有多高。寫單片機

        C 程序最關鍵的一點是單片機內的資源非常有限,控制的實時性要求又很高,因此,如

        果沒有對單片機體系結構和硬件資源作詳盡的了解,以筆者的愚見認為是無法寫出高質量實

        用的 C 語言程序。這就是為什么前面所有章節中的的示范代碼全部用基礎的匯編指令實現

        的原因,希望籍此能使讀者對 PIC 單片機的指令體系和硬件資源有深入了解,在這基礎之

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

        本書圍繞中檔系列 PIC 單片機來展開討論,Microchip 公司自己沒有針對中低檔系列 PIC

        單片機的 C 語言編譯器,但很多專業的第三方公司有眾多支持 PIC 單片機的 C 語言編譯器

        提供,常見的有 Hitech、CCS、IAR、Bytecraft 等公司。其中筆者最常用的是 Hitech 公司的

        PICC 編譯器,它穩定可靠,編譯生成的代碼效率高,在用 PIC 單片機進行系統設計和開發

        的工程師群體中得到廣泛認可。其正式完全版軟件需要購置,但在其網站上有限時的試用版

        供用戶評估。另外,Hitech 公司針對廣大 PIC 的業余愛好者和初學者還提供了完全免費的學

        習版 PICC-Lite 編譯器套件,它的使用方式和完全版相同,只是支持的 PIC 單片機型號限制

        在 PIC16F84、PIC16F877 和 PIC16F628 等幾款。這幾款 Flash 型的單片機因其所具備的豐富

        的片上資源而最適用于單片機學習入門,因此筆者建議感興趣的讀者可從 PICC-Lite 入手掌

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

        在此列出幾個主要的針對 PIC 單片機的 C 編譯器相關連接網址,供讀者參考:

        Hitech-PICC: www.htsoft.com


        IAR:www.iar.com

        CCS:www.ccsinfo.com/picc.shtml

        ByteCraft:www.bytecraft.com/mpccaps.html


        本章將介紹 Hitech-PICC 編譯器的一些基本概念,由于篇幅所限將不涉及 C 語言的標準

        語法和基礎知識介紹,因為在這些方面都有大量的書籍可以參考。重點突出針對 PIC 單片

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

        11.2

        Hitech-PICC 編譯器

        PICC 基本上符合 ANSI 標準,除了一點:它不支持函數的遞歸調用。其主要原因是因

        為 PIC 單片機特殊的堆棧結構。在前面介紹 PIC 單片機架構時已經詳細說明了 PIC 單片機

        中的堆棧是硬件實現的,其深度已隨芯片而固定,無法實現需要大量堆棧操作的遞歸算法;

        另外在 PIC 單片機中實現軟件堆棧的效率也不是很高,為此,PICC 編譯器采用一種叫做“靜

        態覆蓋”的技術以實現對 C 語言函數中的局部變量分配固定的地址空間。經這樣處理后產

        生出的機器代碼效率很高,按筆者實際使用的體會,當代碼量超過 4K 字后,C 語言編譯出

        的代碼長度和全部用匯編代碼實現時的差別已經不是很大(<10%),當然前提是在整個 C

        代碼編寫過程中須時時處處注意所編寫語句的效率,而如果沒有對 PIC 單片機的內核結構、

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

        11.3

        MPLAB-IDE 內掛接 PICC

        PICC 編譯器可以直接掛接在 MPLAB-IDE 集成開發平臺下,實現一體化的編譯連接和

        原代碼調試。使用 MPLAB-IDE 內的調試工具 ICE2000、ICD2 和軟件模擬器都可以實現原

        代碼級的程序調試,非常方便。

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

        MPLAB-IDE掛接。安裝成功后可以進入IDE,選擇菜單項Project Set Language Tool

        Locations…,打開語言工具掛接設置對話框,如圖 11-1 所示:

        %C3%82%C2%B3%C3%83%C2%8C%C3%82%C2%BD%C3%83%C2%8C%C3%82%C2%B3%C3%83%C2%8C.files/7.jpg" src="file:///F:/data/%C3%83%C2%8F%C3%83%C2%82%C3%83%C2%94%C3%83%C2%98/PIC%C3%82%C2%B5%C3%82%C2%A5%C3%83%C2%86%C3%82%C2%AC%C3%82%C2%BB%C3%83%C2%BAC%C3%83%C2%93%C3%83%C2%AF%C3%83%C2%91%C3%83%C2%94%C3%82%C2%B1%C3%83%C2%A0%3Cwbr%3E%C3%82%C2%B3%C3%83%C2%8C%C3%82%C2%BD%C3%83%C2%8C%C3%82%C2%B3%C3%83%C2%8C.files/7.jpg" />

        圖 11-1 MPLAB-IDE 語言工具設置對話框

        在對話框中選擇“HI-TECH PICC Toolsuite”欄,展開可執行文件組“Executable”后,

        列出了將被 MPLAB-IDE 后臺調用的編譯器所用到的所有可執行文件,其中有匯編編譯器

        “PICC Assembler”、C 原程序編譯器“PICC Compiler”和連接定位程序“PICC Linker”。同

        時在此列表中還顯示了對應的可執行程序名,請注意在這里都是“PICC.EXE”。用鼠標分別

        點擊選中這三項可執行文件,觀察對話框下面“Location”一欄中顯示的文件路徑,用

        “Browse…”按紐,從計算機中已經安裝的 PICC 編譯器文件夾中選擇 PICC.EXE 文件。實

        際上 PICC.EXE 只是一個調度管理程序,它會按照所輸入的文件擴展名自動調用對應的編譯

        器和連接器,用戶要注意的是 C 語言原程序擴展名用“.c”,匯編原程序用“.as”即可。

        工具掛接完成后,在建立項目時可以選擇語言工具為“HI-TECH PICC”,具體步驟可以

        參閱第三章 3.1.3 節,此處不再重復。項目建立完成后可以加入 C 或匯編原程序,也可以加

        入已有的庫文件或已經編譯的目標文件。最常見的是只加入 C 原程序。用 C 語言編程的好

        處是可以實現模塊化編程。程序編寫者應盡量把相互獨立的控制任務用多個獨立的 C 原程序文件實

        現,如果程序量較大,一般不要把所有的代碼寫在一個文件內。

        圖 11-2 列出的是筆者建立的一個項目中所有 C 原程序模塊,其中主控、數值計算、I2C 總線

        作、命令按鍵處理和液晶顯示驅動等不同的功能分別在不同的獨立的原程序模塊中實現。

        %C3%82%C2%B3%C3%83%C2%8C%C3%82%C2%BD%C3%83%C2%8C%C3%82%C2%B3%C3%83%C2%8C.files/8.jpg" src="file:///F:/data/%C3%83%C2%8F%C3%83%C2%82%C3%83%C2%94%C3%83%C2%98/PIC%C3%82%C2%B5%C3%82%C2%A5%C3%83%C2%86%C3%82%C2%AC%C3%82%C2%BB%C3%83%C2%BAC%C3%83%C2%93%C3%83%C2%AF%C3%83%C2%91%C3%83%C2%94%C3%82%C2%B1%C3%83%C2%A0%3Cwbr%3E%C3%82%C2%B3%C3%83%C2%8C%C3%82%C2%BD%C3%83%C2%8C%C3%82%C2%B3%C3%83%C2%8C.files/8.jpg" />

        圖 11-2 C 語言多模塊編程

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

        基于 PICC 編譯環境編寫 PIC 單片機程序的基本方式和標準 C 程序類似,程序一般由以

        下幾個主要部分組成:

        &O1540; 在程序的最前面用#include 預處理指令引用包含頭文件,其中必須包含一個編譯器

        提供的“pic.h”文件,實現單片機內特殊寄存器和其它特殊符號的聲明;

        &O1540; 用“__CONFIG”預處理指令定義芯片的配置位;

        &O1540; 聲明本模塊內被調用的所有函數的類型,PICC 將對所調用的函數進行嚴格的類型

        匹配檢查;

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

        &O1540; 實現函數(子程序),特別注意 main 函數必須是一個沒有返回的死循環。

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

        #include //包含單片機內部資源預定義

        #include “pc68.h” //包含自定義頭文件

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

        __CONFIG (HS & PROTECT & PWRTEN & BOREN & WDTDIS);

        //聲明本模塊中所調用的函數類型

        void SetSFR(void);

        void Clock(void);

        void KeyScan(void);

        void Measure(void);

        void LCD_Test(void);

        void LCD_Disp(unsigned char);

        //定義變量

        unsigned char second, minute, hour;

        bit flag1,flag2;

        //函數和子程序

        void main(void)

        {

        SetSFR();

        PORTC = 0x00;

        TMR1H += TMR1H_CONST;

        LED1 = LED_OFF;

        LCD_Test();

        //程序工作主循環

        while(1) {

        asm(“clrwdt”);

        Clock();

        KeyScan();

        Measure();

        SetSFR();

        }

        }

        //清看門狗

        //更新時鐘

        //掃描鍵盤

        //數據測量

        //刷新特殊功能寄存器

        11.5

        PICC 中的變量定義


        例 11-1 C 語言原程序框架舉例

        11.5.1 PICC 中的基本變量類型


        PICC 遵循 Little-endian 標準,多字節變量的低字節放在存儲空間的低地址,高字節放

        在高地址。

        11.5.2 PICC 中的高級變量

        基于表 11-1 的基本變量,除了 bit 型位變量外,PICC 完全支持數組、結構和聯合等復

        合型高級變量,這和標準的 C 語言所支持的高級變量類型沒有什么區別。例如:

        數組:unsigned int data[10];

        結構:struct commInData {

        unsigned char inBuff[8];

        unsigned char getPtr, putPtr;

        };

        聯合:union int_Byte {

        unsigned char c[2];

        unsigned int i;

        };

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

        11.5.3 PICC 對數據寄存器 bank 的管理

        為了使編譯器產生最高效的機器碼,PICC 把單片機中數據寄存器的 bank 問題交由編程

        員自己管理,因此在定義用戶變量時你必須自己決定這些變量具體放在哪一個 bank 中。如

        果沒有特別指明,所定義的變量將被定位在 bank0,例如下面所定義的這些變量:

        unsigned char buffer[32];

        bit flag1,flag2;

        float val[8];

        除了 bank0 內的變量聲明時不需特殊處理外,定義在其它 bank 內的變量前面必須加上

        相應的 bank 序號,例如:

        bank1 unsigned char buffer[32]; //變量定位在 bank1 中


        bank2 bit flag1,flag2;

        bank3 float val[8];


        //變量定位在 bank2 中

        //變量定位在 bank3 中


        中檔系列 PIC 單片機數據寄存器的一個 bank 大小為 128 字節,刨去前面若干字節的特

        殊功能寄存器區域,在 C 語言中某一 bank 內定義的變量字節總數不能超過可用 RAM 字節

        數。如果超過 bank 容量,在最后連接時會報錯,大致信息如下:

        Error[000] : Cant find 0x12C words for psect rbss_1 in segment BANK1

        連接器告訴你總共有 0x12C(300)個字節準備放到 bank1 中但 bank1 容量不夠。顯然,只

        有把一部分原本定位在 bank1 中的變量改放到其它 bank 中才能解決此問題。

        雖然變量所在的 bank 定位必須由編程員自己決定,但在編寫原程序時進行變量存取操

        作前無需再特意編寫設定 bank 的指令。C 編譯器會根據所操作的對象自動生成對應 bank 設

        定的匯編指令。為避免頻繁的 bank 切換以提高代碼效率,盡量把實現同一任務的變量定位

        在同一個 bank 內;對不同 bank 內的變量進行讀寫操作時也盡量把位于相同 bank 內的變量

        歸并在一起進行連續操作。

        11.5.4 PICC 中的局部變量

        PICC 把所有函數內部定義的 auto 型局部變量放在 bank0。為節約寶貴的存儲空間,它

        采用了一種被叫做“靜態覆蓋”的技術來實現局部變量的地址分配。其大致的原理是在編譯

        器編譯原代碼時掃描整個程序中函數調用的嵌套關系和層次,算出每個函數中的局部變量字

        節數,然后為每個局部變量分配一個固定的地址,且按調用嵌套的層次關系各變量的地址可

        以相互重疊。利用這一技術后所有的動態局部變量都可以按已知的固定地址地進行直接尋

        址,用 PIC 匯編指令實現的效率最高,但這時不能出現函數遞歸調用。PICC 在編譯時會嚴

        格檢查遞歸調用的問題并認為這是一個嚴重錯誤而立即終止編譯過程。

        既然所有的局部變量將占用 bank0 的存儲空間,因此用戶自己定位在 bank0 內的變量字

        節數將受到一定的限制,在實際使用時需注意。

        11.5.5 PICC 中的位變量

        bit 型位變量只能是全局的或靜態的。PICC 將把定位在同一 bank 內的 8 個位變量合并

        成一個字節存放于一個固定地址。因此所有針對位變量的操作將直接使用 PIC 單片機的位

        操作匯編指令高效實現。基于此,位變量不能是局部自動型變量,也無法將其組合成復合型

        高級變量。

        PICC 對整個數據存儲空間實行位編址,0x000 單元的第 0 位是位地址 0x0000,以此后

        推,每個字節有 8 個位地址。編制位地址的意義純粹是為了編譯器最后產生匯編級位操作指

        令而用,對編程人員來說基本可以不管。但若能了解位變量的位地址編址方式就可以在最后

        程序調試時方便地查找自己所定義的位變量,如果一個位變量 flag1 被編址為 0x123,那么

        實際的存儲空間位于:

        字節地址=0x123/8 = 0x24

        位偏移 =0x123%8 = 3

        即 flag1 位變量位于地址為 0x24 字節的第 3 位。在程序調試時如果要觀察 flag1 的變化,必

        須觀察地址為 0x24 的字節而不是 0x123。

        PIC 單片機的位操作指令是非常高效的。因此,PICC 在編譯原代碼時只要有可能,對

        普通變量的操作也將以最簡單的位操作指令來實現。假設一個字節變量 tmp 最后被定位在

        地址 0x20,那么


        tmp |= 0x80

        tmp &= 0xf7


        => bsf

        => bcf


        0x20,7

        0x20,3


        if (tmp&0xfe)


        => btfsc 0x20,0


        即所有只對變量中某一位操作的 C 語句代碼將被直接編譯成匯編的位操作指令。雖然編程

        時可以不用太關心,但如果能了解編譯器是如何工作的,那將有助于引導我們寫出高效簡介

        的 C 語言原程序。

        在有些應用中需要將一組位變量放在同一個字節中以便需要時一次性地進行讀寫,這一

        功能可以通過定義一個位域結構和一個字節變量的聯合來實現,例如:

        union {

        struct {

        unsigned b0: 1;

        unsigned b1: 1;

        unsigned b2: 1;

        unsigned b3: 1;

        unsigned b4: 1;

        unsigned b5: 1;

        unsigned : 2; //最高兩位保留

        } oneBit;

        unsigned char allBits;

        } myFlag;

        例 11-3 定義位變量于同一字節

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

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

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

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

        當程序中把非位變量進行強制類型轉換成位變量時,要注意編譯器只對普通變量的最低

        位做判別:如果最低位是 0,則轉換成位變量 0;如果最低位是 1,則轉換成位變量 1。而標

        準的 ANSI-C 做法是判整個變量值是否為 0。另外,函數可以返回一個位變量,實際上此返

        回的位變量將存放于單片機的進位位中帶出返回。

        11.5.6 PICC 中的浮點數

        PICC 中描述浮點數是以 IEEE-754 標準格式實現的。此標準下定義的浮點數為 32 位長,

        在單片機中要用 4 個字節存儲。為了節約單片機的數據空間和程序空間,PICC 專門提供了

        一種長度為 24 位的截短型浮點數,它損失了浮點數的一點精度,但浮點運算的效率得以提

        高。在程序中定義的 float 型標準浮點數的長度固定為 24 位,雙精度 double 型浮點數一般

        也是 24 位長,但可以在程序編譯選項中選擇 double 型浮點數為 32 位,以提高計算的精度。

        一般控制系統中關心的是單片機的運行效率,因此在精度能夠滿足的前提下盡量選擇

        24 位的浮點數運算。




        評論


        技術專區

        關閉
        主站蜘蛛池模板: 五原县| 建德市| 漠河县| 宝兴县| 九龙县| 长乐市| 呼伦贝尔市| 绥棱县| 洛阳市| 吐鲁番市| 闽清县| 金湖县| 蓬莱市| 湛江市| 滦南县| 兴隆县| 海安县| 恭城| 乌兰县| 莫力| 美姑县| 贡觉县| 深圳市| 调兵山市| 福清市| 双城市| 巴南区| 烟台市| 伊通| 望奎县| 苍溪县| 建德市| 云梦县| 南投市| 遂昌县| 崇阳县| 碌曲县| 永济市| 杭州市| 邳州市| 宜宾县|