查看: 813|回复: 0
打印 上一主题 下一主题

鱼,熊掌.AVR的两种位操作的比较

[复制链接]
跳转到指定楼层
沙发
发表于 2015-10-29 08:50:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
转贴前言:一直看到做51转做AVR的朋友,想继续使用bit这样的操作,讨论也不少。其实对于设计人员的未来考虑,还是使用纯C比较好,毕竟适应性强。C51增加的bit、sbit是考虑了51的SRAM小的特点的。移植性就受到影响了。能放弃,尽量放弃。

-------------------------------------------

wjc3k 发表于 3/5/2003 10:39:38 AM AVR 单片机

大家好,得到大家的大力支持,本小小菜现如今胆儿大了点,脸皮厚了点儿,又来献丑啦。今儿就不说没用的话了,免得鸡蛋横飞过来啦。



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 <avr/io.h>



                // 定义一个寄存器(Register)或端口(Port)的八个位

                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           sbrc    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           sbic    0x16, 7    ; 22

              58:    02 c0           rjmp    .+4          ; 0x5e

              5a:    c0 9a           sbi    0x18, 0    ; 24

              5c:    01 c0           rjmp    .+2          ; 0x60

              5e:    c0 98           cbi    0x18, 0    ; 24

    5. 菜论:鱼和熊掌。

      由于AVR可以对I/O脚进行sbic,sbi,cbi,这样的位操作,所以使用I/O脚操作时,移位宏可以产生高效的代码。

      例如,要实现上面的几个简单的指令,为了实现LED=1这样的类似C51的sbit的效果,我必须多付出(38-10=28Bytes)的代价。



    6......

        对于I/O脚,可以产生这样高效的代码,是因为有sbi和cbi这样的指令,那么对于一般的变量,又如何呢?................
收藏收藏17
回复 举报
论坛公益广告:使用360产品将会被封锁ID。周流氓枪毙1万次也无法弥补3721犯下的罪行。
hotpowe转载

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表