PIC微控制器開發中PICC編譯環境的應用

2021-05-21 15:08:01 字數 4817 閱讀 2436

picc基本上符合ansi標準,但是不支援函式的遞迴呼叫,其主要原因是pic微控制器特殊的堆疊結構。pic微控制器中的堆疊是硬體實現的,其深度已隨晶元固定,無法實現需要大量堆疊操作的遞迴演算法;另外在pic微控制器中實現軟體堆疊的效率也不是很高。為此,picc編譯器採用一種「靜態覆蓋」技術,以實現對c語言函式中的區域性變數分配固定的位址空間。經這樣處理後產生出的機器**效率很高。當**量超過4kb後,c語言編譯出的**長度與全部用彙編**實現的差別已經不是很大(<10%),當然前提是在整個c**編寫過程中需時時注意所編寫語句的效率。

2  picc中的變數

picc中的變數型別和標準c語言一樣,這裡不再重複。為了使編譯器產生最高效的機器碼,picc把微控制器中資料暫存器的bank交由程式設計員自己管理,因此在定義使用者變數時必須自己決定這些變數具體放在哪乙個bank中。如果沒有特別指明,所定義的變數將被定位在bank0。定義在其他bank內的變數前面必須加上相應的bank序號,例如:

bank1 unsigned char temp;//變數定位在bank1中

中檔系列pic微控制器資料暫存器的乙個bank大小為128

b,除前面若干位元組的特殊功能暫存器區域,在c語言中某一bank內定義的變數位元組總數不能超過可用ram位元組數。如果超過bank容量,在最後連線時會報錯,大致資訊如下:

error[000]:can』t find 0x12c words for psect rbss_1 in

segmentbank1

鏈結器提示,總共有0x12c(300)位元組準備放到bank1中,但bank1容量不夠。雖然變數所在的bank定位必須由程式設計員自己決定,但編寫源程式時在進行變數訪問操作前無需再特意編寫設定bank的指令。c編譯器會根據所操作的物件自動生成對應bank設定的彙編指令。為避免頻繁的bank切換以提高**效率,盡量把實現同一任務的變數定位在同乙個bank內;對不同bank內的變數進行讀寫操作時也盡量把位於相同bank內的變數歸併在一起進行連續操作。

bit型位變數只能是全域性的或靜態的。picc將把定位在同一bank內的8個位變數合併成乙個位元組存放於乙個固定位址。picc對整個資料儲存空間實行位編址,0x000單元第0位位位址是0x0000,以此類推,每個位元組有8個位位址。如果乙個位變數flag1被編址為0x123,那麼實際的儲存空間位於:

位元組位址=0x123/8 = 0x24

位偏移=0x123%8 = 3

即flag1位變數位於位址為0x24位元組的第3位。在程式除錯時如果要觀察flag1的變化,必須觀察位址為0x24的位元組而不是0x123。picc在編譯原**時只要有可能,對普通變數的操作也將以最簡單的位操作指令來實現。假設乙個位元組變數tmp最後被定位在位址0x20,那麼

tmp | =0x80=>bsf 0x20.7

另外,函式可以返回乙個位變數,返回的位變數將存放於微控制器的進製位中返回。

3  picc中的指標

3.1  指向ram的指標

picc在編譯c源程式時,將指向ram的指標操作最終用fsr來實現間接定址。fsr能夠直接連續定址的範圍是256

b,所以乙個指標可以同時覆蓋2個bank的儲存區域(bank0/1或bank2/3,乙個bank區域是128 b)。要覆蓋最大512

b的內部資料儲存空間,在定義指標時必須明確指定該指標適用的定址區域。例如:

unsigned char *pointer0; //定義覆蓋bank0/1的指標

bank2 char *pointer1;//定義覆蓋bank2/3的指標

既然定義的指標有明確的bank適用區域,在對指標變數賦值時就必須實現型別匹配,否則將產生錯誤,例如:

unsigned char *pointer0; //定義指向bank0/1的指標

bank2 unsigned char buff[8];//定義bank2/3中的乙個緩衝區

程式語句:

pointer() =buff;//錯誤!試圖將bank2內的變數位址賦給指向bank0/1的指標

fixup overflow in expression (…)

3.2  指向rom常數的指標

如果一組變數是已經被定義在rom區的常數,那麼指向其的指標可以這樣定義:

const unsigned char company="software"

3.3  指向函式的指標

因為在pic微控制器這一特定的架構上實現函式指標呼叫的效率不高,因此,除非特殊演算法的需要,建議大家盡量不要使用函式指標。

4  picc中的子程式和函式

中檔系列的pic微控制器程式空間有分頁的概念,但用c語言程式設計時基本不用過多關心**的分頁問題。因為所有函式或子程式呼叫時的頁面設定(如果**超過乙個頁面)都由編譯器自動生成的指令實現。

4.1  函式的**長度限制

picc決定了c源程式中的乙個函式經編譯後生成的機器碼一定會放在同乙個程式頁面內。中檔系列pic微控制器的乙個程式頁面的長度是2

kb,用c語言編寫的任何乙個函式最後生成的**不能超過2

kb。如果為實現特定的功能確實要連續編寫很長的程式,這時就必須把這些連續的**拆分成若干函式,以保證每個函式最後編譯出的**不超過乙個頁面空間。

4.2  呼叫層次的控制

pic微控制器採用硬體堆疊,所以程式設計時函式的呼叫層次會受到一定限制。一般pic系列的中檔微控制器硬體堆疊深度為8級。程式設計師必須自己控制子程式呼叫時的巢狀深度以符合這一限制要求。picc在最後編譯鏈結成功後可以生成乙個鏈結定位對映檔案(*.map),在此檔案中有詳細的函式呼叫巢狀指示圖「call

graph」,有些函式呼叫是編譯時自動加入的庫函式,這些函式呼叫從c源程式中無法直接看出,但在巢狀指示圖上則一目了然。

5  c語言和組合語言混合程式設計

微控制器的一些特殊指令操作在標準的c語言語法中沒有直接對應的描述,例如pic微控制器的清看門狗指令「clrwdt」和休眠指令「sleep」;微控制器系統強調的是控制的實時性,為了實現這一要求,有時必須用彙編指令實現部分**以提高程式執行的效率。在c程式中嵌入彙編指令有2種方法。

① 如果只需要嵌入少量幾條彙編指令,picc提供了乙個類似於函式的語句:

asm("clrwdt");

這是在c源程式中直接嵌入彙編指令的最直接最容易的方法。

② 如果需要編寫一段連續的彙編指令,picc支援另外的一種語法描述:用「#asm」來開始彙編指令段,用「#endasm」結束。例如:

# asm

cdis:movlw4;清顯示子程式

movwfcount;共4位顯示

cdis1:movlw0feh;顯示為「滅」的段碼

callxmit;顯示子程式

decfszcount

gotocdisi

# endasm

5.1  彙編指令定址c語言定義的全域性變數

所有c語言中定義的符號在編譯後將自動在前面新增下劃線「_」。因此,若要在彙編指令中定址c語言定義的各類變數,一定要在變數前加上「_」符號,例如上例中的count是在c語言中定義的無符號全域性變數,在組合語言中只需在其前面加上「_」符號就可進行訪問了。另外,對於c語言中定義的多位元組全域性變數,例如c語言中的如下定義:

int advalue;

在組合語言裡訪問時就得分位元組訪問,例如:

asm(「movf_advalue+0.0」);//把advalue低位元組中的數送到w裡

asm(「rrf_advalue+1」)//把advalue高位元組中的數左移一位

5.2  彙編指令定址c函式的區域性變數

前面已經提到,picc對自動型區域性變數(包括函式呼叫時的入口引數)採用一種「靜態覆蓋」技術,對每乙個變數確定乙個固定位址(位於bank0),嵌入的彙編指令對其定址時只需採用資料暫存器的直接定址方式即可,因此關鍵是要知道這些區域性變數的定址符號。建議讀者先編寫一小段c**,其中有最簡單的區域性變數操作指令,把此源**編譯成對應的picc彙編指令;檢視c編譯器生成的彙編指令是如何定址這些區域性變數的,自己編寫的行內彙編指令就採用同樣的定址方式。

相對於組合語言,用c語言程式設計的優勢是毋庸置疑的:開發效率大大提高、人性化的語句指令及模組化的程式易於日常管理和維護、程式在不同平台間移植方便。所以既然使用c語言程式設計,就應該盡量避免嵌入彙編指令或編寫彙編指令模組檔案。例如:

count1=8;

while(count1>0)

變數的迴圈右移操作用c語言實現非常不方便,pic微控制器已有對應的移位操作彙編指令,因此用嵌入彙編的形式實現效率最高。對移位次數的控制,實際上變數count1的遞減判零也可以直接用彙編指令實現,這樣可節約**,但用標準c語言描述更直觀、更易於維護。

6  注意事項

① 既然所有的區域性變數將占用bank0的儲存空間,因此使用者自己定位在bank0內的變數位元組數將受到一定的限制,在實際使用時需注意。 ②

當程式中把非位變數進行強制型別轉換成位變數時,要注意編譯器只對普通變數的最低位做判別:若最低位是0,則轉換成位變數0;若最低位是1,則轉換成位變數1。

③ 由於pic系列微控制器的內部資源十分有限,所以在允許的條件下應盡量使用無符號字元型變數,以節約空間。

unsigned char advalue @ 0x20 ;//advalue定位在位址0x20,相當於組合語言中的偽指令

advalue equ 20h

所以請讀者慎用。 ⑤

盡量使用全域性變數進行引數傳遞,使用全域性變數最大的好處是定址直觀,只需在c語言定義的變數名前增加乙個下劃線符即可在彙編語句中定址;使用全域性變數進行引數傳遞的效率也比形參高。

⑥ 對於多位元組變數(如int型、float型變數等)picc遵循little

endian標準,即低位元組放在儲存空間的低位址,高位元組放在高位址,程式設計時需注意。 結語

一般c語言產生的**是比較繁瑣的,所以要寫出高質量、實用的c語言程式,就必須對微控制器體系結構和硬體資源作詳盡的了解。用c語言開發pic系列微控制器系統軟體具有編寫**效率高、軟體除錯直觀、維護公升級方便、**的重複利用率高、便於跨平台的**移植等優點,因此c語言程式設計在微控制器系統設計中的應用必將越來越廣泛。

PIC微控制器入門 PICC標頭檔案介紹

picc支援下的c程式 中一定要包含pic.h標頭檔案,該檔案安裝在ht pic include目錄下。它是很多標頭檔案的集合,c編譯器在pic.h中根據使用者選擇的晶元自動載入相應的其它標頭檔案,例如使用者選擇的晶元是pic16f877,則pic.h會把pic1687x.h載入 例如使用者選擇的晶...

PIC微控制器入門 PICC的指向RAM的指標

將30h,31h,32h單元中最大的數放入40h。include static volatile unsigned char add1 0x30 static volatile unsigned char add2 0x31 static volatile unsigned char add3 0x...

PIC微控制器引腳

微控制器的訊號引腳是微控制器外特性的體現,在硬體上使用者只能使用引腳,通過引腳的連線組建微控制器系統。pic 8位微控制器系列和mcs 51系列微控制器一樣,其引腳除電源 vdd vss為單一功能外,其餘的訊號引腳常是多個功能,即引腳的復用功能。常見的引腳符號和主要功能如下 1 clr vpp 清除...