如何构建寄存器中特定二进制数

 

如何构建寄存器中特定二进制数

在stm32中寄存器按照位进行操作。寄存器的每一位都是不同的功能,如何给特定的一位写入值而不改变其他位?在stm32中这些都是通过位运算来完成的。

1. 给寄存器特定位置1,请零或者取反,之前我们知道了,我们只需要写出一个特定数来再和寄存器中原来的数进行位运算即可。
举个例子:假定寄存器中原来的值是0xaa,给他第2位置一。
我们原来的解决思路是:
第一步:看到寄存器中原来的值是0xaa,转换成二进制数是1010 1010
第二步:思考如何给特定位置1?(假装思考~~!)让被置1的那一位和1位与
第三步:构建出一个新的二进制数:0000 0100
第四步:计算

        1010 1010 //原来的数
        0000 0100 //新构建的数
        1010 1110 //结果是给原来的数第2位置1了

第五步:0000 0100转换成十六进制0x4,并写入寄存器。

上面的思路转换成代码

#include<stdio.h>
void main(void)
{
    unsigned int a=0xaa;    //原来的值
    unsigned int b=0x4;     //构建的数
    unsigned int c=0;
    c = a & b;          // c =0xae;二进制为 1010 1110
}

思考上面的代码就会发现一些弊端
(1)新构建的数是我们口算或者笔算或者借助计算器得到的,可能会出现差错,借助工具会产生依赖,一旦离开工具,我们就无能为力了。
(2)当别人看代码的时候发现,哎这里为什么b=0x4,就会回疑惑不明白为什么这么写。即使是自己三个月后再来看也未必可以看懂,当然排除注释写的好的情况。这时候怎么解决?(假装思考了一分钟~~!突然想到了)位移嘛。

那么问题来了:如何使用位移解决上面的问题?

再来回顾上面的新构建的数,b=0x4;二进制是0000 0100;在上面是直接写出了b=0x4,现在我们通过位移构建出这个数。很简单:b=0x1<<2;搞定了,是不是好简单,上面的代码可以改成

#include<stdio.h>
void main(void)
{
    unsigned int a=0xaa;        //原来的值
    unsigned int b=0x1<<2;      //使用位移构建的数
    unsigned int c=0;
    c = a & b;              // c =0xae;二进制为 1010 1110
}   

//这时候我们在来看b=0x1<<2;这行代码,这时候无论是谁都可以直接看出这是构建了一个bit2为1的,其他位为0的二进制数

下面再来写几个题练习一下吧

(1)获取一个一个bit3-bit7为1(其他位为0)的二进制数。
分析:
第一步:我们要获取一个bit3-bit7为1的二进制数,从bit3-bit7一共有5位。
第二步:先获取bit0-bit4为1的二进制数,其数为0x1f。
第三步:把bit0-bit4为1的二进制数左移到bit3-bit7为1的二进制数。0x1f<<0x1f8。

代码:

#include<stdio.h>
void main(voiud)
{
    unsigned int a=0x1f;    //二进制数为0001 1111  bit0-bit4为1
    unsigned int b=0;
    b = b<<3;               //二进制数为1111 1000  bit3-bit7为1
}

(2)更难一点的要求:获取一个bit3-bit7为1,bit23-bit25为1.其余位为0的数
分析:

第一步:bit3-bit7为1的二进制数上面已经得到,看bit23-bit25为1的数怎么获取。
第二步:根据上面获取bit3-bit7为1的二进制数的方法可以得到,0x7<<23即可得到。
第三步:
bit3-bit7为1的二进制数是0000_0000_0000_0000_0000_0000_1111_1000
bit23-bit25为1的二进制数0000_0011_1000_0000_0000_0000_0000_0000

思考:这两个分别得到特定位为特定值的二进制数如何合并?

第四步:使用位与进行合并得到bit3-bit7为1并且bit23-bit25为1的二进制数为
0000_0011_1000_0000_0000_0000_1111_1000
第五步:思考为什么这两个二进制数可以通过位与进行合并呢?
从两个二进制数可以看出来,两个数的不同位是不同的,可以进行位与。

代码:

#include<stdio.h>
void main(void)
{
    unsigned int a = 0x1f<<3;   //bit0-bit4为1左移得到bit3-bit3-bit7为1
    unsigned int b = 0x7<<23;   //从bit0-bit2为1左移得到bit23-bit25为1
    unsigned int c = a & b                          

                //通过位运算得到bit0-bit0-bit4为1并且bit23-bit25为1的二进制数
}

*2. 再结合位取反获取特定位为0的二进制数
(1)获取bit4-bit10为0,其余位全部为1的数,怎么做?
(2)利用上面的方法就可以:(0xf<<0)|(0x1fffff<<11)
但是问题是;连续为1的位数太多了,这个数字本身就很难构建,所以这种方法的有事就损失掉了。
(3)这种特定位为1(特别少),为1的位数却特别多,不适合用很多个连续1左移的方式来构建。适合做以加位取反的方式来构建。
(4)思路是:先让bit4-bit10为1其他位为0,然后按位取反。先设定bit4-bit10为1:(连续七位为1的十六进制数是:7f) 7f<<4 然后再取反 ~(7f<<4) 就可以得到题目所要求的数

3.总结:位与、位或结合特定二进制数即可完成寄存器位操作需求
(1)较少为为1 可以直接使用1左移
(2)较多位为0 可以先获取其位反数然后再位取反
(3)如果需要的数是好多个不连续的1组成的,可以分别构建,然后互相位或到一起去。因为分开的那几部分的1 肯定是不会冲叠的0

 

 

posted @ 2016-05-17 20:49  薛定谔的小灯泡  阅读(202)  评论(0编辑  收藏  举报