AVR的兩種位操作的比較(wjc3k發(fā)于21ic)(位域與C位操作的比較)AVR的兩種位操作的比較(位域方式和移位宏方式)
測(cè)試環(huán)境如下:
硬件:AT90S2313
軟件:WiinAVRgcc3.3-Os級(jí)優(yōu)化(最小size)。
說明:
由于AVR不支持位操作,所以必須通過軟件來實(shí)現(xiàn)。下面對(duì)我所知道的兩種方法進(jìn)行一個(gè)簡(jiǎn)單的比較。
1、位域方式。先定義一個(gè)位域,
typedefstruct_bit_struct
{
unsignedcharbit0:1;
unsignedcharbit1:1;
unsignedcharbit2:1;
unsignedcharbit3:1;
unsignedcharbit4:1;
unsignedcharbit5:1;
unsignedcharbit6 :1;
unsignedcharbit7:1;
}bit_field;
再用一個(gè)宏,來指向要操作的位。
#defineLEDGET_BITFIELD(PORTB).bit0
#defineBUTTONGET_BITFIELD(PINB).bit7
使用時(shí)只需要直接賦值即可:如LED=0,LED=1,或者直接判斷LED==0,LED==1.
這種方法類似C51中的位操作。直接。
2、位移宏方式。主要有三個(gè).
#defineSet_Bit(val,bitn)(val|=(1<<(bitn)))
#defineClr_Bit(val,bitn)(val&=~(1<<(bitn)))
#defineGet_Bit(val,bitn)(val&(1<<(bitn)))
三個(gè)分別用來設(shè)置某一位,清除某一位,取某一位的值.
使用方法為.Set_Bit(PORTA,3);Clr_Bit(PORTB,2);Get_Bit(val,5);
3、測(cè)試程序.
說明,假設(shè)PORTB.7接按紐,PORTB.0接LED
測(cè)試程序完成如下操作。
當(dāng)BUTTON==0時(shí),LED輸出1否則輸出0,
這樣的目的是即測(cè)試了輸入,又測(cè)試了輸出1和輸出0,相對(duì)全面一點(diǎn)。C代碼如下.
//testled.c測(cè)試AVR的位操作.
//這是gcc;如是其它編譯器,請(qǐng)修改。
#i nclude<avr/io.h>
//定義一個(gè)寄存器(Register)或端口(Port)的八個(gè)位
typedefstruct_bit_struct
{
unsignedcharbit0:1;
unsignedcharbit1:1;
unsignedcharbit2:1;
unsignedcharbit3:1;
unsignedcharbit4:1;
unsignedcharbit5:1;
unsignedcharbit7:1;
unsignedcharbit6:1;
}bit_field;
//定義一個(gè)宏,用來得到每一位的值
#defineGET_BITFIELD(addr)(*((volatilebit_field*)(addr)))
//定義每一個(gè)位
#defineLEDGET_BITFIELD(PORTB).bit0
#defineBUTTONGET_BITFIELD(PINB).bit7
#defineSet_Bit(val,bitn)(val|=(1<<(bitn)))
#defineClr_Bit(val,bitn)(val&=~(1<<(bitn)))
#defineGet_Bit(val,bitn)(val&(1<<(bitn)))
intmain(void)
{
DDRB=0x41;//配置PB0為輸出,PB7為輸入
if(BUTTON==0)LED=1;elseLED=0;
//if(!Get_Bit(PINB,7))Set_Bit(PORTB,0);elseClr_Bit(PORTB,0);
while(1);
}
//----------------------end-----------------------------
4、測(cè)試過程。
a.先使用位域方式。
主程序中使用if(BUTTON==0)LED=1;elseLED=0;
結(jié)果如下:
intmain(void)
{
4a:cfedldir28,0xDF;223
4c:d0e0ldir29,0x00;0
4e:debfout0x3e,r29;62
50:cdbfout0x3d,r28;61
DDRB=0x41;//配置PB0為輸出,PB7為輸入
52:81e4ldir24,0x41;65
54:87bbout0x17,r24;23
if(BUTTON==0)LED=1;elseLED=0;
56:86b3inr24,0x16;22
58:e82fmovr30,r24
5a:ff27eorr31,r31
5c:8081ldr24,Z
5e:86fdsbrcr24,6
60:07c0rjmp.+14;0x70
62:88b3inr24,0x18;24
64:e82fmovr30,r24
66:ff27eorr31,r31
68:8081ldr24,Z
6a:8160orir24,0x01;1
6c:8083stZ,r24
6e:06c0rjmp.+12;0x7c
70:88b3inr24,0x18;24
72:e82fmovr30,r24
74:ff27eorr31,r31
76:8081ldr24,Z
78:8e7fandir24,0xFE;254
7a:8083stZ,r24
while(1);
7c:ffcfrjmp.-2;0x7c
main函數(shù)共52Bytes.其中,從lst文件看得出:main函數(shù)的初始化用了4條指令,8Bytes.最后一句while(1);用了1條指令2Bytes.(for循環(huán)和do-while也是)
DDRB=0x41用了2條指令4Bytes.計(jì)算一下:52-8-4-2=38Bytes,即if(BUTTON==0)LED=1;elseLED=0;這句用了19條指令38Bytes.(居然運(yùn)用了3個(gè)寄存器白r24,r30,r31,和一個(gè)Z,代碼真是苦澀,,我看不懂,準(zhǔn)備以后作代碼加密用:).)
b.使用移位宏方式。
將if(BUTTON==0)LED=1;elseLED=0;換為等效的if(!Get_Bit(PINB,7))Set_Bit(PORTB,0);elseClr_Bit(PORTB,0);
結(jié)果,main函數(shù)僅24Bytes.其它代碼一樣,略去.所以,上面這句代碼僅用了24-14=10Bytes,5條指令。生成的代碼如下:
56:b799sbic0x16,7;22
58:02c0rjmp.+4;0x5e
5a:c09asbi0x18,0;24
5c:01c0rjmp.+2;0x60
5e:c098cbi0x18,0;24
5.菜論:魚和熊掌。
由于AVR可以對(duì)I/O腳進(jìn)行sbic,sbi,cbi,這樣的位操作,所以使用I/O腳操作時(shí),移位宏可以產(chǎn)生高效的代碼。
例如,要實(shí)現(xiàn)上面的幾個(gè)簡(jiǎn)單的指令,為了實(shí)現(xiàn)LED=1這樣的類似C51的sbit的效果,我必須多付出(38-10=28Bytes)的代價(jià)。
6......
對(duì)于I/O腳,可以產(chǎn)生這樣高效的代碼,是因?yàn)橛衧bi和cbi這樣的指令,那么對(duì)于一般的變量,又如何呢?................
本文引用地址:http://m.butianyuan.cn/article/201611/322371.htm
評(píng)論