完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
AVR的两种位操作的比较(位域方式和移位宏方式)
测试环境如下: 硬件:AT90S2313 软件: WiinAVR gcc3.3 -Os级优化(最小size)。 说明: 由于AVR不支持位操作,所以必须通过软件来实现。下面对我所知道的两种方法进行一个简单的比较。 1、位域方式。先定义一个位域, typedef struct _bit_struct { unsigned char bit0 : 1 ; unsigned char bit1 : 1 ; unsigned char bit2 : 1 ; unsigned char bit3 : 1 ; unsigned char bit4 : 1 ; unsigned char bit5 : 1 ; unsigned char bit7 : 1 ; unsigned char bit6 : 1 ; }bit_field; 再用一个宏 ,来指向要操作的位。 #define LED GET_BITFIELD(PORTB).bit0 #define BUTTON GET_BITFIELD(PINB).bit7 使用时只需要直接赋值即可:如LED = 0 ,LED = 1, 或者直接判断 LED==0 , LED ==1. 这种方法类似C51中的位操作。直接。 2、位移宏方式。主要有三个. #define Set_Bit(val, bitn) (val |=(1<<(bitn))) #define Clr_Bit(val, bitn) (val&=~(1<<(bitn))) #define Get_Bit(val, bitn) (val &(1<<(bitn)) ) 三个分别用来设置某一位,清除某一位,取某一位的值. 使用方法为.Set_Bit(PORTA,3); Clr_Bit(PORTB,2); Get_Bit(val,5); 3、测试程序. 说明,假设PORTB.7接按纽,PORTB.0 接LED 测试程序完成如下操作。 当BUTTON == 0时 ,LED输出1 否则输出0, 这样的目的是即测试了输入,又测试了输出1和输出0,相对全面一点。 C代码如下. // testled.c 测试AVR的位操作. // 这是gcc;如是其它编译器,请修改。 #include // typedef struct _bit_struct { unsigned char bit0 : 1 ; unsigned char bit1 : 1 ; unsigned char bit2 : 1 ; unsigned char bit3 : 1 ; unsigned char bit4 : 1 ; unsigned char bit5 : 1 ; unsigned char bit7 : 1 ; unsigned char bit6 : 1 ; }bit_field; //定义一个宏,用来得到每一位的值 #define GET_BITFIELD(addr) (*((volatile bit_field *) (addr))) //定义每一个位 #define LED GET_BITFIELD(PORTB).bit0 #define BUTTON GET_BITFIELD(PINB).bit7 #define Set_Bit(val, bitn) (val |=(1<<(bitn))) #define Clr_Bit(val, bitn) (val&=~(1<<(bitn))) #define Get_Bit(val, bitn) (val &(1<<(bitn)) ) int main( void ) { DDRB = 0x41; //配置PB0为输出,PB7为输入 if ( BUTTON==0 ) LED = 1; else LED = 0; //if(!Get_Bit(PINB,7) ) Set_Bit(PORTB,0); else Clr_Bit(PORTB,0); while(1); } // ---------------------- end ----------------------------- 4、测试过程。 a.先使用位域方式。 主程序中使用 if ( BUTTON==0 ) LED = 1; else LED = 0; 结果如下: int main( void ) { 4a: cf ed ldi r28, 0xDF ; 223 4c: d0 e0 ldi r29, 0x00 ; 0 4e: de bf out 0x3e, r29 ; 62 50: cd bf out 0x3d, r28 ; 61 DDRB = 0x41; //配置PB0为输出,PB7为输入 52: 81 e4 ldi r24, 0x41 ; 65 54: 87 bb out 0x17, r24 ; 23 if ( BUTTON==0 ) LED = 1; else LED = 0; 56: 86 b3 in r24, 0x16 ; 22 58: e8 2f mov r30, r24 5a: ff 27 eor r31, r31 5c: 80 81 ld r24, Z 5e: 86 fd ***rc r24, 6 60: 07 c0 rjmp .+14 ; 0x70 62: 88 b3 in r24, 0x18 ; 24 64: e8 2f mov r30, r24 66: ff 27 eor r31, r31 68: 80 81 ld r24, Z 6a: 81 60 ori r24, 0x01 ; 1 6c: 80 83 st Z, r24 6e: 06 c0 rjmp .+12 ; 0x7c 70: 88 b3 in r24, 0x18 ; 24 72: e8 2f mov r30, r24 74: ff 27 eor r31, r31 76: 80 81 ld r24, Z 78: 8e 7f andi r24, 0xFE ; 254 7a: 80 83 st Z, r24 while(1); 7c: ff cf rjmp .-2 ; 0x7c main函数共52Bytes.其中,从lst文件看得出:main函数的初始化用了4条指令,8Bytes. 最后一句while(1);用了1条指令2Bytes.( for循环和do-while也是) DDRB=0x41用了2条指令4Bytes. 计算一下:52-8-4-2=38Bytes,即if ( BUTTON==0 ) LED = 1; else LED = 0; 这句用了19条指令38Bytes. (居然运用了3个寄存器白r24,r30,r31,和一个Z,代码真是苦涩,,我看不懂,准备以后作代码加密用. ) b.使用移位宏方式。 将 if ( BUTTON==0 ) LED = 1; else LED = 0; 换为等效的 if(!Get_Bit(PINB,7) ) Set_Bit(PORTB,0); else Clr_Bit(PORTB,0); 结果,main函数仅24Bytes.其它代码一样,略去. 所以,上面这句代码仅用了24-14=10Bytes ,5条指令。生成的代码如下: 56: b7 99 ***ic 0x16, 7 ; 22 58: 02 c0 rjmp .+4 ; 0x5e 5a: c0 9a ***i 0x18, 0 ; 24 5c: 01 c0 rjmp .+2 ; 0x60 5e: c0 98 cbi 0x18, 0 ; 24 5. 菜论:鱼和熊掌。 由于AVR可以对I/O脚进行***ic,***i,cbi,这样的位操作,所以使用I/O脚操作时,移位宏可以产生高效的代码。 例如,要实现上面的几个简单的指令,为了实现LED=1这样的类似C51的***it的效果,我必须多付出(38-10=28Bytes)的代价。 6...... 对于I/O脚,可以产生这样高效的代码,是因为有***i和cbi这样的指令,那么对于一般的变量,又如何呢?. |
|
相关推荐
|
|
【RA-Eco-RA2E1-48PIN-V1.0开发板试用】(第三篇)ADC采集+PWM输出
515 浏览 0 评论
《DNK210使用指南 -CanMV版 V1.0》第四十五章 人脸识别实验
515 浏览 0 评论
780 浏览 0 评论
如何用OpenCV的相机捕捉视频进行人脸检测--基于米尔NXP i.MX93开发板
1360 浏览 0 评论
《DNK210使用指南 -CanMV版 V1.0》第四十章 YOLO2人手检测实验
572 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11757 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 00:49 , Processed in 0.630957 second(s), Total 67, Slave 51 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号