寄存器位操作在STM32中的应用

最近在学I2C通信,发现有两行代码看不懂(因为一直用的库函数,没用过位操作),代码为:

#define SDA_IN() {
            
     GPIO->CRL&=0x0FFFFFFF;GPIOB->CRL|=(u32)8<<28)} //上拉输入
#define SDA_OUT() {
            
     GPIO->CRL&=0x0FFFFFFF;GPIOB->CRL|=(u32)3<<28)} //推挽输出

首先说一下I2C使用的SDA引脚是PB7,时钟使能时有GPIOB->CRL和GPIOB->CRH两个。STM32中32的含义是寄存器是32位(不都是)的,对于CRL和CRH寄存器,都是32位寄存器。 如图,每四个位控制一个IO口,比如0 1 2 3位控制Px0(PA0、PB0…)那么32位控制的就是8个IO口。而每个IO口的四个位,前两位控制IO口模式(输入还是输出?如果是输出模式最大速度是多少?),后两位控制IO口的八种工作模式。 接下来看代码

#define SDA_IN() {
            
     GPIO->CRL&=0x0FFFFFFF;GPIOB->CRL|=(u32)8<<28)} //上拉输入

首先提一下16进制与2进制的转换关系:16进制下,每一位16进制对应4位二进制,比如0xFF 对应的二进制就是 1111 1111,0xAF 对应的就是 1010 1111,一一对应即可。

代码中GPIO->CRL&=0x0FFFFFFF的含义是:将所需要用到的PB7进行位清零,方便后续初始化。GPIOB->CRL|=(u32)8<<28)是对28:31位进行位操作,因为想要实现上拉输入,根据寄存器相关配置,应该让28:29位设置为00, 30:31位设置为10,那么28:31位的寄存器位就为1000,对应十进制为8,所以要将8(也就是1000)写入28:31位。在STM32中u32是unsigned int(无符号整型),(u32)8强制将8转换为整型,计算如下:

0000 0000 0000 0000 0000 0000 0000 1000 左移28位 ----------------------->得: 1000 0000 0000 0000 0000 0000 0000 0000

然后通过GPIOB->CRL|=(u32)8<<28)位或运算: 1000 0000 0000 0000 0000 0000 0000 0000 | 0000 (0-27位为初始量) =1000 (0-27位不变)

***位操作回顾:1|任何=1;0&任何=0

即通过位操作,实现了让PB7工作模式为上拉输入。 同理推挽输出:

`#define SDA_OUT() {
          
   GPIO->CRL&=0x0FFFFFFF;GPIOB->CRL|=(u32)3<<28)} //推挽输出`

反推:3代表二进制0011,对应50MHz输出工作模式通用推挽输出。

有任何写的错误的地方,还请希望多多指正!

经验分享 程序员 微信小程序 职场和发展