AVR的两种位操作的比较

    AVR的两种位操作的比较位域与C位操作的比较)

    AVR的两种位操作的比较(位域方式和移位宏方式)

    测试环境如下:
    硬件:AT90S2313
    软件:    WiinAVR gcc3.3   -Os级优化(最小size)。

    说明:
       由于AVR不支持位操作,所以必须通过软件来实现。下面对我所知道的两种方法进行一个简单的比较。
       1、位域方式。先定义一个位域,
               typedef struct _bit_struct
               {
                   unsigned char bit0 ;
                   unsigned char bit1 ;
                   unsigned char bit2 ;
                   unsigned char bit3 ;
                   unsigned char bit4 ;
                   unsigned char bit5 ;
                   unsigned char bit6 : ;
                   unsigned char bit7 ;
               }bit_field;
           再用一个宏    ,来指向要操作的位。
                #define LED             GET_BITFIELD(PORTB).bit0
                #define BUTTON      GET_BITFIELD(PINB).bit7
           使用时只需要直接赋值即可:如LED     ,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;如是其它编译器,请修改。
                   #i nclude <avr/io.h>

                   // 定义一个寄存器(Register)或端口(Port)的八个位
                   typedef struct _bit_struct
                   {
                       unsigned char bit0 ;
                       unsigned char bit1 ;
                       unsigned char bit2 ;
                       unsigned char bit3 ;
                       unsigned char bit4 ;
                       unsigned char bit5 ;
                       unsigned char bit7 ;
                       unsigned char bit6 ;
                   }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,    22
                 58:    02 c0           rjmp    .+4          0x5e
                 5a:    c0 9a           sbi    0x18,    24
                 5c:    01 c0           rjmp    .+2          0x60
                 5e:    c0 98           cbi    0x18,    24
       5. 结论:
         由于AVR可以对I/O脚进行sbic,sbi,cbi,这样的位操作,所以使用I/O脚操作时,移位宏可以产生高效的代码。
         例如,要实现上面的几个简单的指令,为了实现LED=1这样的类似C51的sbit的效果,我必须多付出(38-10=28Bytes)的代价。

       6......
           对于I/O脚,可以产生这样高效的代码,是因为有sbi和cbi这样的指令,那么对于一般的变量,又如何呢?................

    IAR 快捷键列表 嵌入式开发

    IAR 快捷键列表

    *Ctrl+Shift+V 列出剪切板中所有的字符串供选择粘贴 Ctrl+B 智能选择光标所在括弧内的区域,多次使用可选更大的区域 Ctrl+T 对选择区域进行自动缩进 Ctrl+K 注释掉选择区域 ...