摘要:文章通過9個程序詳細介紹PIC單片機在PICC編譯器環(huán)境下,C語言與匯編語言混合編程的方法并對出現(xiàn)的情況進行分析解決,最后對C語言與匯編語言混合編程的優(yōu)劣提出自已的看法。
關鍵詞:PIC單片機;PICC編譯器;C語言;匯編語言
中圖分類號:TP312文獻標識碼:A文章編號:1009-3044(2010)11-2640-05
Analysis Based on C Language and Assembler Language Mix Programming in PICC Compiler
LIU Jin-ping, YE Sai-feng
(Fujian Electric Vocational and Technical College, Quanzhou 362000, China)
Abstract: Articles detailed C language and assembly language mixed programming methodology and anslysis and settlement according to these problems of PIC singlechip in PICC compiler environment through 9 program and lastly presented their own views on the advantages and disadvantages of C language and assembly language mixed programming .
Key words: PICC singlechip; PICC compiler; C language; assembler language
目前,最常用PIC單片機C語言編程環(huán)境是MATLAB調(diào)試環(huán)境和HI-TECH編譯器PICC。雖然還有眾多支持PIC單片機的C語言編譯器,但PICC因為穩(wěn)定、可靠、編譯生成的代碼效率高,而受到青睞。用C語言來開發(fā)PIC單片機系統(tǒng)軟件最大的好處是編寫代碼效率高,軟件高度直觀、維護升級方便、代碼的重復利用率高、便于跨平臺的代碼移植等。因此用C語言編程,在進行系統(tǒng)設計和開發(fā)的工程師群體中得到廣泛認可。既然C語言是一種強有力的程序設計語言,那么是不是就可以拋棄匯編語言?寫單片機C程序最關鍵的一點是單片機內(nèi)設資源非常有限,同時,要求控制的實時性高,這就要求對單片機體系結構和硬件資源有詳盡的了解,而這些恰恰是匯編語言的優(yōu)勢,所以對于PIC愛好者,尤其初學者而言,C語言與匯編語言混編是不可避免的。實際上,C語言和匯編語言混合編程可以使單片機應用程序的開發(fā)效率和程序本身的運行效率達到最佳的配合。
1 PICC對RAM的特殊要求
下面,我們通過一個引例的不同編程來看PICC對RAM的特殊要求。
例:將RAM中的BANK0的0X20~0X2F共16個單元置為55H。
1.1 采用匯編語言編程
程序1:
INCLUDE\"P16F877.INC\"
MOVLW 0X20
MOVWF FSR
MOVLW 55H
ABCMOVWFINDF
INCF FSR ,F(xiàn)
BTFSSFSR ,4
GOTOABC
GOTO$
END
程序1經(jīng)過調(diào)試,運行后能實現(xiàn)引例功能。
1.2 采用C語言編程
程序2:
#include\"pic.h\"
unsigned char i;
unsigned char *tmp;
void main()
{
tmp=0x20;
for(i=1;i<17;i++)
{
(*tmp)=0x55;
tmp++;
}
}
程序2中運用指針知識,經(jīng)過調(diào)試沒有發(fā)現(xiàn)錯誤,但運行后根本無法滿足引例的要求。
修改程序2第2行為:“bank2 unsigned char i;”,即變量i改到RAM的BANK2。運行的結果是將0X56~0X64共15個單元置為55H。再次將程序2第6行修改為:“tmp=0x21;”,運行后,RAM的0X21~0X30共16個單元置為55H,離要求還有一點距離。
1.3 采用C語言絕對定位技術
程序3:
#include\"pic.h\"
bank2 unsigned char i;
static volatile unsigned char *tmp @ 0x30;
void main()
{
tmp=0x20;
for(i=1;i<17;i++)
{
(*tmp)=0x55;
tmp++;
}
}
程序3將定義的指針定位在BANK0的0X30單元開始的區(qū)域,與0X20~0X2F區(qū)域沒有沖突。經(jīng)過調(diào)試運行能實現(xiàn)引例功能。
1.4 采用C語言與匯編語言混編
程序4:
#include\"pic.h\"
bank2 unsigned char i;
void main()
{#asm
MOVLW0X20
MOVWF_FSR
MOVLW0X55
MOVWF_INDF
#endasm
for(i=1;i<16;i++)
{#asm
INCF _FSR,F(xiàn)
MOVLW0X55
MOVWF _INDF
#endasm
}
}
程序4中唯一變量i 定義在RAM的BANK2區(qū)域,程序經(jīng)過調(diào)試運行能實現(xiàn)引例功能。要說明的是,C語言與匯編語言混編時,匯編語言部分的特殊功能寄存器名必須采用下劃線引導和大寫字母。
從以上不同方法的編程出現(xiàn)的結果,可以看出在C語言環(huán)境下,PICC對File Registers(RAM數(shù)據(jù)存儲器)中的20H~7FH單元具有絕對使用權,這些單元位于BANK0的最后,即通用寄存器的96個字節(jié)。所以,在編程時若要應用這部分單元,那么,則在C語言中定義的所有變量必須放在除BANK0外的RAM中,否則運行結果不可預料。
2 PICC混編時對傳遞參數(shù)的要求
2.1 采用局部變量進行主函數(shù)與自定義函數(shù)之間的數(shù)據(jù)傳遞
PICC規(guī)定,應用局部變量傳遞數(shù)據(jù),在匯編語言部分引用參數(shù)時,第2 個形參要寫成?_函數(shù)名,第3個形參要寫成?_函數(shù)名+1,以此類推。而第1個形參以及函數(shù)內(nèi)部自定義變量必須分別命名為?a_函數(shù)名,?a_函數(shù)名+1,……,至于?a_函數(shù)名先分配給第1個形參或是第1個自定義變量則不確定。
程序5:
#include
void Test(unsigned char inVar1, unsigned char inVar2,unsigned char inVar3,unsigned char inVar4)
{
unsigned char tmp1=0;
inVar1++;
asm(\"incf ?a_Test+1,f\");
asm(\"decf ?_Test,f\");//inVar2--;
#asm//inVar3+=5;
movf ?_Test+1,w
addlw 0x5
movwf ?_Test+1
#endasm
#asm//inVar4-=0x5左移一位,低位補1;
bsf _STATUS,0
rlf ?_Test+2,f
#endasm
#asm //tmp1=inVar1;
movf ?a_Test+1,w
movwf ?a_Test
#endasm
}
void main()
{
unsigned char t1,t2;
t1=t2=10;
Test(t1,t2,t1,t2);
}
程序5中的自定義函數(shù)名為Test,共有inVar1~inVar4等4個形參,函數(shù)內(nèi)部還有1個自定義變量tmp1。在匯編語言中inVar1寫成?a_Test+1、inVar2~inVar4分別寫成?_Test~?_Test+2、而tmp1寫成?a_Test。需要說明的是:
1) 程序中C語言部分若不對第1個形參inVar1進行操作,則在匯編語言部分中對inVar1處理是無效的!也就是不分配內(nèi)在單元給inVar1。
2) 程序中C語言部分若不對函數(shù)內(nèi)部的自定義tmp1進行賦值或運算,則在匯編部分對tmp1處理是無效的,也就是不分配RAM空間。
以上兩點,在進行C語言與匯編語言混編時應特別關注。
2.2 采用全局變量進行主函數(shù)與自定義函數(shù)之間的數(shù)據(jù)傳遞
程序6:
#include
volatile unsigned char tmp;
volatile bank1 unsigned char tmp1;
volatile bank2 unsigned char tmp2;
void Test(void)
{
#asm
clrf _STATUS
movlw 0x55
movwf _tmp
#endasm
}
void Test1(void)
{
#asm
clrf _STATUS
movlw 0x10
movwf _tmp
bcf _STATUS,6
BSF _STATUS,5
movlw 0x20
movwf _tmp1^0x80;非BANK0變量,在匯編語言中使用要如此
#endasm
}
void main()
{
while(1)
{
Test1();
if(tmp==0x10)
{
tmp=0xab;
}
if(tmp1==0x20)
{
tmp1=0xcd;
}
Test();
tmp2=tmp+tmp1;
}
}
程序6采用全局變量傳遞數(shù)據(jù),共定義tmp、tmp1、tmp2三個全局變量,分別定義在RAM的BANK0、BANK1、BANK2,其中tmp、tmp1用于函數(shù)之間傳遞函數(shù),在匯編語言部分要使用這兩個全局變量時,只要在變量名前加下劃線作為引導就可以了。但要注意的是,若這些全局變量定義在非BANK0,如程序中的tmp,則在匯編語言部分使用時,必須寫成_tmp1^0x80。若是定義在BANK1,就得寫成_tmp1^0x100,若是定義在BANK2,就得寫成_tmp1^0x180。
程序7:
#include
volatile unsigned char inVar1,inVar2,inVar3,inVar4;
void Test()
{
unsigned char tmp1=0;
//inVar1-=1;
asm(\"incf _inVar1,f\");
//inVar2--;
asm(\"decf _inVar2,f\");
//inVar3+=5;
#asm
movf _inVar3,w
addlw 0x5
movwf _inVar3
#endasm
//inVar4-=0x5左移一位,低位補1;
#asm
bsf _STATUS,0
rlf _inVar4,f
#endasm
//tmp1=inVar1;
#asm
movf _inVar1,w
movwf ?a_Test
#endasm
}
void main()
{
unsigned char tmp1=2;
inVar1=inVar2=inVar3=inVar4=10;
Test();
inVar1=inVar4;inVar3=tmp1;
}
程序7除定義了全局變量,還在自定義函數(shù)中定義了一個自定義變量tmp1,同樣在匯編部分要換名為?a_Test,需要說明的是,若對tmp1不賦初值,那么在匯編時會出現(xiàn)“找不到?a_Test”錯誤信息,而無法通過匯編。
使用全局變量最大的好處是尋址直觀,只需在 C 語言定義的變量名前增加一個下劃線,即可在匯編語句中尋址,使用全局變量進行參數(shù)傳遞效率比形參傳遞高。
3 C語言主函數(shù)內(nèi)含匯編語言的情況
程序8:
#include
void main()
{
unsigned char tmp,i;
while(1)
{
tmp=1;
#asm
movf ?a_main+1,w
movwf ?a_main
#endasm
i++;
} }
程序8在主函數(shù)內(nèi)定義兩個變量,這兩個變量在匯編語言部分使用時,必須換名為 ?a_main和 ?a_main+1,需要說明的是,第1 個自定義變量tmp,在匯編語言部分使用?a_main前,在C語言部分必須先進行賦初值或計算,否則會出現(xiàn)錯誤。
程序9:
#include
volatileunsigned char tmp,i;
void main()
{
while(1)
{
//tmp=1;
#asm
movf _i,w
movwf _tmp
#endasm
i++;
} }
程序9在主函數(shù)外定義了兩個全局變量,它們在匯編語言部分使用比較簡單,只要在變量前加下劃線引導就可以。
4 結束語
可以看出,C語言和匯編語言混合編程在具體實施時,一定要注意許多細節(jié)問題,否則運算結果不可預料。
一般來說,在項目開發(fā)過程中,程序量較大且PICC 進行后道編譯優(yōu)化,采用C語言編寫的代碼不會比全部用匯編編寫的代碼差多少。所以,既然用了C語言編程,就盡量避免使用嵌入?yún)R編指令或整個地編寫匯編指令模塊文件。對于非得采用C語言和匯編語言混合編程,一定要注意:1)盡量使用嵌入?yún)R編;2)盡量使用全局變量進行參數(shù)傳遞。
參考文獻:
[1] 李榮正.PIC單片機原理及應用[M].北京:北京航空航天大學出版社,2006.
[2] 周堅.PIC單片機輕松入門[M].北京:北京航空航天大學出版社,2009.
[3] 張明峰.PIC單片機入門與實戰(zhàn)[M].北京:北京航空航天大學出版社,2004.