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

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

基于STM32的硬件和软件IIC区别经验分享

[复制链接]
攻城狮Melo 发布时间:2024-5-29 19:23
IIC(Inter-Integrated Circuit)是一种常见的串行通信协议,广泛应用于各种嵌入式系统中,包括STM32单片机。在STM32中,IIC通信可以通过硬件IIC和软件IIC两种方式实现。本文将介绍IIC的基本原理,然后重点探讨STM32中硬件IIC和软件IIC的区别。
5 [! ?  n# C6 ?/ i# I
+ ?3 e& j% I6 [$ A2 Q$ O 微信图片_20240529192252.png
- S) t; J# c3 Q/ Q8 x' `

1 P% v3 H# V% O* r% i: v8 Y; b( l- u6 {IIC基本原理:IIC是由飞利浦(Philips)公司提出的一种串行通信协议,适用于在同一电缆上连接多个设备。它采用两根线进行通信,即SDA(数据线)和SCL(时钟线)。设备之间通过这两根线实现数据传输,其中SDA用于传输数据,SCL用于同步时钟。
+ }% ~9 x8 X  E" L+ L" Y  |9 ^
7 h  o6 J' @0 u) k$ e8 i, ?3 N 微信图片_20240529192248.png
+ v( D7 e4 R8 P3 m7 g* L% T" X
5 s# P+ g$ S7 u* Q
一对IIC总线上面可以挂载多个设备并且多个设备之间有不同的地址,所以我们可以根据不同设备的地址来实现不同设备之间的通信。
$ F8 B. t" W3 I5 Q$ O% G
9 F$ F, c( w( f) t
软件IIC
9 ]7 N: R2 J8 I( c在STM32中,软件IIC是一种通过程序控制GPIO口模拟实现IIC通信的方法。这种实现方式常用于一些资源有限的应用场景,或者在需要更灵活控制IIC通信时使用。
9 n/ b, D& }: w7 Z3 p/ f8 Z" E& _8 b4 d( ?# M/ L
微信图片_20240529192245.png : `  S- j3 v& Z% ?7 V

: c& ~! i( f" s( O9 p. q总而言之,软件IIC是利用GPIO的翻转,一个IO模拟SCL线,一个IO模拟SDA线实现IIC通信协议的实现。9 V, x' B3 r# M! Z2 ]7 t
+ ^+ _* s4 ^+ S* {. U; @5 z
软件IIC不需要对IO有特殊的要求,只需要两个普通的GPIO即可实现,因此较为方便也方便移植,不同设备只需要重写IIC的基本通讯即可。9 h9 T: G1 W# z$ x- @
  1. // 定义IIC的GPIO口和引脚
    3 m5 @+ H1 a- Q: d# `
  2. #define IIC_SCL_PIN GPIO_PIN_6+ {; \" u1 k) q! }1 w. H) J8 p
  3. #define IIC_SCL_PORT GPIOB
    / L, x- B& d; ^! O/ T
  4. % E; F' Q  r0 i5 Z" F: A

  5. & ?* G0 t( @3 a6 p" q" }$ b/ l2 o$ Y
  6. #define IIC_SDA_PIN GPIO_PIN_9
    : Z: z: N( j/ `* t; j
  7. #define IIC_SDA_PORT GPIOB
    ' e8 a2 c* ^; u
  8.   v- T. ^9 ~( g* A

  9. * g& g0 y; g  I* @7 a) {* }
  10. // 定义读写控制位- Y! @& |! z7 a+ ^, [' O! p5 M
  11. #define IIC_READ  1
    , G3 Q2 w: @- _& k- C4 e  P5 E
  12. #define IIC_WRITE 0
    . X0 D) Z. H5 I5 X5 x; i" y

  13. 9 H+ V. y$ X4 e8 Q! a1 {* Q
  14. # u; A/ g* \4 g. ?% a( Z0 S! S  v- L
  15. // 定义函数
    4 b& F5 {& x) e- A' @* d& Z" \
  16. void IIC_Start(void);
    & Y7 y1 T# c2 C4 a6 [; f
  17. void IIC_Stop(void);+ F6 |5 u6 f3 t) _9 U& T
  18. void IIC_SendByte(uint8_t byte);
    ' X3 M& {# X- m/ \# |
  19. uint8_t IIC_ReadByte(uint8_t ack);( E. ~$ t8 U1 w" N0 v% h. H2 v% a

  20. $ [% A$ g' J% x/ s, \
  21. 1 J% S6 p% I. m' I% O. L
  22. 6 j) K. c  M: f2 W5 h8 o- i& g" f8 s  b
  23. 3 C) g6 i0 z. B9 b
  24. // 启动IIC总线
    ' r/ f; w. ?; w2 y7 F, u1 E1 \
  25. void IIC_Start(void)# ^2 t: ^' p5 X( ^5 {0 {
  26. {6 i! _: K+ _; b
  27.     HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET);
    0 \* Z# J( u1 W! v" D
  28.     HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);
    - V6 |2 _8 o: N, _* x. H- e
  29.     HAL_Delay(2);  // 稍微延时,确保时序正确
    : Z1 |& m( Z5 R7 D
  30.     HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET);
    / B3 t7 G% V, ^; s  j0 l9 O0 k; ^8 A
  31.     HAL_Delay(2);$ G$ E" f  W; |* a6 o$ o, G
  32.     HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);0 G  O' N0 S  k$ k
  33. }) D, x% D1 h  Z6 i8 `( n
  34. 0 `% G; E, X* o" |0 \4 a
  35. 1 {4 K4 J9 A/ c3 z
  36. // 结束IIC总线
    ( m, Q, ]2 j& Z* w3 {7 y( i- b" \
  37. void IIC_Stop(void)
    1 ~+ H$ [6 f2 g
  38. {! Q" c5 {! Y: H- U$ b- y
  39.     HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET);
    : ]4 T. D/ r' r  l& e% N
  40.     HAL_Delay(2);
    $ Z: r5 T* `2 [
  41.     HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);) ~# X) P# [6 r9 t6 S
  42.     HAL_Delay(2);
    ' M' F" [4 l' d: E* U; d; V/ |
  43.     HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET);
    ; X# ~% J: a% U0 c, e$ H
  44.     HAL_Delay(2);
    1 w5 O' c  [5 y# ^& o5 c
  45. }3 \3 k) J/ s& m6 v+ f
  46. * S' b( |' E  U/ g

  47. 0 T3 T- Y! Q, f" _/ P+ T7 f
  48. // 发送一个字节
    " I/ _8 d: w+ l0 g( n! S4 H
  49. void IIC_SendByte(uint8_t byte)
      q  [6 B: k7 W4 z2 g
  50. {
    1 Z& H5 O5 G6 |  b' N' [
  51.     for (int8_t i = 7; i >= 0; i--)
    2 C! T. W5 ]0 A4 K# K0 k- `
  52.     {
    & `/ C- n) ]6 @  s
  53.         HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);
    " b; Y% B- r3 U3 ^6 w  v/ n% ~
  54.         HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, (byte & (1 << i)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    : u. p5 U) i! H7 w% o, @5 K
  55.         HAL_Delay(1); // 稍微延时,确保时序正确
    ) ~, o) }! S7 D  {) [' V* {
  56.         HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);6 F6 D* ]$ i9 m# L. b4 @9 ^" h- o
  57.         HAL_Delay(1);8 ^! d- I0 h# E& Z: {0 n+ g+ O- c
  58.     }
    $ i2 K3 \1 |: u2 ?+ R6 [3 B5 \" I4 K2 g
  59.     HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);
    , R* k$ p$ A' R: N( J( Y8 X  J
  60. }
    * O) {" S: X1 u  ~& K

  61. , W0 H# ~9 Y: O) F

  62. . q  ?3 U3 T' P1 Z1 I
  63. // 读取一个字节) F1 I" E- c% |: A
  64. uint8_t IIC_ReadByte(uint8_t ack); K! F% @8 x( N8 u7 [/ w
  65. {
    # M8 h" @: {0 z# P# U
  66.     uint8_t byte = 0;  t: ?  ^6 z7 m8 f4 w5 i
  67.    
    & b) f9 Z9 p8 i6 D, B! j
  68.     HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET);
    * |/ F+ {' r: g8 N6 O
  69.     for (int8_t i = 7; i >= 0; i--)2 o8 S4 s2 |1 B7 z2 {; ~
  70.     {" c' ?$ l, z5 f8 e0 _
  71.         HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);
      ~' o7 P, A, V1 Q1 w4 U8 k
  72.         HAL_Delay(1); // 稍微延时,确保时序正确6 v  W# V; |0 i2 _' [1 {
  73.         HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);
    * k! ^! {7 p2 o/ V
  74.         HAL_Delay(1);7 R4 H, U# \2 e' I  O
  75.         byte |= (HAL_GPIO_ReadPin(IIC_SDA_PORT, IIC_SDA_PIN) << i);- E7 e  ^2 o6 ]" V$ T8 J. X
  76.     }
    - L) u  ?4 v7 a& J
  77.    
    5 q4 J$ ~6 a& j! L$ u% h
  78.     if (ack)# u7 ?# B. W$ L1 h" \$ F' O
  79.         HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET); // 发送应答
    3 J3 V  ?9 S: a7 D1 q0 Q
  80.     else
    % j, v/ u$ n( A3 d5 Z
  81.         HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET);   // 不发送应答
    ( d9 T6 B% i, K8 R7 D6 H+ X
  82.    : L7 T1 a9 k' {# @0 l% V
  83.     HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET);! o: \4 Q6 V, V2 T% Q1 x  t+ R
  84.     HAL_Delay(1); // 稍微延时,确保时序正确
    ! \( \/ S4 }  \
  85.     HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET);: S$ n# A) k- J9 R" e
  86.     HAL_Delay(1);
    ; X, j# H4 K( h+ U- k9 B
  87.    - B" i" J  l4 [3 ?8 E9 z
  88.     return byte;# h8 v, \8 x9 q1 e( k: [% z
  89. }
复制代码
! @/ {/ N. b) f3 h4 \8 m1 Z2 ]0 \( l
例如IIC的启动信号为:SCL为高电平的时候,SDA从高电平转为低电平。
7 R( S7 z, x4 A4 L* B9 D
3 c. k6 Y6 r* L' _' E! \; R$ A& h" ~
IIC的结束信号为:在SCL线是高电平时,SDA线从低到高的跳变。2 o% h  X6 ]" P# s

8 U& K$ `/ d- V4 f- G* ]
因此使用这种方法可以模拟IIC时序完成通讯。  L# R) l* v7 B3 g! o
# v( C* t7 G+ V
但是这种方法的弊端也是非常明显的,需要占用CPU,其次这样子并不能确保I2C时序的正确性。所以无论是稳定性还是可移植性还是IIC的效率都欠妥。
# f# Z+ m; v4 f+ N$ p. h, h
$ p8 }2 z7 u, n. I5 P2 W* f
STM32中的硬件IIC   
& _* R! K' q1 O; G4 g7 HSTM32系列单片机提供了硬件IIC(Inter-Integrated Circuit)模块,用于支持IIC通信协议。硬件IIC通过专门的硬件模块实现了IIC协议的基本功能,包括起始信号、停止信号、时钟同步等,无需用户通过软件模拟实现。8 G+ z& W1 X$ C+ D8 ^

! n0 C' [( t2 R& C( A3 V  VSTM32硬件IIC优势:9 v9 z( t& j+ B6 V+ H; ?
1.高效性: 硬件IIC使用专用硬件模块处理通信,不需要CPU直接参与,提高了通信效率,降低了对CPU的负担。
" ~* \! }! n) E8 g. ]% c0 ]  }5 |
2.时序精确控制: 硬件IIC模块能够精确控制时序,确保通信的稳定性,避免了由于软件执行时间不确定性而引起的时序问题。
# h' }+ H6 I4 ?# z  L. v% T3.多主机模式支持: 硬件IIC模块通常支持多主机模式,能够轻松处理多个设备同时访问总线的情况。* F0 x% D8 ~. r4 q) p" @
4.易用性: 由于硬件IIC是芯片内置模块,使用起来相对简单,只需配置相应的寄存器和引脚即可。
; a0 q+ w) N! O; p5.占用资源少: 硬件IIC模块通常占用较少的资源,对于资源有限的嵌入式系统来说,是一种较为理想的选择。
. X2 G" P3 B' X% m
/ i' u1 U# z* A8 D5 @
微信图片_20240529192242.png
* f$ I7 H  J* m" f9 L( b5 a) J5 x' p* D0 m6 P0 x4 W
在CubeMX中配置好硬件IIC即可利用HAL库函数进行IIC通讯。
  1. static void MX_I2C1_Init(void)
    % X' K: ^+ A  Q" s
  2. {
    & K4 m3 P; U% Y- |1 S2 z
  3.   hi2c1.Instance = I2C1;& j7 f3 D1 {8 @  f% ]# ]
  4.   hi2c1.Init.ClockSpeed = 100000;% R! {& [3 y4 ~9 M  h2 y0 r! {
  5.   hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;* f2 M! D4 e# B  S3 E4 _" l$ K
  6.   hi2c1.Init.OwnAddress1 = 0;% v# T4 ^5 w& V1 l5 t
  7.   hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;, j( j9 D0 Q0 _4 L7 n. i1 G
  8.   hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;5 n% J( J# w' @9 ^, Z. h
  9.   hi2c1.Init.OwnAddress2 = 0;1 [9 x; n: |5 Y0 G( n
  10.   hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    / h7 a, P1 h1 L$ ]
  11.   hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    " `& s* Z1 f8 G3 w) R' ~
  12.   HAL_I2C_Init(&hi2c1);  l# H" m) {0 L
  13. }9 I) c- o( b# c2 Q, J0 O

  14. 3 S9 E4 z! U7 D- W
  15. " a1 t  |9 ?2 g% a% G- Z: o; N' z
  16. uint8_t deviceAddress = 0x50;//设备地址
    : x7 r+ G& ?) Y* A
  17. uint8_t registerAddress = 0x00;//寄存器地址
    2 o$ Z$ |0 K# L4 N7 O
  18. HAL_I2C_Master_Transmit(&hi2c1, deviceAddress, &registerAddress, 1, HAL_MAX_DELAY);
复制代码
1 Q; U  s" V( a0 }6 ]$ A+ S' u
调用CubeMX的初始化函数,之后就可以使用例如HAL_I2C_Master_Transmit,HAL_I2C_Master_Receive等函数来实现IIC通讯。
: ]* N3 W3 z7 t' P# c: T/ Z5 k- ~7 T; ^; s) p
) A( T; G- Q3 j* L
STM32硬件IIC缺点:
# r8 l0 ^) r" E$ X4 Q" l1 D) Q- H) y1.资源占用: 相比软件IIC,硬件IIC模块可能会占用一定的硬件资源,因此在资源受限的系统中需要谨慎选择。3 ~; u- I8 Y3 `' R8 B# [2 N
2.灵活性: 硬件IIC通常由芯片内部硬件模块实现,因此在一些特殊场景下可能缺乏一些灵活性,例如无法更改时序。1 l( U; \& k6 v
3.部分限制: 不同型号的STM32芯片的硬件IIC模块可能存在一些差异,不同芯片的IO不一样,所以设计时需要谨慎检查。
. d& N, {- w+ `7 |: n8 [4 _  P
总体而言,STM32的硬件IIC是一种高效、稳定的IIC通信方式,特别适用于对性能要求较高的应用场景,同时在易用性和可靠性上有较大优势。在选择IIC通信方式时,可以根据具体需求权衡硬件IIC和软件IIC的优缺点。
- A; p1 I( N$ I
& z1 r( W/ @9 ]! E9 p, |' e3 S9 {- m, F) v4 ?" g

. N  ]) F1 v1 t5 ]转载自:电路小白: L' \* P$ O* r* z& \
如有侵权请联系删除
+ G. k! F. ^6 k% M$ W/ c0 w3 }0 o) L% m
收藏 评论0 发布时间:2024-5-29 19:23

举报

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