寄存器操作,位与位或?你OUT啦~

2020-02-04 09:25发布

呵呵,和大家分享几个我用了很久的宏,
菜鸟表示刚刚才用STM32点了个灯,看着例程代码还是有点辛苦,主要是我比较笨吧,什么位与又什么位或的,
还好在学习51的时候写了一些宏,改了一下,代码读起来才感觉舒服一些,心情也好了一点
心情好的时候我就分享~

第一个:
#define BIT(x)        (0x01L<<(x))
这个宏是后面使用的基础,很好理解,其实这个宏是抄的,我一开始的定义是
#define BIT0 0x01L
#define BIT1 0X02l
...

第二个:
#define BitFromTo(h, l)        ((h > l)? ((BIT(h) - BIT(l) + BIT(h))): (BIT(l) - BIT(h) + BIT(l)) )
打个比方,BitFromTo(3, 0) 的结果就是 0x0f
BitFromTo(7, 4)的结果是0xf0

第三个:
#define AssignBit(type ,flag , which_bit, val)        ((((type)which_bit)&((type)val)) | ((flag)&(~((type)which_bit))))
一开始写这个宏的时候是没有type这个参数的,type是从通用性和安全上考虑的,不过又要多打几个字,不爽,如果C/C++能够支持typeof操作符就好了(自己分析,这里不详细写,在帖子的最后我会提供我代码里的全部注释)
比如说我要把变量u8 a 的 6号位到4号位的值设置为 101,我就可以
a = AssignBit(u8, a, BitFromTo(6, 4), BIT(6) | BIT(4));
这样多直观呀,
本来是要这样写的,不仅不好懂,还容易出错
a &= 0x8f;
a |= 0x50;

第四个
#define SetBit(type, flag, which_bit)                        ((flag) | ((type)which_bit))
这个好理解,如果要把变量a的1号位转置1的话就
a = SetBit(u8, a, BIT(1));

第五个
#define ClearBit(type, flag, which_bit)                        ((flag) & (~((type)which_bit)))
呵呵,这个是用来把一个变量的某些位清零的
比如把变量u8 a = 0xf4;的2号位清零
a = ClearBit(u8, a, BIT(2));
现在 a == 0xf0 了

最后说一下优缺点,
最大的优点就是可读性好,
最大的缺点就是打的字会比较多,每次要加个类型作为参数,不过在我的眼里,可读性更重要

有网友可能会提到效率问题,
这几个宏没有效率问题!如果参数which_bit和val 是常数表达式(我用到的大部分场合都是这样的),编译器是会自动优化的,不信你可以反汇编看看。如果都是变量,编译器不能优化,但是就算是手动写代码效率也是一样的。




最后附上全部代码以及说明:
/*********************************************************************************
*        AssignBit / AssignFlag
*说明:
*        这个宏用来得到一个变量的某个或某几个位被赋值后的值
*参数:
*        type        参数flag的类型
*        flag        要赋值的变量
*        which_bit       
*                        标明flag的哪几个位要被赋值
*        val                表示要赋给flag的那几个位的值
*注意:
*        1. 对于宏,其参数不要用++i;之类的表达式!也不要直接使用调用函数得到的返回值!
*        2. 如果type是寄存器,那么它必须是可读的
*示例:
*        u8 a = 0xf0;
*        AssignBit(u8, a, BIT4 | BIT0, BIT0);
*        执行完后,a == 0xe1;
*备注:
*        1. 效率上, 如果参数(除flag外)都是常量, 编译器会自动优化, 如果参数是变量, 就算手动写代码也是这个样子的
*        2. (which_bit) 括号是为了保证 AssignBit(flag, BIT0 | BIT1, 0)之类的用法不会出错
*********************************************************************************/
#define AssignBit(type ,flag , which_bit, val)                                       
                                                ((((type)which_bit)&((type)val)) | ((flag)&(~((type)which_bit))))               
#define AssignFlag                        AssignBit
#define AssignB                        AssignBit


/*********************************************************************************
//说明:
//        得到一个变量某几位位被置位后的值
//注意:
//        1. 如果flag是寄存器,必须是可读的
*********************************************************************************/
#define SetBit(type, flag, which_bit)                        ((flag) | ((type)which_bit))
#define SetB        SetBit



//说明:
//        清零位,flag变量中which_bit标明的位被清0
//注意:
//        1. flag必须是可以正常读写的
#define ClearBit(type, flag, which_bit)                        ((flag) & (~((type)which_bit)))
#define ClearB                ClearBit


//说明:
//        检查flag中的某一位是否被置位, 如果被置位, 则宏的值为非0(不一定是1), 如果没有被置位, 则宏的值为0
//注意:
//        1. flag必须是可以读的
#define CheckBit(type, flag, which_bit)                        ( (flag) & ((type)which_bit) )

#define BIT(x)        (0x01L<<(x))

//说明:
//        得到一个指定范围的BIT被置位的值
//        BitFromTo(3, 0)        会得到 0x0f
//备注:
//        1. 这个宏是为提高可读性才写的,对于常数参数是表达式的,编译器会自动优化。
#define BitFromTo(h, l)                                                        ((h > l)? ((BIT(h) - BIT(l) + BIT(h))): (BIT(l) - BIT(h) + BIT(l)) )
#define BitF2                BitFromTo
#define BitFT                BitFromTo
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
47条回答
hefq
1楼-- · 2020-02-06 17:01
 精彩回答 2  元偷偷看……
hefq
2楼-- · 2020-02-06 17:17
#define FOSC 6//MHz
#define CYCL 10L//MS
#define DTH0 (long)(65536-CYCL*FOSC*1000/12)/256
#define DTL0 (long)(65536-CYCL*FOSC*1000/12)%256+11
#define mask(i) (
(i>> 0&1)<<0|
(i>> 4&1)<<1|
(i>> 8&1)<<2|
(i>>12&1)<<3|
(i>>16&1)<<4|
(i>>20&1)<<5|
(i>>24&1)<<6|
(i>>28&1)<<7)
#define mask1(i) (1<<(i))
#define mask0(i) (~(1<<(i)))
#define set(i,j) ((i)|=mask1(j))
#define rst(i,j) ((i)&=mask0(j))
#define get(i,j) ((i)&mask1(j))
#define h8(i) (char)(i)
#define l8(i) (char)((i)>>8)
#define uc unsigned char
#define us unsigned short
#define ul unsigned long
#define sc signed char
#define ss signed short
#define sl signed long
hefq
3楼-- · 2020-02-06 19:01
//顺控程序
uc data PRES;
void rstps(){rst(*(uc*)((PRES/8)+WS),PRES%8);}
#define stls(i) PRES=i;if(get(*(uc*)(i/8+WS),i%8))
#define sets(i) do{set(*(uc*)(i/8+WS),i%8);rstps();}while(0)
//void sets(uc i){set(*(uc*)(i/8+WS),i%8);rst(*(uc*)((PRES/8)+WS),PRES%8);}
void stl_zone()
{
        stls(8)
        {
                Y0=0;Y1=0;Y2=1;Y4=0;Y5=1;//马达0,刹车0,松锁1,启动灯0,停止灯1
                D0=D1;
                if(X3||X4)Y3=0;//关报警
                if(XF3&&!X5){D0=0;sets(9);}
        }
        stls(9)
        {
                Y0=1;Y1=0;Y2=0;Y4=1;Y5=0;//马达1,刹车0,松锁0,启动灯1,停止灯0
                if(MP8013)D0++;
                if(X4||D0>=D1){sets(10);}
        }
        stls(10)
        {
                Y0=0;Y1=1;Y4=0;D0=D2;//马达0,刹车1,启动灯0,倒计时赋初值
                if(1){sets(11);}
        }
        stls(11)
        {
                if(MP8013)D0--;
                if(D0<=0){sets(12);}
                else if(XF3){D0=0;sets(9);}
        }
        stls(12)
        {
                Y3=1;//时间到报警
                if(1){sets(8);}
        }
        stls(0)//显示计时
        {
                HB1=HB2=HB3=0;
                if(X0||X3)disp(D1);//如果设置1,显示设定值
                else disp(D0);
//                if(X0)outt(0,30);       
                if(X1||X2){sets(1);}//如果设置1长3秒,跳到S1
        }
        stls(1)//设置
        {
                if(XP1)D1++;
                if(XP2)D1--;
                if(X1||X2)
                {
                        outt(2,3);
                        outt(3,10);
                        if(TG2&&MP8012)
                        {
                                if(TG3){if(X1)D1+=10;else D1-=10;}
                                else{if(X1)D1++;else D1--;}
                        }
                }
                else outt(1,5);
                HB1=HB2=HB3=0;
                if(TG1)HB1=HB2=HB3=1;
                if(D1>999)D1=999;
                if(D1<0)D1=0;
                disp(D1);
                if(!X0&&!X1&&!X2)outt(4,100);
                if(X0)outt(5,30);
                if(TG5){sets(2);}//如果SET键按下3秒,保存
                else if(TG4){sets(0);}//如果10秒内没有键按下跳到S0,不保存               
        }
        stls(2)//保存
        {
                iap(3,0x0000,0);
                iap(2,0x0000,DH1);
                iap(2,0x0001,DL1);
                if(1){sets(0);}
        }
}
armku
4楼-- · 2020-02-06 22:12
mark 寄存器操作,位与位或?你OUT啦~ 宏操作
Pony279
5楼-- · 2020-02-07 02:25
回复【14楼】hefq 何访贤
回复【12楼】pony279 霍斯
-----------------------------------------------------------------------
这样也行,但如果前导是0就变成8进制了,所以我干脆换成16进制了

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


编译通过测试通过啦~

#define mask(x)        (                                       
(((( 0x##x )                        ) & 1 )<<0)        |       
(((( 0x##x )        >>4                ) & 1 )<<1)        |       
(((( 0x##x )        >>8                ) & 1 )<<2)        |       
(((( 0x##x )        >>12                ) & 1 )<<3)        |       
(((( 0x##x )        >>16                ) & 1 )<<4)        |       
(((( 0x##x )        >>20                ) & 1 )<<5)        |       
(((( 0x##x )        >>24                ) & 1 )<<6)        |       
(((( 0x##x )        >>28                ) & 1 )<<7)               
)
xizi
6楼-- · 2020-02-07 06:34
 精彩回答 2  元偷偷看……

一周热门 更多>