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

2021-01-12 電子產品世界
PIC 單片機 C 語言編程簡介

本文引用地址:http://www.eepw.com.cn/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 語言原程序框架舉例


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 位的浮點數運算。


相關焦點

  • PIC單片機C語言程序設計(8)
    即可用MPLAB IDE7.40 對PIC 單片機建立彙編語言或C 語言的源程序、創建項目(project)、對源程序進行彙編(使用彙編語言時)或編譯(使用C 語言時),彙編或編譯通過後,會生成目標碼。hex 文件。有了目標碼。hex 文件,就可對PIC 單片機編程(燒寫)和對源程序進行模擬調試了。
  • PIC單片機C語言程序實例
    用彙編語言編程,直接、簡捷,可有效地訪問和控制各種硬體設備,如存儲器、I/O口等,目標代碼簡短、佔用內存少、執行速度快、語句效率高。然而,由於彙編語言是面向機器的語言,不同廠家或同廠家不同系列的單片機。其彙編語言指令系統往往互不相同,即通常所說的「不兼容」。
  • 單片機c語言教程:建立你的第一個KeilC51項目
    KEIL uVISION2 是眾多單片機應用開發軟體中優秀的軟體之一,它支持眾多不一樣公司的MCS51架構的晶片,它集編輯,編譯,仿真等於一體,同時還支持,PLM,彙編和C語言的程序設計,它的界面和常用的微軟 VC++的界面相似,界面友好,易學易用,在調試程序,軟體仿真方面也有很強大的功能。本站提供的單片機c語言教程都是基於keilc51的。
  • 單片機基本結構及C語言編程基礎
    RXD、TXD、INT0、INT1、T0、T1   單片機內部I/O部件:(所為學習單片機,實際上就是編程控制以下I/O部件,完成指定任務) 1、 四個8位通用I/O埠,對應引腳P0、P1、P2和P3; 2、 兩個16位定時計數器;(TMOD,TCON,TL0,TH0,TL1,TH1) 3、 一個串行通信接口;(SCON,SBUF) 4、 一個中斷控制器;(
  • PIC單片機asm與C混合編程
    在基於PICC 編譯環境下開發PIC 單片機的C 語言應用程式時基本無需關心其彙編編譯器,除非是在混合語言編程時用彙編語言編寫完整的彙編原程序模塊文件。其編譯選項設定的對話框見圖11-7,最重要的是優化使能控制項「Enable optimization」,一般情況下應該使用彙編器的優化以節約程序空間。
  • 單片機C語言模塊化編程方法
    初學者往往搞不懂如何模塊化編程,其實它是簡單易學,而且又是組織良好程序結構行之有效的方法之一.本文將先大概講一下模塊化的方法和注意事項,最後將以初學者使用最廣的keil c編譯器為例,給出模塊化編程的詳細步驟。
  • 單片機c語言教程:C51變量
    存儲器類型的說明就是指定該變量在單片機c語言硬體系統中所使用的存儲區域,並在編譯時準確的定位。表6-1中是KEIL uVision2所能認別的存儲器類型。注意的是在AT89c51晶片中RAM只有低128位,位於80H到FFH的高128位則在52晶片中才有用,並和特殊寄存器地址重疊。
  • 單片機程序C語言與彙編語言混合編程
    中C語言與彙編語言混合編程本文引用地址:http://www.eepw.com.cn/article/201611/322505.htm1.彙編語言源程序; ******************************************************************;文件名: asm_source.s43; C語言和彙編語言混合編程,彙編語言源程序;這段源程序調用兩個C語言函數,標準庫函數rand()和用戶自定義函數mult(); *********************
  • stm32與pic單片機比較_哪個好
    >   stm32單片機特性   1、內核:ARM32位Cortex-M3CPU,最高工作頻率72MHz,1.25DMIPS/MHz,單周期乘法和硬體除法   2、存儲器:片上集成32-512KB的Flash存儲器。
  • 單片機編程用C語言還是彙編?
    單片機是一種可編程器件,單片機的出現使硬體設計變得更為簡單,產品的功能也更強大,而程序就是單片機的靈魂。目前功能稍微複雜一點的電子產品,都是以單片機為核心,再加以不通的外設電路實現不通的功能需求。單片機的編程可以通過彙編語言和C語言來實現。
  • gcc c編譯器如何編譯c程序,如何為pic單片機選擇c編譯器
    對於c編譯器,大家應早已熟悉。往期文章中,小編帶來諸多c編譯器相關文章,尤其是gcc c編譯器。本文中,小編將對gcc c編譯器如何編譯c程序予以介紹,並在文章的後半部分向大家講解如果選擇pic單片機的c編譯器。如果你對本文即將要涉及的內容存在一定興趣,不妨繼續往下閱讀哦。
  • 51單片機教程之基礎編(基於C語言)
    大家好,我是陳濱,本人是去年9月份開始學單片機,到現在一年多了,現在本人基本掌握了單片機編程,開始深入學習彙編語言了。很多初學者有很多的疑惑,我究竟是先學C語言,還是彙編語言?其實我告訴你,本人認為,先學C語言!為什麼呢?C語言是目前使用最廣泛的中級語言,就連現在的windows7也是C語言編寫的,C語言易讀性好,無需對單片機內部結構十分熟悉即會編程,可移植性高,便於維護。C語言只有32個關鍵字,9種控制語句,而且編譯器提供了很多函數庫,使用十分方便。
  • 51單片機C語言延時函數
    以某晶振為12MHz的單片機為例,晶振為12MHz即一個機器周期為1us。>0;i--)for(j=202;j>0;j--)for(k=81;k>0;k--);}計算分析:程序共有三層循環一層循環n:R5*2 = 81*2 = 162us DJNZ 2us二層循環m:R6*(n+3) = 202*165 = 33330us DJNZ 2us + R5賦值 1us
  • 單片機C語言延時分析
    標準的C語言中沒有空語句。但在單片機的C語言編程中,經常需要用幾個空指令產生短延時的效果。這在彙編語言中很容易實現,寫幾個nop就行了。
  • 為什麼C語言是最適合單片機編程的高級語言!
    為什麼還在用C語言編程?答案是:C語言是最適合單片機編程的高級語言。 這個問題的意思應該是:現在有很多很好用的高級語言,如java,python等等,為什麼這些語言不能用來編寫單片機程序呢?那麼這個問題的答案就是:不是不能,而是不合適。
  • C語言程序設計教程
    導讀:C語言是一門通用的計算機程式語言,應用非常得廣泛,在計算機、單片機以及工業上都有的莫大的貢獻,今天我們來學習如何進行C語言程序設計。
  • 最適合單片機編程的高級語言,除了C語言,別無選擇!
    單片機為什麼還在用C語言編程?答案是:C語言是最適合單片機編程的高級語言。 這個問題的意思應該是:現在有很多很好用的高級語言,如java,python,VC等等,為什麼這些語言不能用來編寫單片機程序呢?那麼這個問題的答案就是:不能不能,而是不合適。
  • 單片機C語言程序設計:LED 模擬交通燈
    i;}while(x--) for(i=0;i120;i++);//交通燈切換void Traffic_Light(){switch(Operation_Type){case 1: //東西向綠燈與南北向紅燈亮RED_A=1;YELLOW_A=1;GREEN_A
  • PIC單片機 C編程技巧
    (以MPLAB5.7版本為例子)啟動MPLAB.在Project-->Install Language Tool:Language Suite>hi-tech piccTool Name ---->PICC CompilerExecutable ---->c:hi-picinpicc.exe (假如你的PICC是默認安裝的)選Command-line
  • 單片機提高C語言代碼效率的方法
    單片機的ROM和RAM的空間都很有限,當您編程時遇到單片機的ROM和RAM的不夠用的時候,或者您的程序要求較高的執行速度時,我們就得面對解決代碼效率問題了。如何提高代碼效率?現筆者以一個LED閃爍的程序為例與您探討。