STM32F1模拟I2C通信中寄存器操作IO方向详解

#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

对于我们学的STM32都是习惯性的调用库函数,操作GPIO直接对结构体成员直接赋值即可。学到I2C通信时,看到以上代码中突如其来的寄存器操作,对于我这个新手小白来说是一脸懵逼状态,经过一个下午的学习,也算是搞懂了GPIO寄存器操作。分享一下个人学习总结,有错误的地方欢迎各路大佬指正。

1、所需基础知识回顾

  • 由参考手册可知,GPIO端口每个位可以由软件分别配置为:
    • 输入浮空
    • 输入上拉
    • 输入下拉
    • 模拟输入
    • 推挽式输出
    • 推挽式复用功能
    • 开漏复用功能
  • 每个GPIO端口由七个寄存器来控制,分别为:
    • 端口配置低寄存器(GPIOx_CRL)
    • 端口配置高寄存器(GPIOx_CRH)
    • 端口输入数据寄存器(GPIOx_IDR)
    • 端口输出数据寄存器(GPIOx_ODR)
    • 端口位设置/清除寄存器(GPIOx_BSRR)
    • 端口位清除数据寄存器(GPIOx_BRR)
    • 端口配置锁定寄存器(GPIOx_LCKR)

:其中GPIOx_CRL配置GPIOx_Pin0——GPIOx_Pin7引脚,GPIOx_CRH配置GPIOx_Pin8——GPIOx_Pin15引脚(这个必须要明白)

  • 逻辑运算
    • 左移运算
      • Value << num
      • num:指定要移位值Value移动的位数
      • 丢弃最高位,0补在最低位
      • 左移一位相当于乘以2的1次方,左移n位相当于乘以2的n次方
      • 例如:8<<28,即:8向左移动28位
    • 与运算:1 & A = A ;可得出1跟任意数进行”“运算不会改变其值
  • STM32寄存器描述
    • GPIOx_CRL寄存器,也就是低位寄存器。配置:Pin0—Pin7。图一如下:
      图一:GPIOx_CRL寄存器
    • GPIOx_CRH寄存器,也就是高位寄存器.配置:Pin8—Pin15。图二如下:
      图二:GPIOx_CRH寄存器
      也就是一个GPIOx端口分为GPIOx_CRL寄存器和GPIOx_CRH寄存器,其中MODE0[1:0]CNF7[1:0]一起表示Pin0的配置值,以下依此类推,MODE7[1:0]CNF7[1:0]一起表示Pin7的配置值。

2、代码详解

对于文章开头提到的两个宏定义分开两条解释,SDA_IN()如下:

#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
  • 其中GPIOB->CRL&=0X0FFFFFFF 等价于 (GPIOB->CRL) = (GPIOB->CRL) & 0X0FFFFFFF
    • 含义为:由于上述提到的CRL为低位寄存器,意思是把GPIOB端口的CRL寄存器的28、29、30、31位清0,即将PB7中CNF7[1:0]和MODE[1:0]四位都置零。(这里应该还是蛮好理解的)
  • 其中GPIOB->CRL|=(u32)8<<28等价于GPIOB->CRL = GPIOB->CRL | (u32)(8<<28)
    • 由于u32强制类型转换为32位,则8的二进制为:0000 0000 0000 0000 0000 0000 0000 1000
    • 将8左移28位得:1000 0000 0000 0000 0000 0000 0000 0000
    • 由左移之后的数据可知:将31、30、29、28位设置为1000。下面对上图中的CNF和MODE解析
      • 即将PB的CRL寄存器中29和28位设置为00,由图一可知,其中29位MODE7[1]的值=0;28位MODE7[0]的值为0;图三如下:
        在这里插入图片描述
      • 由上图得知:29:28位配置为00,由下表得知,MODE1和MODE0为00时为输入模式。图四如下:在这里插入图片描述
      • 接下来分析31:30位的值:10,由图一可知,其中31位CNF7[1]的值=1;30位CNF7[0]的值为0。图五如下:
        在这里插入图片描述
      • 由29:28位得知:为输入模式,且31:30位的值为10,对照图四亦可得出,即为上下拉输入模式

SDA_OUT()如下:

#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
  • 其中(GPIOB->CRL) &= 0X0FFFFFFF等价于 (GPIOB->CRL) = (GPIOB->CRL) & 0X0FFFFFFF
    • 其含义为:把PB端口的CRL寄存器的第28、29、30和31位清空,把GPIOB端口中的CNF7[1:0]和MODE7[1:0]置零
  • 其中GPIOB->CRL |= (u32)3<<28 等价于 GPIOB->CRL = GPIOB->CRL | (u32)(3<<12)
    • 3转换为2进制为:0000 0000 0000 0000 0000 0000 0000 0011
    • 将3左移28位得:0011 0000 0000 0000 0000 0000 0000 0000
      • 分析左移之后的数据为,将31、30、29、28位设置为00 11
        • PB的CRL寄存器中29和28位设置为11,其中29位MODE7[1]的值=1;28位MODE7[0]的值为1。即为输出模式,最大速度为50Mhz。
          在这里插入图片描述
        • PB的CRL寄存器中31和30位设置为00,其中31位CNF7[1]的值=0;30位CNF7[0]的值为0;由图五可知:通用推挽式输出模式。

3、通用GPIO方向设置代码

待写

评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫华雪悦.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值