请选择 进入手机版 | 继续访问电脑版

你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32F1模拟I2C通信中寄存器操作IO方向经验分享

[复制链接]
攻城狮Melo 发布时间:2023-5-22 20:00
  1. #define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}3 |) n! W, y1 R: ~3 m& F( x
  2. #define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
    - d) C) ?( V  ]: L
复制代码

6 w: n2 {5 v# d5 ~& s0 P0 @) t0 j" i5 {8 c- c
对于我们学的STM32都是习惯性的调用库函数,操作GPIO直接对结构体成员直接赋值即可。学到I2C通信时,看到以上代码中突如其来的寄存器操作,对于我这个新手小白来说是一脸懵逼状态,经过一个下午的学习,也算是搞懂了GPIO寄存器操作。分享一下个人学结,有错误的地方欢迎各路大佬指正。4 I% |& z8 m/ J. s1 f2 m( T
) E) h7 `2 p/ P9 y6 ]! X

0 f* W4 V' U: y8 b  t% V% P0 y1、所需基础知识回顾( Y0 {2 f% k! j1 Z/ X4 @+ s" X
由参考手册可知,GPIO端口每个位可以由软件分别配置为:
% z! F2 a7 y" n& `8 K9 w( p8 u; F输入浮空" Y) _; A% d/ v# n, x
输入上拉
. n8 L7 \/ d* _" c* _3 ]1 n# }输入下拉
( A/ d3 N5 R7 f5 \1 t$ {3 G# d模拟输入
1 @5 i. \+ S1 q) d, c, k推挽式输出
. W7 T/ @. r  D+ V推挽式复用功能- `2 x& P* H8 O! {4 }+ `% E
开漏复用功能
, L! a& W0 ^6 }+ R7 _* q每个GPIO端口由七个寄存器来控制,分别为:
) ^8 y/ e& n. \7 P端口配置低寄存器(GPIOx_CRL)& u+ ?. d9 D% S  l# a; J+ a2 A
端口配置高寄存器(GPIOx_CRH)
# U( O5 J1 ]" o! d, i端口输入数据寄存器(GPIOx_IDR)
7 g2 `# s! z# j5 D端口输出数据寄存器(GPIOx_ODR)4 b- b: `' ]2 J, g3 ~
端口位设置/清除寄存器(GPIOx_BSRR); e! G0 V  r( D7 `
端口位清除数据寄存器(GPIOx_BRR)9 b2 v- h2 \9 p7 o9 \8 N1 V
端口配置锁定寄存器(GPIOx_LCKR)
) F: j3 \  g  G- m4 q* r! X* [1 J注:其中GPIOx_CRL配置GPIOx_Pin0——GPIOx_Pin7引脚,GPIOx_CRH配置GPIOx_Pin8——GPIOx_Pin15引脚(这个必须要明白)
1 B' d! e' x6 Y- v5 E, H- G2 h1 e$ @: `& p, Z& _9 n& F

( W! S/ @0 e7 v# m3 x" h1 h- {逻辑运算" u6 @' l2 E* ]$ }0 ?8 t
左移运算
, W4 k& m# j; ]" JValue << num
$ \% e3 H; _2 `# jnum:指定要移位值Value移动的位数% x9 j. y) {% x  P& r) i- b+ t$ v
丢弃最高位,0补在最低位
. z' e6 u; t  m左移一位相当于乘以2的1次方,左移n位相当于乘以2的n次方
, i" @  c7 j* `2 l8 h例如:8<<28,即:8向左移动28位
$ v/ N4 E) X4 y/ y/ u& j3 d/ Z与运算:1 & A = A ;可得出1跟任意数进行”与“运算不会改变其值2 c1 m# E7 {+ X4 a* R: u
STM32寄存器描述

! |: r5 O# v. s  a: u) LGPIOx_CRL寄存器,也就是低位寄存器。配置:Pin0—Pin7。图一如下:+ ^& O  P* i3 z) M2 ^

# b* U+ \: _4 N) d, F6 I
8d0b99d571a841a0898e4f19d8fd4894.png 8 L9 ~7 _& S. M' {+ H

7 Q- n) r; p" AGPIOx_CRH寄存器,也就是高位寄存器.配置:Pin8—Pin15。图二如下:$ T7 }5 g0 a2 K6 r. Y4 |8 j0 ?
; E, q( f1 c  X: {9 J$ x
812f052b961547b4817ee64b743310f7.png
+ C! N0 n0 z9 _8 P6 B4 \8 N: e

* B0 t  `6 C6 i1 z" D( S也就是一个GPIOx端口分为GPIOx_CRL寄存器和GPIOx_CRH寄存器,其中MODE0[1:0]和CNF7[1:0]一起表示Pin0的配置值,以下依此类推,MODE7[1:0]和CNF7[1:0]一起表示Pin7的配置值。
5 K8 Z* t6 w: O6 l  f5 Q  I5 K' d2 z# W% p/ r! X! H0 u: h
2、代码详解' ^/ P2 e5 x- p! \4 T" u
对于文章开头提到的两个宏定义分开两条解释,SDA_IN()如下:1 ]* u# A9 W% N* \% C) G/ }

: y( L9 p  T8 w1 b( }' N#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}3 O; m- ]5 _) s8 c
* ]2 s4 k3 H- y  v- N
其中GPIOB->CRL&=0X0FFFFFFF 等价于 (GPIOB->CRL) = (GPIOB->CRL) & 0X0FFFFFFF: |9 G3 F, V- A( {' y
含义为:由于上述提到的CRL为低位寄存器,意思是把GPIOB端口的CRL寄存器的28、29、30、31位清0,即将PB7中CNF7[1:0]和MODE[1:0]四位都置零。(这里应该还是蛮好理解的)
1 q* L. l3 M2 Z
/ }( c& F, j% O
其中GPIOB->CRL|=(u32)8<<28等价于GPIOB->CRL = GPIOB->CRL | (u32)(8<<28)
) R8 g! |) b7 k& U由于u32强制类型转换为32位,则8的二进制为:0000 0000 0000 0000 0000 0000 0000 1000; l$ D+ e# x& y" G% E! ^( p9 C
将8左移28位得:1000 0000 0000 0000 0000 0000 0000 0000! R0 J6 |: ?+ U. W  g8 p* s4 u
由左移之后的数据可知:将31、30、29、28位设置为1000。下面对上图中的CNF和MODE解析- z5 c) H! [& P& _5 r( j. I  l; v

& H2 u' E* y; H* u( i
即将PB的CRL寄存器中29和28位设置为00,由图一可知,其中29位MODE7[1]的值=0;28位MODE7[0]的值为0;图三如下:
$ W% n8 H& [; p* k0 s- Z7 z+ N, j+ g0 s
0 {- b( z' M; H" g) l! }' m9 T
57bdb75cf48a484d836d20a6a31f7923.png
* `0 ?0 [% O  j+ C+ J  U% R. T- l- v
% k$ Q, g4 ^9 f' a8 P; `
由上图得知:29:28位配置为00,由下表得知,MODE1和MODE0为00时为输入模式。图四如下:% M$ {' K8 _" \& x; i, Q/ o% }/ v
5 c6 U1 t6 s  f$ c% D4 ~: m' j
- x# f0 u. Z( q
baf0dd61a6b348b6a47dfd6ecc295fc4.png % u6 z1 z+ D$ E( Y/ m$ O. ?2 {
( L$ ?) P- D+ t2 \; ~9 X
接下来分析31:30位的值:10,由图一可知,其中31位CNF7[1]的值=1;30位CNF7[0]的值为0。图五如下:
3 I; c# k9 S, A; c7 l# h- y: e, x/ E
56323f282da24b1dbd2150136a292c37.png & p( m0 `& z* C- Q/ k4 [8 c: f1 u3 P

  [% n; M5 L1 D9 `/ f; f. ~由29:28位得知:为输入模式,且31:30位的值为10,对照图四亦可得出,即为上下拉输入模式
: M2 e  g' q  Q  g4 ySDA_OUT()如下:, A6 {7 s6 Y- j* `

; P; w2 T5 H  J# z) A$ X#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
8 R3 ]- Z) k( s! ^2 @8 i
- D* M  j1 h' m5 N& i" x其中(GPIOB->CRL) &= 0X0FFFFFFF等价于 (GPIOB->CRL) = (GPIOB->CRL) & 0X0FFFFFFF
4 d6 N. Z* F  |3 }0 d* O其含义为:把PB端口的CRL寄存器的第28、29、30和31位清空,把GPIOB端口中的CNF7[1:0]和MODE7[1:0]置零
( H6 s3 V3 |* |! E' A1 v1 p$ A. G( U+ p$ u0 p8 \- R! T* X) f! {
其中GPIOB->CRL |= (u32)3<<28 等价于 GPIOB->CRL = GPIOB->CRL | (u32)(3<<12). x8 a. o' \0 U. Y* j
3转换为2进制为:0000 0000 0000 0000 0000 0000 0000 00116 r0 A( g$ l/ Y" ]4 N
将3左移28位得:0011 0000 0000 0000 0000 0000 0000 0000
6 U- ?' o$ B/ }! d分析左移之后的数据为,将31、30、29、28位设置为00 11
; x1 N- B& z4 Z6 n5 I- R  kPB的CRL寄存器中29和28位设置为11,其中29位MODE7[1]的值=1;28位MODE7[0]的值为1。即为输出模式,最大速度为50Mhz。
* D* R- }% E5 m& ~# x3 M! y. K3 a8 ^
bd0b6655f914488c8b083441edf707d0.png 3 l# K$ H0 y$ {5 P
2 I. k$ m/ i/ r6 M3 M
PB的CRL寄存器中31和30位设置为00,其中31位CNF7[1]的值=0;30位CNF7[0]的值为0;由图五可知:通用推挽式输出模式。
% |- w( H3 `' b3 B& c————————————————1 P; k2 m9 H. a8 s% O( a
版权声明:枫华雪悦v/ O7 `6 {" D' p; _, M% r# I3 ~3 U% S. Q3 Y
如有侵权请联系删除
; b" Z/ v& P4 X( u" k
- u8 K/ q/ z1 D  J9 n9 D' i" Z0 D- p5 r5 P3 b8 x2 Z

8 q2 X, D9 T/ J6 l
收藏 评论0 发布时间:2023-5-22 20:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版