zoukankan      html  css  js  c++  java
  • 位操作

    以下红线内容部分为网友测试过程:

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

    AVR的两种位操作的比较(位域方式和移位宏方式) (来自:http://blog.sina.com.cn/s/blog_4b0e58e8010006pe.html

    测试环境如下:
    硬件: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这样的指令,那么对于一般的变量,又如何呢

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

    以下是我对网友的宏作了修改:

    Port 可以是变量或是内存。

       1: #define RevBit(port, bitn)           (port ^=  (1<<(bitn)))                                 //翻转port口bitn位
       2: #define SetBit(port, bitn)           (port |=  (1<<(bitn)))                                 //port口bitn位 = 1
       3: #define ClrBit(port, bitn)           (port &= ~(1<<(bitn)))                                 //port口bitn位 = 0
       4: #define GetBit(port, bitn)           (port &   (1<<(bitn)))                                 //读port口bitn位值
       5: #define OutBit(port, bitn, value)    ((value) ? (SetBit(port, bitn)) : (ClrBit(port, bitn)))//port口bitn位 = value
  • 相关阅读:
    Ant 中作用代理
    linux通用自动清理日志脚本
    linux shell 脚本攻略 下
    我在写shell自动部署脚本碰到的问题
    linux shell 脚本攻略(上)
    Java Object.wait() jvm的bug
    shell 脚本 更新或者添加host ,并且增加hostname映射到hosts (修改)
    记一次子域名IP搜集reconngkali
    ie6下面试用png使用滤镜需知
    canvas 使用 图片 切片的时候 在chrome 下 要注意的 一点
  • 原文地址:https://www.cnblogs.com/worldsing/p/3200793.html
Copyright © 2011-2022 走看看