<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > PIC 單片機 C 語(yǔ)言編程簡(jiǎn)介(4)

PIC 單片機 C 語(yǔ)言編程簡(jiǎn)介(4)

作者: 時(shí)間:2016-11-22 來(lái)源:網(wǎng)絡(luò ) 收藏
11.9

C 和匯編混合編程

本文引用地址:http://dyxdggzs.com/article/201611/319598.htm

有兩個(gè)原因決定了用 C 語(yǔ)言進(jìn)行單片機應用程序開(kāi)發(fā)時(shí)使用匯編語(yǔ)句的必要性:?jiǎn)纹?/p>


機的一些特殊指令操作在標準的 C 語(yǔ)言語(yǔ)法中沒(méi)有直接對應的描述,例如 PIC 單片機的清

看門(mén)狗指令“clrwdt”和休眠指令“sleep”;單片機系統強調的是控制的實(shí)時(shí)性,為了實(shí)現這

一要求,有時(shí)必須用匯編指令實(shí)現部分代碼以提高程序運行的效率。這樣,一個(gè)項目中就會(huì )

出現 C 和匯編混合編程的情形,我們在此討論一些混合編程的基本方法和技巧。

11.9.1 嵌入行內匯編的方法

C 原程序中直接嵌入匯編指令是最直接最容易的方法。如果只需要嵌入少量幾條的

匯編指令,PICC 提供了一個(gè)類(lèi)似于函數的語(yǔ)句:

asm(“clrwdt”);

雙引號中可以編寫(xiě)任何一條 PIC 的標準匯編指令。例如:

for (;;) {

asm("clrwdt"); //清看門(mén)狗

Task();

ClockRun();


asm("sleep");

asm("nop");

}


//休眠

//空操作延時(shí)

例 11-8 逐行嵌入匯編的方式

如果需要編寫(xiě)一段連續的匯編指令,PICC 支持另外一種語(yǔ)法描述:用“#asm”開(kāi)始匯

編指令段,用“#endasm”結束。例如下面的一段嵌入匯編指令實(shí)現了將 0x20~0x7F 間的

RAM 全部清零:

#asm

movlw 0x20

movwf _FSR

clrf _INDF

incf _FSR,f

btfss _FSR,7

goto $-3

#endasm

例 11-9 整段嵌入匯編的方式

11.9.2 匯編指令尋址 C 語(yǔ)言定義的全局變量

C 語(yǔ)言中定義的全局或靜態(tài)變量尋址是最容易的,因為這些變量的地址已知且固定。按

C 語(yǔ)言的語(yǔ)法標準,所有 C 中定義的符號在編譯后將自動(dòng)在前面添加一下劃線(xiàn)符“_”,因

此,若要在匯編指令中尋址 C 語(yǔ)言定義的各類(lèi)變量,一定要在變量前加上一“_”符號,我

們在上面例 11-9 中已經(jīng)體現了這一變量引用的法則,因為 FSR 和 INDF 等所有特殊寄存器

是以 C 語(yǔ)言語(yǔ)法定義的,因此匯編中需要對其尋址時(shí)前面必須添加下劃線(xiàn)。

對于 C 語(yǔ)言中用戶(hù)自定義的全局變量,用行內匯編指令尋址時(shí)也同樣必須加上“_” ,

下面的例 11-10 說(shuō)明了具體的引用方法:

volatile unsigned char tmp; //定義位于 bank0 的字符型全局變量

void Test(void)

{

#asm

clrf _STATUS

movlw 0x10

movwf _tmp

#endasm

if (tmp==0x10) {

;

}

}

//測試程序

//開(kāi)始行內匯編

//選擇 bank0

//設定初值

//tmp=0x10

//結束行內匯編

//開(kāi)始 C 語(yǔ)言程序


例 11-10 行內匯編尋址 C 全局變量(位于 bank0)

上面的例子說(shuō)明了匯編指令中尋址 C 語(yǔ)言所定義變量的基本方法。PICC 在編譯處理嵌

入的行內匯編指令時(shí)將會(huì )原封不動(dòng)地把這些指令復制成最后的機器碼。所有對 C 編譯器所

作的優(yōu)化設定對這些行內匯編指令而言將不起任何作用。編程員必須自己負責編寫(xiě)最高效的

匯編代碼,同時(shí)處理變量所在的 bank 設定。對于定義在其它 bank 中的變量,還必須在匯編

指令中加以明確指示,見(jiàn)例 11-11 的代碼范例。

volatile bank1 unsigned char tmpBank1; //定義位于 bank1 的字符型全局變量

volatile bank2 unsigned char tmpBank2; //定義位于 bank2 的字符型全局變量

volatile bank3 unsigned char tmpBank3; //定義位于 bank3 的字符型全局變量

void Test(void)

{

#asm

bcf _STATUS,6

bsf _STATUS,5

movlw 0x10

movwf _tmpBank1^0x80

bsf _STATUS,6

bcf _STATUS,5

movlw 0x20

//測試程序

//開(kāi)始行內匯編

//選擇 bank1

//設定初值

//tmpBank1=0x10

//選擇 bank2

//設定初值


movwf _tmpBank1^0x100 //tmpBank2=0x20

bsf _STATUS,6

bsf _STATUS,5

movlw 0x30


//選擇 bank3

//設定初值


movwf _tmpBank1^0x180 //tmpBank1=0x30


}


#endasm


//結束行內匯編

例 11-11 行內匯編尋址 C 全局變量(非 bank0 變量)


通過(guò)上面的代碼實(shí)例,我們可以掌握這樣一個(gè)規律:在行內匯編指令中尋址 C 語(yǔ)言定

義的全局變量時(shí),除了在尋址前設定正確的 bank 外,在指令描述時(shí)還必須在變量上異或

所在 bank 的起始地址,實(shí)際上位于 bank0 的變量在匯編指令中尋址時(shí)也可以這樣理解,只

是異或的是 0x00,可以省略。如果你了解 PIC 單片機的匯編指令編碼格式,上面異或的 bank

起始地址是無(wú)法在真正的匯編指令中體現的,其目的純粹是為了告訴 PICC 連接器變量所在

的 bank,以便連接器進(jìn)行 bank 類(lèi)別檢查。

11.9.3 匯編指令尋址 C 函數的局部變量

前面已經(jīng)提到,PICC 對自動(dòng)型局部變量(包括函數調用時(shí)的入口參數)采用一種“靜

態(tài)覆蓋”技術(shù)對每一個(gè)變量確定一個(gè)固定地址(位于 bank0),因此嵌入的匯編指令對其尋

址時(shí)只需采用數據寄存器的直接尋址方式即可,唯一要考慮的是如何才能在編寫(xiě)程序時(shí)知道

這些局部變量的尋址符號(具體地址在最后連接后才能決定,編程時(shí)無(wú)需關(guān)心)。一個(gè)最實(shí)

用也是最可靠的方法是先編寫(xiě)一小段 C 代碼,其中有最簡(jiǎn)單的局部變量操作指令,然后參

考圖 11-5(B)對話(huà)框選擇“Compile to assembly only”,把此 C 原代碼編譯成對應的 PICC 匯

編指令;查看 C 編譯器生成的匯編指令是如何尋址這些局部變量的,你自己編寫(xiě)的行內匯

編指令就采用同樣的尋址方式。例如,例 11-12 的一小段 C 原代碼編譯出的匯編指令

//C 原程序代碼

void Test(unsigned char inVar1, inVar2)

{

unsigned char tmp1, tmp2;

inVar1++;

inVar2--;

tmp1 = 1;

tmp2 = 2;

}

//編譯器生成的匯編指令

_Test

; _tmp1 assigned to ?a_Test+0 //tmp1 的尋址符為 ?a_Test+0


_Test$tmp1 set


?a_Test


; _tmp2 assigned to ?a_Test+1 //tmp2 的尋址符為 ?a_Test+1


_Test$tmp2 set


?a_Test+1


; _inVar1 assigned to ?a_Test+2 //inVar1 的尋址符為 ?a_Test+2

_Test$inVar1 set ?a_Test+2

44line


;_inVar1 stored from w

bcf

bcf

movwf ?a_Test+2


//第一個(gè)字符型行參由 W 寄存器傳遞


;ht16.c: 43: unsigned char tmp1, tmp2;

incf

45line

;ht16.c: 45: inVar2--;


decf

46line

;ht16.c: 46: tmp1 = 1;

clrf

incf

47line

;ht16.c: 47: tmp2 = 2;

movlw 2

movwf ?a_Test+1

48line

;ht16.c: 48: }

return


//行參 inVar2 的尋址符為 ?_Test


例 11-12 PICC 實(shí)現局部變量操作的尋址方式

基于上面得到的 PICC 編譯后局部變量的尋址方式,我們在 C 語(yǔ)言程序中用嵌入匯編指

令時(shí)必須采樣同樣的尋址符以實(shí)現對應變量的存取操作,見(jiàn)下面的例 11-13。

//C 原程序代碼

void Test(unsigned char inVar1, inVar2)

{

unsigned char tmp1, tmp2;

#asm

//開(kāi)始嵌入匯編


incf

decf

movlw

addwf

rrf

0x10


?a_Test+0,f

?a_Test+1,f

?a_Test+2,f

?_Test,w


//tmp1++;

//tmp2--;

//inVar1 +=

//inVar2 循環(huán)右移一位

}


rrf

#endasm


?_Test,f

//結束嵌入匯編


例 11-13 嵌入匯編指令實(shí)現局部變量尋址操作

如果局部變量為多字節形式組成,例如整型數、長(cháng)整型等,必須按照 PICC 約定的存儲

格式進(jìn)行存取。前面已經(jīng)說(shuō)明了 PICC 采用“Little endian”格式,低字節放在低地址,高字

節放在高地址。下面的例 11-14 實(shí)現了一個(gè)整型數的循環(huán)移位,在 C 語(yǔ)言中沒(méi)有直接針對循

環(huán)移位的語(yǔ)法操作,用標準 C 指令實(shí)現的效率較低。

//16 位整型數循環(huán)右移若干位

unsigned int RR_Shift16(unsigned int var, unsigned char count)

{

}


while(count--)

{

#asm

rrf ?_RR_Shift16+0,w

rrf ?_RR_Shift16+1,f

rrf ?_RR_Shift16+0,f

#endasm

}

return(var);


//移位次數控制

//開(kāi)始嵌入匯編

//最低位送入 C

//var 高字節右移 1 位,C 移入最高位

//var 低字節右移 1 位

//結束嵌入匯編

//返回結果


例 11-14 嵌入匯編指令對多字節變量的操作

11.9.4 混合編程的一些經(jīng)驗

C 和匯編語(yǔ)言混合編程可以使單片機應用程序的開(kāi)發(fā)效率和程序本身的運行效率達到

最佳的配合。筆者從實(shí)際應用中得到一些經(jīng)驗供讀者一起分享。

慎用匯編指令

相比于匯編語(yǔ)言,用 C 語(yǔ)言編程的優(yōu)勢是毋庸置疑的:開(kāi)發(fā)效率大大提高、人性化的

語(yǔ)句指令加上模塊化的程序易于日常管理和維護、程序在不同平臺間的移植方便。所以既然

用了 C 語(yǔ)言編程,就盡量避免使用嵌入匯編指令或整個(gè)地編寫(xiě)匯編指令模塊文件。PICC 已

具備高效的優(yōu)化功能,如果在寫(xiě) C 原程序時(shí)就十分注意程序的編譯和運行效率問(wèn)題,加上

PICC 的后道編譯優(yōu)化,最后得到的代碼效率不會(huì )比全部用匯編編寫(xiě)的代碼差多少,尤其是

程序量較大時(shí)。另外,PICC 對數據存儲空間的利用率肯定比用戶(hù)人工定位變量時(shí)的利用率

要高,同時(shí)還提供完整的庫函數支持。C 語(yǔ)言的語(yǔ)法功能強大,能夠高效率地實(shí)現絕大部分

控制和運算功能。因此,除了一些十分強調單片機運行時(shí)間的代碼或 C 語(yǔ)言沒(méi)有直接對應

的操作可以考慮用匯編指令實(shí)現外,其它部分都應該用 C 語(yǔ)言編寫(xiě)。

以上面的例 11-14 進(jìn)一步說(shuō)明,變量的循環(huán)右移操作用 C 語(yǔ)言實(shí)現非常不方便,PIC 單

片機已有對應的移位操作匯編指令,因此用嵌入匯編的形式實(shí)現效率最高。同時(shí)對移位次數

的控制,本質(zhì)上說(shuō)變量 count 的遞減判零也可以直接用匯編指令實(shí)現,但這樣做節約不了多

少代碼,用標準的 C 語(yǔ)言描述更直觀(guān),更易于維護。

一句話(huà):用了 C 語(yǔ)言后,就不要再老想著(zhù)用匯編。

盡量使用嵌入匯編

這和上面的慎用匯編指令的說(shuō)法并不矛盾。如果確實(shí)需要用匯編指令實(shí)現部分代碼以提

高運行效率,應盡量使用行內匯編,避免編寫(xiě)純匯編文件(*.as 文件)。

雖然 PICC 支持 C 和匯編原程序模塊存在于同一個(gè)項目中,但要編寫(xiě)純匯編文件必須首

先了解 PICC 特有的匯編語(yǔ)法結構。Hitech 公司提供了完整的文檔介紹其匯編器的使用方法,

有興趣者可以從其網(wǎng)站上下載 PICC 的用戶(hù)使用手冊查看。

筆者認為,類(lèi)似于純匯編文件的代碼也可以在 C 語(yǔ)言框架下實(shí)現,方法是基于 C 標準

語(yǔ)法定義所有的變量和函數名,包括需要傳遞的形式參數、返回參數和局部變量,但函數內

部的指令基本用嵌入匯編指令編寫(xiě),只有最后的返回參數用 C 語(yǔ)句實(shí)現。這樣做后函數的

運行效率和純匯編編寫(xiě)時(shí)幾乎一模一樣,但各參數的傳遞統一用 C 標準實(shí)現,這樣管理和

維護就比較方便。例如下面的例 11-15 實(shí)現一個(gè)字節變量的偶校驗位計算。

bit EvenParity(unsigned char data)

{

#asm


swapf ?a_EvenParity+0,w

xorwf ?a_EvenParity+0,f

rrf ?a_EvenParity+0,w

xorwf ?a_EvenParity+0,f

btfsc ?a_EvenParity+0,2

incf ?a_EvenParity+0,f

#endasm

//至此,data 的最低位即為偶校驗位

if (data&0x01) return(1);

else return(0);

}


//入口參數 data 的尋址符為 ?a_EvenParity+0


例 11-15 C 函數框架中使用嵌入匯編指令

盡量使用全局變量進(jìn)行參數傳遞

使用全局變量最大的好處是尋址直觀(guān),只需在 C 語(yǔ)言定義的變量名前增加一個(gè)下劃線(xiàn)

符即可在匯編語(yǔ)句中尋址;使用全局變量進(jìn)行參數傳遞的效率也比形參高。編寫(xiě)單片機的 C

程序時(shí)不能死硬強求教科書(shū)上的模塊化編程而大量采用行參和局部變量的做法,在開(kāi)發(fā)編程

時(shí)應視實(shí)際情況靈活變通,一切以最高的代碼效率為目標。



關(guān)鍵詞: PIC單片機C語(yǔ)言編

評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>