IIC(Inter-Integrated Circuit)是一种常见的串行通信协议,广泛应用于各种嵌入式系统中,包括STM32单片机。在STM32中,IIC通信可以通过硬件IIC和软件IIC两种方式实现。本文将介绍IIC的基本原理,然后重点探讨STM32中硬件IIC和软件IIC的区别。8 D J$ P( f( H! @* X9 Q6 I4 h3 P0 N
! ~7 w w) B! q& @1 l \+ G( }( @" V6 ~
- h3 H' r' q/ }7 ^* D8 y( ?
4 d0 r& k; Z8 T9 l. T7 SIIC基本原理:IIC是由飞利浦(Philips)公司提出的一种串行通信协议,适用于在同一电缆上连接多个设备。它采用两根线进行通信,即SDA(数据线)和SCL(时钟线)。设备之间通过这两根线实现数据传输,其中SDA用于传输数据,SCL用于同步时钟。
2 \$ e% h4 f8 w* ^5 |& a
$ \% d; D0 d4 I2 [/ ~
. V% w' B+ [& p, U4 \0 S
" P- y) ? x! y; x一对IIC总线上面可以挂载多个设备并且多个设备之间有不同的地址,所以我们可以根据不同设备的地址来实现不同设备之间的通信。! C# y3 x! [4 j5 y/ J: M
) B5 ` {8 D7 u软件IIC" D' s: L5 O# L; c# j
在STM32中,软件IIC是一种通过程序控制GPIO口模拟实现IIC通信的方法。这种实现方式常用于一些资源有限的应用场景,或者在需要更灵活控制IIC通信时使用。' w- y/ c. x% V8 K* Y
$ J: B+ T: e5 L" m/ B5 q/ K" x
5 s# u0 w0 i$ d- \% J7 k1 d9 D
0 b; g0 a/ Y$ b. |1 H( t2 u总而言之,软件IIC是利用GPIO的翻转,一个IO模拟SCL线,一个IO模拟SDA线实现IIC通信协议的实现。& Y" `! Y5 x c1 g$ e$ V
" m* F, ^2 X7 X% E1 ]2 O/ g, x# Q
软件IIC不需要对IO有特殊的要求,只需要两个普通的GPIO即可实现,因此较为方便也方便移植,不同设备只需要重写IIC的基本通讯即可。/ K O, k* s, `4 E+ o
- // 定义IIC的GPIO口和引脚
/ O+ O) e- j4 t3 q2 v8 B6 Q - #define IIC_SCL_PIN GPIO_PIN_6' N0 n0 E% F& x( J: w
- #define IIC_SCL_PORT GPIOB4 }5 a9 q& I" ?7 W, _3 ?
! b6 p, I- K. w6 @# T- 1 R, d9 H2 y ~* J
- #define IIC_SDA_PIN GPIO_PIN_9' E; D& s g8 F
- #define IIC_SDA_PORT GPIOB2 k% k9 d/ s! V7 a7 q& H, w1 U# n/ {
, _8 C- \' ^2 X' }0 v: q- ! h+ w9 S7 l8 v- H% o
- // 定义读写控制位
8 k# ?; n: |# m f2 f& O8 {/ w* y# J - #define IIC_READ 1* g, i8 C9 _0 {: Q8 _ X7 d
- #define IIC_WRITE 01 k+ ~5 K3 l' h& j
- - O3 k$ I5 s/ ]+ Y3 M
- , U+ ]9 i7 t6 \" b: Q; Y5 j' ^
- // 定义函数
' i N( b8 t" @) h" M! w: k3 p& @+ u - void IIC_Start(void);6 C$ Q" P. g" R5 z. k5 C, u8 `3 f
- void IIC_Stop(void);5 P8 @0 m& p* c9 S
- void IIC_SendByte(uint8_t byte);
+ E/ T0 }5 T$ q' G7 p( G6 u - uint8_t IIC_ReadByte(uint8_t ack);
3 ?/ q2 ^3 ~0 c2 e+ {$ o
! z. u8 N9 b* _( d2 `# C
' e4 \" ?$ p- u- 8 v9 Z# j8 B5 P3 m: ?" D
& b! f0 X$ r8 R; C- // 启动IIC总线
& T7 g. f- [( D% h - void IIC_Start(void)$ [& [- I+ w9 Y
- {( k/ q3 b! h4 m9 \* E4 Z
- HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET);1 {1 j+ k0 U. [
- HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);
x( r5 h& q. j6 s; b. |) b7 ~0 N5 X - HAL_Delay(2); // 稍微延时,确保时序正确" m* o, V5 P4 B8 F
- HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET);
# _8 V- V9 l9 ~2 j& K& L - HAL_Delay(2);+ ~+ H2 R( Q) i& q# m: W, h
- HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);% U: V- B+ t" l. M1 N0 b7 _
- }* Y" u# U! x- W6 D) Q- Z- |" ^
- 7 F+ P6 x* k9 ?/ V* \2 X
- 2 g; r2 ^8 |8 k9 e$ @
- // 结束IIC总线
' _3 [7 @ d6 y. s! { - void IIC_Stop(void)
( i5 {( D) W- {; a. e, q' ^+ R - {
, |# ~8 T: ~+ R; ]3 J/ U - HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET);
: G" Z, \) P/ R4 _& Y& c - HAL_Delay(2);
: S* O3 V) J7 u6 ? - HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);
6 J+ b P* \; ?% X - HAL_Delay(2);
% F' d2 h- E) M! M f- E9 ~0 G - HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET);
" x C. n) V6 ?1 ~ - HAL_Delay(2);( o) c1 c( b2 R/ l% _8 A
- }
5 t- m; P$ ~. l; Y/ `1 t" K - ) h0 j$ U7 m. y6 o4 r
- # O3 L3 h6 Q8 B8 X' h
- // 发送一个字节- R+ M4 Z- k4 v# h3 ^
- void IIC_SendByte(uint8_t byte)9 x& b1 B. h+ N6 C9 { G
- {
0 h6 \+ K# ~6 W* { - for (int8_t i = 7; i >= 0; i--)
! m, ~8 f, q: e! E7 h$ F - {
. Q. F& |, W' a2 \" r - HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);
. Y& S9 x/ T( }$ h# Y' n" b; i - HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, (byte & (1 << i)) ? GPIO_PIN_SET : GPIO_PIN_RESET);- z: Q2 S- G' z
- HAL_Delay(1); // 稍微延时,确保时序正确( M2 @5 T9 I5 {% r0 l; a
- HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);
, m9 @! e: N3 D: a7 q: p9 A - HAL_Delay(1);
$ H* a# H) Y" Z0 _0 m - }
) }" K* N7 } {$ X - HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);4 G& V% V" R6 w7 ]
- }
, N' h, U6 n) ^4 I( ~; t( Z
2 T# ?* H: x. h) D4 s/ S9 e9 ~- d
9 R& c! s6 Z& i) S3 z c- // 读取一个字节
0 H8 ?& i# l! I) L9 X7 K - uint8_t IIC_ReadByte(uint8_t ack)
: x N: B4 w' ~# c( G; {! L - {" f$ V6 c; o& i5 o
- uint8_t byte = 0;1 ^+ U: o' _+ z( e1 X% s# D& Z
-
h1 i% `+ c4 g% [. N% V0 p - HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET);
3 b5 c' u ]4 Q4 z& l - for (int8_t i = 7; i >= 0; i--)7 L) k$ f- h1 M; l2 a8 V4 e9 {+ N
- {
0 B. p6 G9 y% c; \ - HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);& L/ \7 s4 N$ n, k/ N3 |1 [: G: y
- HAL_Delay(1); // 稍微延时,确保时序正确
8 q$ D: g9 u/ i7 ?1 c - HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);
3 A _$ x6 a# c) `, W% r - HAL_Delay(1);
+ u& \6 K8 ]; }- |1 a - byte |= (HAL_GPIO_ReadPin(IIC_SDA_PORT, IIC_SDA_PIN) << i);
9 q# d9 [% |2 H6 n% A( f - }
, Q9 v( H2 m) J -
2 W6 ^: ]0 y& T1 q$ ~$ r8 Z4 L6 c - if (ack)
R) G( z( P" P1 H8 P - HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET); // 发送应答; f+ ~6 _, g- P4 f
- else8 T) P& O6 n" Q) C. m/ O
- HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET); // 不发送应答0 u; k* z# G2 L1 f3 D: C+ q
- , i+ j& c- h0 e7 W% s
- HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);4 ?. y% Q) x0 _6 Q+ U1 l' A& s
- HAL_Delay(1); // 稍微延时,确保时序正确9 v" G0 m0 ]2 @: I. q8 L
- HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);
% U6 q2 {- q! j* p$ ^1 R0 l - HAL_Delay(1);
; D. z: E2 k& y% x - : N2 X9 ^" X, X; K8 a! T: Z
- return byte;- E& J7 X6 M$ g) R+ y
- }
复制代码 ( H- m2 }5 d: f' X4 I
例如IIC的启动信号为:SCL为高电平的时候,SDA从高电平转为低电平。% ~: h! [' Z; u4 _9 e
. }; a% h4 W# Q4 f) P$ PIIC的结束信号为:在SCL线是高电平时,SDA线从低到高的跳变。; p. j0 g2 V& J* q
( g& G7 Q) P) H2 ?因此使用这种方法可以模拟IIC时序完成通讯。
- z H6 E) X; j3 C0 h6 S3 p
6 X, z. z5 P/ _. E% I2 g但是这种方法的弊端也是非常明显的,需要占用CPU,其次这样子并不能确保I2C时序的正确性。所以无论是稳定性还是可移植性还是IIC的效率都欠妥。
4 O e7 A+ m1 [3 V% i6 W- J0 _# Z, x, m$ X' D6 x- f
STM32中的硬件IIC 3 P5 J: w8 e0 f/ w. f
STM32系列单片机提供了硬件IIC(Inter-Integrated Circuit)模块,用于支持IIC通信协议。硬件IIC通过专门的硬件模块实现了IIC协议的基本功能,包括起始信号、停止信号、时钟同步等,无需用户通过软件模拟实现。
, { d* U9 ~7 L5 x+ z/ v& g! R4 k) K% o, D) [7 E8 V+ m, \# N
STM32硬件IIC优势:
; @9 J9 ~, s7 {8 e6 z2 D0 Y* `) r1.高效性: 硬件IIC使用专用硬件模块处理通信,不需要CPU直接参与,提高了通信效率,降低了对CPU的负担。
L: B4 R/ m( j! Q4 C/ C3 P8 s, c2.时序精确控制: 硬件IIC模块能够精确控制时序,确保通信的稳定性,避免了由于软件执行时间不确定性而引起的时序问题。, d. M4 t& \3 c6 `+ F
3.多主机模式支持: 硬件IIC模块通常支持多主机模式,能够轻松处理多个设备同时访问总线的情况。
, m# X3 Y. G7 W o1 W! p' \4.易用性: 由于硬件IIC是芯片内置模块,使用起来相对简单,只需配置相应的寄存器和引脚即可。1 @* Q( w+ R+ z
5.占用资源少: 硬件IIC模块通常占用较少的资源,对于资源有限的嵌入式系统来说,是一种较为理想的选择。
/ R" e" B# h/ s; g. k0 x( C0 R9 S, ?6 m% O8 X6 n
/ S+ N5 i* o% N
0 P, T- @3 ^% p3 K( x在CubeMX中配置好硬件IIC即可利用HAL库函数进行IIC通讯。- static void MX_I2C1_Init(void)
( d. o8 i- I+ b1 a8 g) g - {
" U r3 G" ?7 y6 t" n- |' V - hi2c1.Instance = I2C1;8 P- @3 C9 w) x" @4 d2 A
- hi2c1.Init.ClockSpeed = 100000;8 j$ o5 d! b3 j1 X, R1 ^
- hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;* i, v* k. ~- \$ ^ |
- hi2c1.Init.OwnAddress1 = 0;
4 X9 _3 R, x; {2 d - hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; S# G* ?8 q% E0 ^5 u
- hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
' h& ~; J+ H2 X. H2 U, S - hi2c1.Init.OwnAddress2 = 0;
) T+ d9 ~! x/ }( n" e, L - hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
3 g# e6 w1 O% A1 z - hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
! \" `8 S6 h: D1 E/ h2 ?" D - HAL_I2C_Init(&hi2c1);
5 Y# O. H. ~3 } G$ O - }$ v% c4 l% l% S$ R7 j. s
2 O" l3 [3 p$ j/ }1 u* N
0 X& C0 W% l- m2 O/ t* ?- uint8_t deviceAddress = 0x50;//设备地址
6 j7 E% I3 V) F2 t5 _& I2 u - uint8_t registerAddress = 0x00;//寄存器地址
7 C+ _' G+ d& a+ s) z' P' }3 N6 W - HAL_I2C_Master_Transmit(&hi2c1, deviceAddress, ®isterAddress, 1, HAL_MAX_DELAY);
复制代码
4 k; R8 o% p4 a" `1 }0 X调用CubeMX的初始化函数,之后就可以使用例如HAL_I2C_Master_Transmit,HAL_I2C_Master_Receive等函数来实现IIC通讯。
! V& W' ?# _! P Y3 B* U0 j8 H$ e$ M$ ?3 ?% A5 V% e5 t6 | s0 q
" o% J( N- p1 A! U! N
STM32硬件IIC缺点:$ W5 L" x8 I% n. [7 h* q
1.资源占用: 相比软件IIC,硬件IIC模块可能会占用一定的硬件资源,因此在资源受限的系统中需要谨慎选择。
- S& |8 B6 A1 O" v- x5 e2.灵活性: 硬件IIC通常由芯片内部硬件模块实现,因此在一些特殊场景下可能缺乏一些灵活性,例如无法更改时序。
5 f( d! l7 y! }9 X3.部分限制: 不同型号的STM32芯片的硬件IIC模块可能存在一些差异,不同芯片的IO不一样,所以设计时需要谨慎检查。7 d5 s0 F7 Q: ^/ d5 o* @* j4 g
4 o% I/ q: D9 O; u
总体而言,STM32的硬件IIC是一种高效、稳定的IIC通信方式,特别适用于对性能要求较高的应用场景,同时在易用性和可靠性上有较大优势。在选择IIC通信方式时,可以根据具体需求权衡硬件IIC和软件IIC的优缺点。7 Y4 X; _$ Q" t; @5 o
- i! Q# t. h; E2 a; s/ Q. e- Q
' A G- m0 k6 V4 e# V
, E& e/ n/ c. j( P转载自:电路小白
/ p v% }2 B1 b如有侵权请联系删除: V' ^# Q o) y' M( V( o
3 w7 i& {( c! h* g
|