C语言单片机位运算——看完马上懂(个人总结)

位运算:    0XF => 1111    0XF0 => 1111 0000    0X0F0F=0XF0F => 1111 0000 1111

&(与):    C语言中清0某些位的操作
    0x12345678    (通过用0来&操作 实现清零)
& 0xFFFF000F


------------------------
    0X12340008

|(或):    C语言中的置1操作                 
     0x12345678        0101    0110
|    0XFF00                1111    1111
------------------------
     0X1234FF78        1111    1111

^(异或):    C语言中取反操作    相同为0    不同为1      (记忆方法: 相异的两个数取或运算 则等于1   相同的两个数自然能想到是相同则清零)

      0x12345678              0110
^    0xF00                        1111
---------------------
      0X12345978             1001


实例使用:(  获取特定数为1  )
0xf8 ==>  1111_1000    把第3位到第7位 置1 可以用这种操作方法
               从哪一位开始置1 则移动多少位 这里是左移
3到7 总共有5位    1_1111 = 0x1f 
结果为:    0x1f << 3  = 1111_1000  = 0xf8

同理:
把第3到第7和第23到25位同时置1
((0x1f <<3) | (0x7<<23)) = 0x380_00f8

实例使用:(  获取特定数为0  )
方法: 按照上例 先把特定位置1 再按位取反
例:把bit4~bit10 取0 其余位为1
~(0x7f <<4) = 0xfffff80f

总结:
1.如果你想要的这个数比较少位为1,大部分位为0,则可以通过连续很多个1左移n位得到.
2.如果你想要的数是比较少位为0,大部分位为1,则可以通过先构建其位的相反数,然后再位取反来得到.
3.如果你想要的数中连续1(连续0) 的部分不止1个,那么可以通过多段分别构造,然后再彼此位或即可.这时候因为参与或运算的各个数为1的位是不重复的,所以这时候的位或其实相当于几个数的叠加.


位运算的实战演练
置1用 | , 清零用 & , 取反用 ^ , ~和<<  >> 用来构建特定的二进制数 

1.给定一个整型数a,设置a的bit3,并保证其他位不变.
    a = a | (1<<3)     或者    a |=  (1<<3)
2.给定一个整型数a,设置a的bit3~bit7,并保证其他位不变.
    a = a | (0b11111 <<3)   或者   a = a | (0x1f << 3)
3.给定一个整型数a,清除a的bit15,并保证其他位不变.
    a = a & (~(1 << 15))    或者   a &=  (~(a << 15))
4.给定一个整型数a,清除a的bit15~bit23,并保证其他位不变.
    a = a & (~(0b111111111 << 15))    或者   a &=  (~(0b111111111 << 15))
    a = a & (~(0x1ff << 15))    或者   a &=  (~(0x1ff << 15))
5.给定一个整型数a,取出a的bit3~bit8.
    第一步:    先将这个数bit3~bit8不变,其余位清零.
    第二步:    再将其右移3位得到结果.
    a = ffff_ffff;
    a &= (0x3f << 3);    //0x3f  => 11_1111 << 3 =  1_1111_1000
    a >> 3;        //结果为 0x1f8
6.用C语言给一个寄存器的bit7~bit17赋值937(其余位不受影响).
    关键点: 第一, 不能影响其他位;  第二, 你并不知道原来bit7~bit17中装的值.
    思路:    第一步, 先将bit7~bit17全部清零,不能影响其他位.
        第二步,再将937写入bit7~bit17中,不能影响其他位.       17-7+1 = 11    (11个1)
    a &=  ~(0x7FF << 7);    //bit7~bit17全部清零    0x7ff = 111_1111_1111 
    a |=  (937 << 7);        //将937写入bit7~bit17中

7.用C语言给一个寄存器的bit7~bit17中的值加17(其余位不受影响).
    第一步: 先读出原来bit7~bit17的值
        unsigned int tem;
        unsigned int a = 0xc30288f8;
        tem = a & (0x7ff << 7);
        tem >>= 7;
    第二步: 给这个值加17
        tem += 17;
    第三步:将a的bit7~bit17清零
        a &= ~(0x7ff << 7);
    第四步:将第二步算出来的值写入bit7~bit17中
        a |= tem;
8.用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17(其余位不受影响).
    解法1: 两次第6题解法
    a = 0xc30288f8
    //bit7~bit17赋值937
    a &= ~(0x7ff << 7);
    a |= 937 << 7;
    //bit21~bit25赋值17
    a &= ~(0x1f << 21);
    a |= 17 << 21;

    解法2: 合二为一
    a &= ~((0x7ff << 7) | (0x1f << 21));
    a |= ((937 << 7) | (17 << 21));    


用宏定义来完成为运算:
置位:置1    复位:清零

(用宏定义将32位数的第n位(右边起算,也就是bit0算第1位)置位)
1.直接用宏来置位 , 复位 (最右边为第一位)
#define    SET_BIT_N(x,n)    (x | (1U << (n-1)))          //这里U是无符号数的意思
                        //n-1是因为从bit0开始 这里的n是32位的要-1  0~31

(用宏定义将32位数的第n位(右边起算,也就是bit0算第1位)复位)
2.直接用宏来复位 , 复位 (最右边为第一位)
#define    CLEAR_BIT_N(x,n)    (x & ~(1U << (n-1)))          //这里U是无符号数的意思
                        //n-1是因为从bit0开始 这里的n是32位的要-1  0~31

3.(用宏定义将32位数的第n位到第m位(右边起算,也就是bit0算第1位,m为高位)置位)
分析:   假如n = 3,m=6, 题目就是把bit2到bit5置位
我们需要一个算式来得到(m-n+1) 个1
算法: 第一步:  先得到32位1:    ~0U    //对一个无符号0取反 得到32位1
         第二步: 将第一步得到的数右移32-(m-n+1)位 即可得到(m-n+1)个1   ==>(~0U) >> (32-(m-n+1))    
         (有个缺陷 就是只能在32位以内使用)    改进: == >        ~((~0U) << (m-n+1))<<(n-1)
         优势: 通用 64位(或更高位运算)照杀    
#define    SET_BIT_N_M(x,n,m)    (x | (((~0U) >> (32-(m-n+1))) << (n-1)))
改进:
#define    SET_BIT_N_M(x,n,m)    ~((~0U) << (m-n+1))<<(n-1)


4.截取变量的连续位. 变量0x88 ==> 10001000b   截取第2~第4位 , 则结果为 : 100b = 4

#define     GETBITS(x,n,m)    (x & (~(~(0U) << (m-n+1)))<<(n-1)) >> (n-1))

分析复杂宏思路:    一:先分析由几部分组成:    2部分
    x & (~(~(0U) << (m-n+1)))<<(n-1))          >>         (n-1)
        二:继续分析剩下的部分:    2部分
        x     &    (~(~(0U) << (m-n+1)))<<(n-1)) 
        三:通查C语言优先级表或自己写程序测试 优先顺序
            (~(~(0U) << (m-n+1)))    <<    (n-1)


int main(void){
    //第一题
    unsigned int a = 0xffffffff;
    unsigned int b = 0;
    b = SET_BIT_N(a,4);
    //第二题
    unsigned int a = 0xffffffff;
    unsigned int b = 0;
    b = CLEAR_BIT_N(a,4);
    
    //第三题
    unsigned    int a = 0x0;
    unsigned int b =0;
    b = SET_BIT_N_M(a,1,4);    //从第1位到第4位置1  即bit0~bit3 置1

    //第四题
    unsigned    int a = 0x88;
    unsigned int b =0;
    b = GETBITS(a,2,4);    //从第1位到第4位置1  即bit0~bit3 置1
}

  • 7
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值