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

【经验分享】STM32开发中使用C语言实现IIC驱动

[复制链接]
STMCU小助手 发布时间:2022-6-7 09:41
简述
    IIC(Inter-Integrated Circuit)其实是IICBus简称,它是一种串行通信总线,使用多主从架构,在STM32开发中经常见到。
    使用面向对象的编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备时只需要实例化一个IIC对象即可,本文是基于STM32和HAL库做进一步封装的。
    底层驱动方法不重要,封装的思想很重要。在完成对IIC驱动的封装之后借助继承特性实现AT24C64存储器的驱动开发,仍使用面向对象的思想封装AT24C64驱动。
; v9 t- C& b8 s6 H
IIC驱动面向对象封装
    iic.h头文件主要是类模板的定义,具体如下:
  1. //定义IIC类: q7 R5 L2 a$ C6 o5 ~
  2. typedef struct IIC_Type& k7 s% e. c- I2 J
  3. {# y0 J4 n% W0 F) ?5 u# g
  4. //属性
    $ R2 N/ J9 ~6 J% u  K5 s8 F
  5.    GPIO_TypeDef  *GPIOx_SCL;  //GPIO_SCL所属的GPIO组(如:GPIOA)
    9 a, D( U- r$ k0 ]$ l& M
  6.    GPIO_TypeDef  *GPIOx_SDA;  //GPIO_SDA所属的GPIO组(如:GPIOA)
    4 U8 N8 H7 e9 _8 K
  7. uint32_t GPIO_SCL;     //GPIO_SCL的IO引脚(如:GPIO_PIN_0)
    1 F+ c% \" F  l
  8. uint32_t GPIO_SDA;     //GPIO_SDA的IO引脚(如:GPIO_PIN_0)# f% b. k; Q: y5 X# x. A
  9. //操作
    & _, v+ Y/ Q- B7 ~/ [* y
  10. void (*IIC_Init)(const struct IIC_Type*);        //IIC_Init
    ' P) s6 b8 ]9 X* A2 C3 T& D% a7 P4 M' j
  11. void (*IIC_Start)(const struct IIC_Type*);       //IIC_Start
    7 E4 L6 m$ Q: @8 U0 t5 T" m0 l& i/ S
  12. void (*IIC_Stop)(const struct IIC_Type*);        //IIC_Stop3 e/ u) d& m# G/ f8 B0 r8 t
  13. uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*);    //IIC_Wait_ack,返回wait失败或是成功9 L0 r$ K; T6 D/ `/ j& |1 }+ M
  14. void (*IIC_Ack)(const struct IIC_Type*);       //IIC_Ack,IIC发送ACK信号; i% |" w) [% H6 N& {& q. @
  15. void (*IIC_NAck)(const struct IIC_Type*);       //IIC_NAck,IIC发送NACK信号
    " o* D  [3 R  k2 Q$ y
  16. void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t);       //IIC_Send_Byte,入口参数为要发送的字节
    + F' L0 n  o) |* n+ b2 H
  17. uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t);     //IIC_Send_Byte,入口参数为是否要发送ACK信号
    ' v& l' t: t9 O
  18. void (*delay_us)(uint32_t);              //us延时( ?, A5 v! i) R' r( n4 @
  19. }IIC_TypeDef;
复制代码
) m7 J9 r# G# l3 h. s1 X7 r* ~
6 M% T( S4 v/ ]$ h( f4 N+ c
iic.c源文件主要是类模板具体操作函数的实现,具体如下:
& c; r# e7 z: m$ s
  1. //设置SDA为输入模式' S2 Y  a( W1 T
  2. static void SDA_IN(const struct IIC_Type* IIC_Type_t)9 n# G- u* s6 M) k
  3. {/ f% z+ U& ^) E1 z0 [; E
  4.   uint8_t io_num = 0;  //定义io Num号& e, W  O0 I% X$ |" F
  5. switch(IIC_Type_t->GPIO_SDA)
    6 @0 b0 B3 @3 ]. G% l4 ^1 ~9 ~6 D* v
  6.   {
    / M/ r! u  I4 E
  7. case GPIO_PIN_0:( K6 k4 ]- O+ V3 W) J9 I: F
  8.     io_num = 0;
    / X& h$ q8 H6 n$ o( y+ [/ r* N
  9. break;
    1 t" k& j0 G9 Z  D3 j+ c
  10. case GPIO_PIN_1:, M+ T/ s% o( i- K  N: v8 W' U: g
  11.     io_num = 1;9 O9 ^4 g. i% |# ?
  12. break; * @$ V7 Q2 R& R6 n8 |7 B6 D* _; ~
  13. case GPIO_PIN_2:
    : I. @6 g* o. Q4 H; ~5 R& K
  14.     io_num = 2;
    3 ?& c; G: L% I6 _0 }
  15. break; 0 J* ?8 r- F; x1 {
  16. case GPIO_PIN_3:
    * Z' G" G! w' y& ?' V
  17.     io_num = 3;
    0 d; @0 k1 `% `7 ^5 R* d" @
  18. break;6 ?2 M& K; K( e6 U9 d  |# k1 M
  19. case GPIO_PIN_4:) w' h: }$ z2 i& x7 K. z/ C) s
  20.     io_num = 4;9 o/ y6 G6 @, z; v5 H* g+ ^9 \
  21. break;
    4 J; j$ G  H$ ~  w( B7 B
  22. case GPIO_PIN_5:# t* p5 h7 z! K, c- W7 ~
  23.     io_num = 5;
    0 ^8 C" ~4 V9 L& @; B* }: J" t
  24. break;
    # d* |3 O9 s. I+ {' o; ~
  25. case GPIO_PIN_6:
    % z2 M; O, c" N6 D1 m9 A
  26.     io_num = 6;  T- |% s3 @! ~: V2 R6 \4 @
  27. break; ; T' v9 e3 I' }, u7 C/ ]2 H
  28. case GPIO_PIN_7:0 `  j# n* U. O0 s8 [. i
  29.     io_num = 7;2 r5 V0 h" q. w# d: y
  30. break;, [% T* r7 x" r
  31. case GPIO_PIN_8:
    ( t6 B4 ]$ N4 j0 U* n& Y
  32.     io_num = 8;
    6 e% u  f# h& d5 _  L$ E+ R+ o
  33. break;
    % S+ Z' g& p/ ]( i% }( n3 @  q
  34. case GPIO_PIN_9:* l" N- \1 `" s9 Q3 k4 P
  35.     io_num = 9;1 z& s- y% F6 b5 C* K' S; v7 L
  36. break;
    1 Z; J9 j+ m1 D$ k, D3 N9 V
  37. case GPIO_PIN_10:
    ) u! X1 X0 }: H
  38.     io_num = 10;
    : i* {0 l, G' r5 d, Z2 v1 ?
  39. break;4 t$ R& r8 L% J) w. }+ [  z: L" M
  40. case GPIO_PIN_11:
    $ T1 ~8 x$ a. y' v: ]* {
  41.     io_num = 11;) C7 P1 c3 M* d# e8 g- Q' s  e/ m
  42. break;
    / F8 p( [4 Q( H% W  m- z. S- L
  43. case GPIO_PIN_12:
    / |# e2 a" o. L- s# y9 w
  44.     io_num = 12;
    + Y+ q' P- i% U3 s
  45. break;4 O' J7 k) L5 F; V" ~: h
  46. case GPIO_PIN_13:
      P. X3 A4 ]6 u& u# }. R+ ^
  47.     io_num = 13;
    $ w% h# G% F# {+ F, L
  48. break;  S" ]; J, G& |$ }  @% |& J0 B3 W" z
  49. case GPIO_PIN_14:
    : {: S. Y4 x$ Y- V( r
  50.     io_num = 14;
    3 r0 H0 U- I& m8 X2 F' G
  51. break;
    * ]7 B5 A: _5 j8 r
  52. case GPIO_PIN_15:
    / l3 u2 e4 N% Z+ c, e: K; C0 ^
  53.     io_num = 15;
    $ M; H# X( Q! h  |
  54. break;
    # M3 M6 G; o. f4 p# a5 B
  55.   }% q) T5 G# \% v7 |& D* x- o
  56.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零
    ( x( d0 _* [: |8 z* Z( y
  57.   IIC_Type_t->GPIOx_SDA->MODER|=0<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输入模式$ T8 t0 X5 P6 J/ ^4 A
  58. }
    ) f; f* @6 [" `, H

  59. 4 ^6 L( l) i* E8 F
  60. //设置SDA为输出模式7 n& @+ \. ~0 t% {
  61. static void SDA_OUT(const struct IIC_Type* IIC_Type_t)
    ' w& b4 ~. V4 H& {7 k8 `2 e( K
  62. {
    ' h3 f8 \9 K( ]( S0 g* [( [# ]
  63.   uint8_t io_num = 0;  //定义io Num号
    ) ]) B# J$ [( x! ^3 a
  64. switch(IIC_Type_t->GPIO_SDA)
    3 q) ~: ]. b5 G
  65.   {
    5 e7 e8 h8 A! e8 J- O' ?
  66. case GPIO_PIN_0:' O* J) J+ j2 t' s
  67.     io_num = 0;2 }# [. x, ^3 E
  68. break;4 J6 D2 Y) t7 ]  u4 P
  69. case GPIO_PIN_1:
    8 U+ C$ Z% O1 ^3 n) q) v
  70.     io_num = 1;
    # ^6 P; K4 g" E* b) o2 A
  71. break; ) [. j* [* c1 T, s9 |/ A. p$ o
  72. case GPIO_PIN_2:  a* h& `7 f4 e, m9 _. N0 H
  73.     io_num = 2;" y! g5 o1 x4 r! K* B
  74. break; ( q3 N: Q  V) j2 V+ t$ E0 m
  75. case GPIO_PIN_3:
    ' I  C. Q) m# I/ }( k, h
  76.     io_num = 3;
    : ?1 {& P% O. T; l% p( _" Y
  77. break;
    6 c& Q6 b) j0 P* m( k5 h* ~
  78. case GPIO_PIN_4:
    . i% J3 G: Z/ s1 i: ^/ f
  79.     io_num = 4;- I  c3 e6 A4 |1 Y  O
  80. break; * w! c, F- d8 l9 p
  81. case GPIO_PIN_5:8 _& z& h$ _. U3 a0 z; Y) ]/ b
  82.     io_num = 5;
    ( t" {% J) ^' l: ]8 ~" u
  83. break;
    9 k: [3 N5 Z: }( G' W( j; q# o
  84. case GPIO_PIN_6:) k' @6 n) E% t) m5 y
  85.     io_num = 6;
    ' ]: L9 n- p$ ?/ ~
  86. break; ( g% ^, Q- h! `8 S) o3 E5 |! B2 P1 z
  87. case GPIO_PIN_7:, u' Q; V. Q8 n& z, [# U7 c7 z3 ]
  88.     io_num = 7;
      m/ S" _) W' k- s8 Q5 A
  89. break;1 |, ^5 B7 w: G( R$ O
  90. case GPIO_PIN_8:
    * W4 B" N7 R9 L# G9 _
  91.     io_num = 8;
    7 ~5 j1 h  H( ^% i3 r2 B: |
  92. break; " D/ ~$ U; t! a, N+ d+ j  Z
  93. case GPIO_PIN_9:
      T* E9 m9 L$ r: N
  94.     io_num = 9;
    8 e3 K  F7 ?0 |6 S* k
  95. break;+ B* B# Q6 ?  u$ K
  96. case GPIO_PIN_10:9 q9 `, G3 P  |8 }+ E
  97.     io_num = 10;8 d2 }7 p' F- P' Y- G2 ]& E
  98. break;8 s2 [( V$ ^0 E' N0 N
  99. case GPIO_PIN_11:
    $ }6 r  q( V/ @
  100.     io_num = 11;
    5 Y. q, `/ `& z( g
  101. break;
    * y% M5 i, |  r( w
  102. case GPIO_PIN_12:
    % L, y1 E' o/ s, ^
  103.     io_num = 12;: s$ S, \" Y7 a8 _2 T
  104. break;
    * T, x  P: X1 K" s' d7 V
  105. case GPIO_PIN_13:
    * T$ U* v2 Y) f# N
  106.     io_num = 13;7 y- C6 ]0 R/ _( Z
  107. break;* [5 s' r' ~  w, @: [( @& y: E: ]- R
  108. case GPIO_PIN_14:, g$ h8 V5 E  J( X
  109.     io_num = 14;
    5 Q; r# L, m! `7 v4 P/ ^+ o
  110. break;
    ! Z. F7 [( `# ~7 p2 z! I0 L5 w4 g. q
  111. case GPIO_PIN_15:; u' P0 U# p+ [0 A  _
  112.     io_num = 15;
    1 S4 l8 L) @- K3 I7 x7 j
  113. break;
    ' Q4 Z! V% z3 {3 H4 A+ u3 o
  114.   }1 h3 a0 p2 h# v6 U0 e
  115.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零
    7 k2 j" u1 }& V/ `5 d. ^, e
  116.   IIC_Type_t->GPIOx_SDA->MODER|=1<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输出模式
    % Z3 R7 w% y: a1 w! ]: R
  117. }
    6 M- B. _4 D# D4 L
  118. //设置SCL电平
    ) h1 I: F( i- ?; }' I3 n1 }
  119. static void IIC_SCL(const struct IIC_Type* IIC_Type_t,int n)9 M; y  D+ z# x. e
  120. {
    ) {5 A; K: E3 o* p0 S
  121. if(n == 1)
    + M" l/ J" e0 r  G, l
  122.   {
    # h0 ]- D4 f, Q5 B5 }2 L# x1 @
  123.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_SET);     //设置SCL为高电平7 `) d4 `8 u0 s/ x& [, _6 M
  124.   }# M0 l; q7 u, {8 N- _) G5 z
  125. else{
    ) T. e8 o. @- H2 o2 ^- _" I
  126.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET);     //设置SCL为低电平
    ' c- T# l+ ]4 ?& L8 R5 k- U4 C
  127.   }) a) C5 ~0 y' M2 O
  128. }
    4 H* F# v" R0 |7 p. E3 C& H
  129. //设置SDA电平. K0 W7 N! K- o3 [
  130. static void IIC_SDA(const struct IIC_Type* IIC_Type_t,int n)& [" y$ t6 ]8 ]7 m6 ~: l
  131. {+ R" j: V& |# c' P- b7 ?
  132. if(n == 1)7 b7 C, p* @9 f3 \/ ?3 b5 X3 q, I% ~
  133.   {
    7 [" \) V: ^4 U- z
  134.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_SET);     //设置SDA为高电平; D% ?/ {& N% g3 K- O1 n& `
  135.   }
      z# V  T; G2 |8 [( P: _
  136. else{$ Y5 a3 o% {* z9 u* a2 @
  137.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET);     //设置SDA为低电平% [9 p/ x! B% m0 L
  138.   }) }2 ~" i) O3 `3 c$ ~
  139. }7 `$ F$ l/ @* m4 y* l3 a
  140. //读取SDA电平. \4 |& L( ]# x4 i/ \, x$ a
  141. static uint8_t READ_SDA(const struct IIC_Type* IIC_Type_t)
    * V, }& {9 b  m, b  {& M; J
  142. {
    ; b! Q% ^; u* `2 n( M
  143. return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA);  //读取SDA电平
    ' L. x1 C+ Q) f; u! }% c
  144. }
    ' e% P8 z% R: e
  145. //IIC初始化2 z8 h  m) I, [( N0 N* D
  146. static void IIC_Init_t(const struct IIC_Type* IIC_Type_t)
    ; Q4 \8 A/ F, \: e  T# H1 E# p
  147. {1 r4 t' D* o6 _2 |7 b8 x$ N3 x
  148.       GPIO_InitTypeDef GPIO_Initure;% L/ d6 h9 B1 {/ |+ ^

  149. / m& u1 Q# [$ t& [# q& C
  150. //根据GPIO组初始化GPIO时钟
    5 I5 ~( c& m' p+ c/ S+ H( J* m
  151. if(IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)' f9 _1 g! E- z9 j
  152.    {
    : s; |# X, d& i; f9 T6 L
  153.      __HAL_RCC_GPIOA_CLK_ENABLE();   //使能GPIOA时钟8 w" t  {& \2 l- ?5 L6 }
  154.    }
    * `3 v3 n# z4 }
  155. if(IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)
    % R# a2 q/ X+ z+ x
  156.    {
    : K& y7 A! M! e
  157.      __HAL_RCC_GPIOB_CLK_ENABLE();   //使能GPIOB时钟4 ?7 o8 ~4 A6 a: u
  158.    }- t' x0 e9 C1 q* ]# l$ F' M# J) ?
  159. if(IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC), U7 X+ d3 M- D  Y5 V9 {
  160.    {
    3 W5 N0 c9 w% f5 ^1 G
  161.      __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟/ [# P9 e& a  D" b
  162.    }$ v0 D: D. M4 M5 W
  163. if(IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)
    0 d8 p' g/ X) v, R
  164.    {
    4 z4 W7 [) W0 ^. I; R6 s9 m' ]
  165.      __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD时钟
    ' l6 [: }; Y( {2 U# L, m/ G7 [
  166.    }
    0 a6 f; ~# t" t& F
  167. if(IIC_Type_t->GPIOx_SCL == GPIOE || IIC_Type_t->GPIOx_SDA == GPIOE)
    ( }& l, {: |- a. i8 T$ V3 W
  168.    {4 ^# k- d+ q+ H# V8 T2 }
  169.      __HAL_RCC_GPIOE_CLK_ENABLE();   //使能GPIOE时钟
      \. f8 [& ?9 n, u2 V! {
  170.    }
    - ^; n3 `( X3 Q  D
  171. if(IIC_Type_t->GPIOx_SCL == GPIOH || IIC_Type_t->GPIOx_SDA == GPIOH)
    6 ]. ^  a) A. ~8 ^9 U8 u5 g
  172.    {
    $ R  u/ l4 k6 u5 X2 C+ Z
  173.      __HAL_RCC_GPIOH_CLK_ENABLE();   //使能GPIOH时钟0 {) H8 u" C4 Q# Z7 `# D
  174.    }     
    + P: U# v) E7 Q. y2 R2 Q4 f

  175. ( Q  p+ I/ B6 Z' ?5 b7 ?
  176. //GPIO_SCL初始化设置' a8 F! d: A! O( X; [
  177.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SCL;
    : [, W6 b  u( @% f5 k
  178.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出* p; \; z7 m2 y, R1 [
  179.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉9 s( P" O$ v: ]" b- b! e
  180.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速
    4 t( q2 @( b8 {: K* Q
  181.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL,&GPIO_Initure);+ v7 }4 ?) S; L8 E2 d) N
  182. //GPIO_SDA初始化设置
    8 E- X) w" \! x7 z
  183.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SDA;
    # F; `& p' T( s8 |. j7 B
  184.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    ! y) ~! \3 L6 D
  185.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉/ y: l4 M3 W0 F" y% Y7 q+ o& |
  186.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速$ j; U; S, Y$ g) T
  187.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA,&GPIO_Initure);
    6 X! j9 a+ r$ [( w. s
  188. ' ^9 E5 K8 Q0 Y+ u! w, ?
  189. //SCL与SDA的初始化均为高电平
    ( m3 h3 I8 q0 p+ \0 Y2 n9 ?
  190.       IIC_SCL(IIC_Type_t,1);. S( K( e! i0 D' m. ?! k  I
  191.        IIC_SDA(IIC_Type_t,1);
    5 o4 j4 X# `3 i/ Q! m3 ?# Q6 q
  192. }+ G/ t/ {4 C8 g' \& A+ J
  193. //IIC Start3 s5 a( u) D/ k: p  Z) H
  194. static void IIC_Start_t(const struct IIC_Type* IIC_Type_t)
    - m  U3 Q/ T( a. o* Y! x) T
  195. {
    1 g0 C, [( @; \( G7 d! G0 \" }: o
  196.   SDA_OUT(IIC_Type_t);      //sda线输出
    + W( |1 W( c' b
  197.   IIC_SDA(IIC_Type_t,1);      
    * }5 T( f& x6 A0 u3 ~
  198.   IIC_SCL(IIC_Type_t,1);& w* h* {+ I$ ?1 a" h5 D# p
  199.   IIC_Type_t->delay_us(4);
    ) K4 K. r7 }7 @, [  v' [$ L
  200.    IIC_SDA(IIC_Type_t,0);  //START:when CLK is high,DATA change form high to low
    1 F* p. Z5 A, O4 j
  201.   IIC_Type_t->delay_us(4);0 \2 r( j  n- [5 u- o- b8 t4 h: c
  202.   IIC_SCL(IIC_Type_t,0);  //钳住I2C总线,准备发送或接收数据
    8 M& M9 y4 K; p' L+ o/ \5 g4 B% ^  g
  203. }) q; ^& C% `: ^: X* j, E' ]
  204. //IIC Stop
    $ v/ j7 b2 Z. K+ s& X0 c
  205. static void IIC_Stop_t(const struct IIC_Type* IIC_Type_t)! X. Y$ F- H$ |5 B& P6 y$ _
  206. {6 {1 }. x% k' P: p/ ]
  207.   SDA_OUT(IIC_Type_t); //sda线输出
    2 r% d, ^' ^0 T" v* P
  208.   IIC_SCL(IIC_Type_t,0);# y# }/ k: y. K7 \! r5 x: L
  209.   IIC_SDA(IIC_Type_t,0); //STOP:when CLK is high DATA change form low to high
    ) c2 P* p$ U8 z; {3 x: _
  210.    IIC_Type_t->delay_us(4);2 B% A( [$ g' b  L' e( a
  211.   IIC_SCL(IIC_Type_t,1); ) Q$ x# h3 E( R% U- s
  212.   IIC_SDA(IIC_Type_t,1); //发送I2C总线结束信号9 y+ {. G9 g7 h) }# r2 ?+ U8 g
  213.   IIC_Type_t->delay_us(4); 5 c) Q4 N8 o& k
  214. }
    # g) g7 w9 G; v8 n( o% ?( J
  215. //IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
    7 e( S" b7 C! a
  216. static uint8_t IIC_Wait_Ack_t(const struct IIC_Type* IIC_Type_t)   //IIC_Wait_ack,返回wait失败或是成功
    ; ]3 R: N( X8 e" Q/ h* k
  217. {
    0 n4 p! ]$ t8 e, }8 ?
  218.   uint8_t ucErrTime = 0;" z: ~; ]: N' n% F4 R4 X
  219.   SDA_IN(IIC_Type_t);      //SDA设置为输入  2 \: A# I0 Q2 u, z
  220.   IIC_SDA(IIC_Type_t,1);IIC_Type_t->delay_us(1);   8 W/ _* h1 I2 g  x8 j
  221.   IIC_SCL(IIC_Type_t,1);IIC_Type_t->delay_us(1);
    & R9 \2 p; Q' v7 c6 |9 b
  222. while(READ_SDA(IIC_Type_t))- ]7 _( k: k! y5 L0 `1 D! E
  223.   {
    9 W; }! a+ a  \9 p. ^1 ^% _! Y
  224.     ucErrTime++;( ^1 ~0 B8 `) u/ r: N
  225. if(ucErrTime>250)
    / {- L0 J% T! k" a8 M
  226.     {" H8 C9 t* q2 \0 p: C
  227.       IIC_Type_t->IIC_Stop(IIC_Type_t);
    ' `9 ?- m; m' Q/ z6 a- L5 O
  228. return HAL_ERROR;% Y& ?; B. m" N  ]( z
  229.     }% a- S7 s* \/ l, E0 g
  230.   }
    2 ^0 @# U8 v, s
  231.   IIC_SCL(IIC_Type_t,0);//时钟输出0     
    + n. T* ]0 N# y
  232. return HAL_OK;  0 ~% T( W( c7 l4 e
  233. }
    9 k6 `$ \% I5 w( B
  234. //产生ACK应答
    3 u8 ^& k' t1 v5 g- ~: m$ D
  235. static void IIC_Ack_t(const struct IIC_Type* IIC_Type_t)      
    : }/ W9 M- d% g8 r7 r' W/ e" G+ I
  236. {
    $ A# B: l3 M' _6 J3 y9 i0 p4 w6 q' n
  237.   IIC_SCL(IIC_Type_t,0);5 A$ a. `  E& F5 k4 W2 U( y, p0 P5 v& l
  238.   SDA_OUT(IIC_Type_t);
    ) K; s! e2 n7 W
  239.   IIC_SDA(IIC_Type_t,0);
    3 @2 c* S- d6 @6 [
  240.   IIC_Type_t->delay_us(2);  & i' b7 d+ [4 G  @+ p% X
  241.   IIC_SCL(IIC_Type_t,1);
    $ D1 ^3 ~) f5 z1 C; H5 C
  242.   IIC_Type_t->delay_us(2);  
    , f! E3 d! I. N" I
  243.   IIC_SCL(IIC_Type_t,0);
    2 H# J  S3 \. g! X! Z, O2 V
  244. }* t) J1 K; m. K3 w8 l# R* y. e; ^
  245. //产生NACK应答$ I0 C- m! Y' C$ L
  246. static void IIC_NAck_t(const struct IIC_Type* IIC_Type_t)      + n( {; H- U( s7 Q) a( v
  247. {
    % j/ a  W2 {8 c$ J% j8 i) v
  248.   IIC_SCL(IIC_Type_t,0);! Z  [( a: i* u& X5 k# W
  249.   SDA_OUT(IIC_Type_t);
    6 o& j, P* W/ V6 a' x0 ]  A* r+ y5 f
  250.   IIC_SDA(IIC_Type_t,1);
      |6 f$ T) e6 `2 n* U4 h
  251.   IIC_Type_t->delay_us(2);  ) Y2 C' q: h8 y" h
  252.   IIC_SCL(IIC_Type_t,1);
    - q  Y; y8 _7 @8 a
  253.   IIC_Type_t->delay_us(2);  4 X; ^7 z9 @, A. ~0 d
  254.   IIC_SCL(IIC_Type_t,0);
    6 U% ~9 t( E1 l4 P3 `8 x; }% l
  255. }- Q# U* e1 y0 }5 l* x# L% M2 P3 t4 W
  256. //IIC_Send_Byte,入口参数为要发送的字节4 b. u1 F& n. y0 g) ]
  257. static void IIC_Send_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t txd)     
    / B( M3 D- Q, \9 B3 e
  258. {3 j3 ]* ~: o; j' S5 x: \$ d: b; n; Z
  259.      uint8_t t = 0;   # o4 [6 u* m5 P, [  Y
  260.      SDA_OUT(IIC_Type_t);      
    4 {% ^! ^2 @9 f$ p" B
  261.      IIC_SCL(IIC_Type_t,0);//拉低时钟开始数据传输
    & d- M& m' T' U. T5 u: h8 [
  262. for(t=0;t<8;t++)
    ( n- Z( F' V+ E, ]; ?& n1 F5 b- x
  263.      {              " \9 ~; f# l! \' {0 X8 o' @
  264.           IIC_SDA(IIC_Type_t,(txd&0x80)>>7);( s3 V: Q# y  V% i) |9 W/ U
  265.           txd <<= 1;    / R. J* g+ J$ }) C7 p: C
  266.        IIC_Type_t->delay_us(2);     //对TEA5767这三个延时都是必须的7 o9 y8 K8 G. B9 |: E+ k
  267.        IIC_SCL(IIC_Type_t,1);1 l$ L- D7 M6 H# j! \  F
  268.        IIC_Type_t->delay_us(2);  4 n! O6 y& P  A
  269.        IIC_SCL(IIC_Type_t,0);
    " C5 f  e: j9 C  f4 h
  270.        IIC_Type_t->delay_us(2);  
      d; \5 t" r( g6 P, Y+ q5 z% j9 e$ v
  271.      }  
    7 C4 N! d5 ]. z6 b' L( f
  272. }* R. @# T- J7 e1 P
  273. //IIC_Send_Byte,入口参数为是否要发送ACK信号( F1 \7 J0 g5 o
  274. static uint8_t IIC_Read_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t ack)     ' F* U$ y  R2 E8 d" }
  275. {
    7 u3 k2 h. a* l' Z7 u
  276.    uint8_t i,receive = 0;
    ! }) K. W% R$ _8 U- O
  277.    SDA_IN(IIC_Type_t);//SDA设置为输入
    . I% b8 P7 c1 `  ?
  278. for(i=0;i<8;i++ )
    * {- q7 X0 n5 m; G) E' C" l! ?
  279.    {6 w6 K. c, Z& C. v0 g% y3 B
  280.       IIC_SCL(IIC_Type_t,0);
    , d' e# L+ i+ K: E2 J
  281.       IIC_Type_t->delay_us(2);8 `9 `, I+ T! i. Q: Y  D- g7 _
  282.       IIC_SCL(IIC_Type_t,1);
    $ e2 @( }; e# Y! h  l3 Q; w: c  D
  283.       receive<<=1;
    + W4 f8 i% w1 ]- }. a% v8 \7 W
  284. if(READ_SDA(IIC_Type_t))receive++;   - k9 a- \/ ~0 x/ i, x! I
  285.       IIC_Type_t->delay_us(1);2 G7 F+ k1 m) H) Z% ^
  286.    }      
    # |5 ?8 \" Z0 ]' M5 [; |- y5 _
  287. if (!ack)" i0 Z' d0 m5 x# R6 }1 c9 K
  288.          IIC_Type_t->IIC_NAck(IIC_Type_t);//发送nACK! c9 P2 J- G( ^: l" A7 a
  289. else
    " b5 Q- n: r- z* {- b1 }6 r
  290.          IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK   
    " [" ]+ G# ~- K( ?1 E* @: b7 L8 O
  291. return receive;! T5 j; X) L3 E7 F
  292. }. Q2 \+ I4 x# ~+ G* f+ t+ K$ F
  293. //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用
    5 w" Z- X+ o$ w( l
  294. IIC_TypeDef IIC1 = {- D) C# \  J8 \/ {4 Z
  295.   .GPIOx_SCL = GPIOA,   //GPIO组为GPIOA
    2 O4 \. R; @+ f7 u9 X/ y  D" O
  296.   .GPIOx_SDA = GPIOA,   //GPIO组为GPIOA
    & S5 @' L. R8 u! o
  297.   .GPIO_SCL = GPIO_PIN_5,   //GPIO为PIN5. Y7 L, M7 u; l$ Q. B3 v
  298.   .GPIO_SDA = GPIO_PIN_6,  //GPIO为PIN6
    4 t8 F. l7 G+ H
  299.   .IIC_Init = IIC_Init_t,+ w! B% }5 y: w2 p1 S: c
  300.   .IIC_Start = IIC_Start_t,
    ! f. H( n# ~5 r. Q2 Z+ p
  301.   .IIC_Stop = IIC_Stop_t,1 Y% e! v/ F- \+ X
  302.   .IIC_Wait_Ack = IIC_Wait_Ack_t,
    3 J6 [6 J; C6 w6 @
  303.   .IIC_Ack = IIC_Ack_t,% [0 C$ S0 y) U
  304.   .IIC_NAck = IIC_NAck_t,/ y& b& @# j( D* v2 F6 c
  305.   .IIC_Send_Byte = IIC_Send_Byte_t,, n4 |, t; Z' B' \: F; S1 ~
  306.   .IIC_Read_Byte = IIC_Read_Byte_t,
    4 H: v& V8 m8 U6 B  p
  307.   .delay_us = delay_us     //需自己外部实现delay_us函数$ ~* J( Z/ t0 \
  308. };
复制代码
5 ^. a: j* \. a* J& `( H: c# `
    上述就是IIC驱动的封装,由于没有应用场景暂不测试其实用性,待下面ATC64的驱动缝缝扎黄写完之后一起测试使用。
ATC64XX驱动封装实现
    at24cxx.h头文件主要是类模板的定义,具体如下:
  1. // 以下是共定义个具体容量存储器的容量
    " X4 m4 q% F$ q( ]8 b
  2. #define AT24C01  127
    + A9 Z/ o  P: v3 y8 G7 j% I
  3. #define AT24C02  2558 F) \( u; c% A1 r; Q
  4. #define AT24C04  5119 P' v7 o; Z9 M. s3 w- N! \
  5. #define AT24C08  10234 ^$ [0 c4 I6 m
  6. #define AT24C16  2047
    & ?* \+ j& C, [5 B1 g" B, ?9 m
  7. #define AT24C32  4095
    ( |. K4 B; x7 C
  8. #define AT24C64   8191         //8KBytes
    6 X: N! {& f3 G+ p/ E9 h0 z: B3 R
  9. #define AT24C128 16383
    4 n6 C  _" c% R2 N% j
  10. #define AT24C256 32767  
    + A! L/ f* r( Q4 e0 ~
  11. 9 h4 N  c9 [" Y! B; ?7 {) C
  12. //定义AT24CXX类& ?5 H2 [/ K$ F* _/ k" B0 U
  13. typedef struct AT24CXX_Type
    ( D8 }* t/ g9 O7 {! L, m
  14. {* w" Y) S5 C$ M( |# F
  15. //属性; n. P' ?+ y4 J2 B, F% T; \
  16.   u32 EEP_TYPE;           //存储器类型(存储器容量). v6 e3 I# V2 |- l
  17. //操作
    5 r7 A9 J4 A  C; h7 S
  18.   IIC_TypeDef IIC;       //IIC驱动
    6 u' \5 n, c; o$ Q
  19. uint8_t (*AT24CXX_ReadOneByte)(const struct AT24CXX_Type*,uint16_t);  //指定地址读取一个字节
    5 \/ C* H/ X  i. ^$ P; H  c
  20. void (*AT24CXX_WriteOneByte)(const struct AT24CXX_Type*,uint16_t,uint8_t); //指定地址写入一个字节. ?* K0 ]0 N" ]  T5 s
  21. void (*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t); //指定地址开始写入指定长度的数据
    , }/ E& h* H, @9 _/ D7 |/ O+ D
  22. uint32_t (*AT24CXX_ReadLenByte)(uint16_t,uint8_t);   //指定地址开始读取指定长度数据
    - J3 S1 I0 O" r- M6 I& S
  23. void (*AT24CXX_Write)(uint16_t,uint8_t *,uint16_t);  //指定地址开始写入指定长度的数据* p* j' F3 ?4 p* Y
  24. void (*AT24CXX_Read)(uint16_t,uint8_t *,uint16_t);   //指定地址开始写入指定长度的数据
    $ n2 {7 [0 D0 x  O8 E7 O& o
  25. void (*AT24CXX_Init)(const struct AT24CXX_Type*); //初始化IIC; g3 r2 @( j" k& C' e
  26. uint8_t (*AT24CXX_Check)(const struct AT24CXX_Type*);   //检查器件- D7 h( z  \+ {0 M' T# k( |
  27. }AT24CXX_TypeDef;8 `/ {. J/ v. y
  28.   U1 G% r7 Z2 K: g/ y' r
  29. extern AT24CXX_TypeDef AT24C_64;     //外部声明实例化AT24CXX对象
复制代码

5 V, s! r0 u  ^) n& B7 ~8 F
    at24cxx.c源文件主要是类模板具体操作函数的实现,具体如下:
  1. //在AT24CXX指定地址读出一个数据
    4 ]5 M# e! j) I) w5 J
  2. //ReadAddr:开始读数的地址  9 E2 e+ t* m  B+ }3 m
  3. //返回值  :读到的数据
    " M* ?& X  j1 s: i7 Q; z4 N
  4. static uint8_t AT24CXX_ReadOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t ReadAddr)
    ; z8 h4 n+ X4 V% g9 t
  5. {      9 N. v+ ]" T4 i
  6.   uint8_t temp=0;                          
    % T  Y$ j" P0 ]6 X$ Q
  7.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);  3 Q( w- ?# z+ x8 }+ j7 n
  8. //根据AT的型号发送不同的地址; A) t4 j0 i1 @3 N1 F5 J% G
  9. if(AT24CXX_Type_t->EEP_TYPE > AT24C16)
    , j- ^# J7 S( V% j9 B
  10.   {
    4 K1 m: Q+ a4 v& e* i# C
  11.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令" S+ B/ p4 y) u1 U: A: i1 m& T3 k
  12.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);+ E0 z: f+ L. L* x
  13.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//发送高地址     $ L; u# |% Q" S/ D
  14.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据     - t" ?; X6 Q5 L+ x
  15.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC); # V) e2 ~" r* Z3 T/ x- o
  16.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256);   //发送低地址; e5 m( r! G- g3 |: X1 D3 W
  17.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     - j' h& f* l/ p
  18.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);        ' x& q" V; l1 w0 l
  19.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA1);           //进入接收模式      
    $ Z: |% N9 p0 l/ h4 G  Y! @- [
  20.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);  : s/ j4 }4 K1 [& X% m) H
  21.   temp=AT24CXX_Type_t->IIC.IIC_Read_Byte(&AT24CXX_Type_t->IIC,0);     8 Z8 `  Q  m& |4 V5 b
  22.   AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件     
    . c9 e& H( u5 I3 Y4 \$ }
  23. return temp;
    5 G8 X2 G6 U: I+ i- g. r
  24. }
    3 {/ |7 j$ _5 c: B
  25. //在AT24CXX指定地址写入一个数据  Z. m) P1 N2 n% f$ i5 S2 j
  26. //WriteAddr  :写入数据的目的地址   
    2 Q; c7 P- |% o/ c; i
  27. //DataToWrite:要写入的数据" x! c# h' |- g& B( s+ E6 ]( z  l1 d
  28. static void AT24CXX_WriteOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t WriteAddr,uint8_t DataToWrite)
    : E1 V0 L, I2 Y, S
  29. {                                
    & d6 d- z" U! o' |+ ]8 ^
  30.    AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);   
    , n8 Q/ Y3 W: X6 l
  31. if(AT24CXX_Type_t->EEP_TYPE > AT24C16)1 c' j$ ]2 r; Q3 Y! E
  32.   {7 v. Q) `# q; R  j" [* l$ H
  33.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令
    ! e7 g" w0 o# g# L. B% k! `1 D( o8 t
  34.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    + r3 N* C# j4 T: \/ W' y) p
  35.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//发送高地址     
    , }0 D2 N6 W( ?8 ?/ [; ~
  36.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据     ( J9 G; ~2 N! t2 f5 B  `
  37.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    / {, s( `! ?( m: a/ D
  38.    AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256);   //发送低地址! o' M- G4 t/ d7 ?
  39.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);               
    0 v/ |$ R/ n% G8 b
  40.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite);     //发送字节         
    5 u5 H$ p3 C: I! g
  41.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);            6 y: k) ^% S1 n6 `* K
  42.    AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件
    4 X2 X( Y# q6 ?2 s* f* T" a0 ?
  43. AT24CXX_Type_t->IIC.delay_us(10000);  
    + b7 {  E: b8 V
  44. }
    0 x# O/ x0 G& s6 O4 [
  45. //在AT24CXX里面的指定地址开始写入长度为Len的数据& U% ^, y( ?& k& K& ]0 s* ~
  46. //该函数用于写入16bit或者32bit的数据.
    - O4 h# J2 I4 r! g; S
  47. //WriteAddr  :开始写入的地址  " z( F' Q; C2 n* k, e$ v
  48. //DataToWrite:数据数组首地址
    7 V( @" h/ G& D$ b) F
  49. //Len        :要写入数据的长度2,4
      a- K# z0 `; s: u5 M9 y" d) G
  50. static void AT24CXX_WriteLenByte_t(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len)0 ]3 D- j) m# `, [! @% L8 t
  51. {   
    % m6 I- P; B- e; k- U: g8 v
  52.   uint8_t t;
    0 F- F( y# B/ O& K0 M% [
  53. for(t=0;t<Len;t++)+ m, E. }9 p% o( ~4 e' x; N" G  [. M8 A
  54.   {
    * |$ |6 r4 m* B
  55.     AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);4 [* h% `- t4 w
  56.   }                3 Z5 o8 v: L' g, R: Y* y) M8 r
  57. }$ j) E2 O9 M5 w6 p; I: L
  58. //在AT24CXX里面的指定地址开始读出长度为Len的数据8 v: u6 w: R8 ?
  59. //该函数用于读出16bit或者32bit的数据.: w& Y" J  q0 f5 h. I& f& a
  60. //ReadAddr   :开始读出的地址
    ( N& T3 l) f0 [9 ^& v; S
  61. //返回值     :数据+ j; F$ F; S- a$ S
  62. //Len        :要读出数据的长度2,4- m4 ^: X7 S( H8 @, h; d# f
  63. static uint32_t AT24CXX_ReadLenByte_t(uint16_t ReadAddr,uint8_t Len)8 C8 D4 _" d, z2 J8 Y/ q, ]
  64. {   
    ' b  T5 G" R+ V$ c5 z
  65.   uint8_t t;
    & d7 D' ]& W7 X4 e
  66.   uint32_t temp=0;
    - g# E8 c" ]9 C' A8 Y
  67. for(t=0;t<Len;t++)
    % ]: S5 y* g. r, F& q: v' ?6 T
  68.   {# `* f0 ~$ e6 j5 r$ A
  69.     temp<<=8;
    % A7 }. v' ?7 Z% t" V4 e
  70.      temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);          4 l5 Q1 K. O* f5 A2 [! m1 K6 n9 L
  71.   }
    ( j  {( l# f5 @  K1 d
  72. return temp;                % a* u# i% y2 W6 E6 b7 g
  73. }
    8 l5 o/ M, [. A$ `3 ~1 {
  74. //在AT24CXX里面的指定地址开始写入指定个数的数据
    1 |. d  E2 ?# h! q
  75. //WriteAddr :开始写入的地址 对24c64为0~81913 B$ U8 w. @+ h" Z0 N$ F
  76. //pBuffer   :数据数组首地址% y9 \1 Z1 @5 c' V! V+ L$ E; ^
  77. //NumToWrite:要写入数据的个数1 B9 L  O, b& K) C# r1 l! F$ v
  78. static void AT24CXX_Write_t(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)
    - ?4 S  A- s% p1 l6 |5 u
  79. {
    8 K3 j& M: t4 L6 n0 d6 a
  80. while(NumToWrite--)" Q3 \# g/ D+ J5 B3 V+ O' b5 [
  81.   {3 ]8 S+ G9 |2 o  u- ]) f8 q7 O
  82.    AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    ) I# A( ]8 x, h5 j& ~% _
  83.     WriteAddr++;, P3 h9 a$ f: v5 ]9 ^
  84.     pBuffer++;( c6 c* e/ s4 P3 r( ~
  85.   }$ l  X6 d/ z- H& m
  86. }
    * n  b9 q4 g$ a
  87. //在AT24CXX里面的指定地址开始读出指定个数的数据
    6 S8 Z5 a, z5 {' l. U* |0 i$ [; V6 ?
  88. //ReadAddr :开始读出的地址 对24c64为0~8191
    + z  A  }/ t+ m3 `" X( Y
  89. //pBuffer  :数据数组首地址0 F9 j0 _6 k0 v1 ?- {8 l: I# h  s
  90. //NumToRead:要读出数据的个数; {4 {% H. C6 B$ Z8 Q! u- S' K
  91. static void AT24CXX_Read_t(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead)
    % s8 H" P( u9 I% \
  92. {
    9 [+ A, p% Y/ H
  93. while(NumToRead)
    : I% ~' ^$ J1 ^2 z6 K+ [2 E& [+ d
  94.   {
    # _! t- S% g" M$ {$ q. F
  95.     *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); & o* t. a9 A6 P5 f2 B& a5 T! {+ L
  96.     NumToRead--;- V* s" U$ b; z7 y# w& s9 e
  97.   }
    8 P6 m5 J4 P4 c; y0 m
  98. } . ~) B1 b7 T6 V3 }) A3 \% _
  99. //初始化IIC接口  b. C! }0 ~. J& ?  w
  100. static void AT24CXX_Init_t(const struct AT24CXX_Type* AT24CXX_Type_t)& F, a2 f  i3 ]( a
  101. {9 l0 z5 @+ R' w) Q7 z8 l. Q
  102.   AT24CXX_Type_t->IIC.IIC_Init(&AT24CXX_Type_t->IIC);//IIC初始化
    * N9 l! l3 e. \) R- \% X+ C: I
  103. }' W# n; x& T5 I0 F) A
  104. //检查器件,返回0表示检测成功,返回1表示检测失败1 ~. f8 l5 d/ ?8 [. t/ |
  105. static uint8_t AT24CXX_Check_t(const struct AT24CXX_Type* AT24CXX_Type_t)   6 W5 B& I  J( N; Z0 R$ ?+ A; X4 N/ `1 O
  106. {8 B* x* \" o4 ?
  107. uint8_t temp;: Z5 ]5 U5 A: ~0 ^' k/ Q/ a
  108.   temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);//避免每次开机都写AT24CXX      ( `% B, S- u. g! t" I
  109. if(temp == 0X33)return 0;     % {+ U5 f) U. i! H+ k7 k6 W
  110. else//排除第一次初始化的情况
    ' ]7 s$ P+ V% h& C$ |3 P# p
  111.   {/ f7 {4 x; b$ d; s% N/ c( ?+ z
  112.       AT24CXX_Type_t->AT24CXX_WriteOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE,0X33);
    3 W& l3 ^  y* r0 B
  113.        temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);
    7 U# P; |4 o# p/ K
  114. if(temp==0X33)return 0;
    * x" D# E' E" ]6 j, M4 h
  115.   }7 O4 H1 A  ~/ U1 |/ l
  116. return 1;  
    . s7 A$ k. `* j5 p8 f) C
  117. }, Y. ~) I8 E6 o& P; u' W
  118. //实例化AT24CXX对象( ]+ |& Y' R! h$ Z" l7 J
  119. AT24CXX_TypeDef AT24C_64={" _% k) ^7 T; {& _' o5 E
  120. .EEP_TYPE = AT24C64,           //存储器类型(存储器容量)
    - _  Z( I2 U0 T' {+ w- \
  121. //操作
    0 z7 Q( j' m" w
  122. .IIC={
    ( T6 k& E7 O2 c% n  `6 U
  123.   .GPIOx_SCL = GPIOA,7 T+ v  O0 T5 A
  124.   .GPIOx_SDA = GPIOA,( W2 [% e- F0 Z: N! G9 U
  125.   .GPIO_SCL = GPIO_PIN_5,7 K" [, S7 Y' I. [! o% b3 i
  126.   .GPIO_SDA = GPIO_PIN_6," O- P0 _: V( R# A6 G
  127.   .IIC_Init = IIC_Init_t,+ E0 X4 D5 b3 L, p
  128.   .IIC_Start = IIC_Start_t,
    * j! h& Y( B  R8 Q8 y: z& b4 Z  o" c. z
  129.   .IIC_Stop = IIC_Stop_t,
    4 N5 W( {2 i# Z' d7 U9 C
  130.   .IIC_Wait_Ack = IIC_Wait_Ack_t,; u3 I$ i4 ~' N0 N
  131.   .IIC_Ack = IIC_Ack_t,
      o+ E1 l; Z% Q
  132.   .IIC_NAck = IIC_NAck_t,9 f; K: n. @; G1 ^# J6 G
  133.   .IIC_Send_Byte = IIC_Send_Byte_t,
    ! L' w: M9 r7 l2 y1 P2 N+ ^
  134.   .IIC_Read_Byte = IIC_Read_Byte_t,
    9 q: L! V9 Z4 H4 n4 f) D
  135.   .delay_us = delay_us; C0 l2 _, f8 d) d
  136. },                   //IIC驱动
    5 f" o1 U- I8 ^6 d/ m3 H# p" t$ K
  137. .AT24CXX_ReadOneByte = AT24CXX_ReadOneByte_t,  //指定地址读取一个字节% O# T7 I* {5 f
  138. .AT24CXX_WriteOneByte = AT24CXX_WriteOneByte_t,//指定地址写入一个字节
    1 J/ x4 e6 ]+ D( o
  139. .AT24CXX_WriteLenByte = AT24CXX_WriteLenByte_t, //指定地址开始写入指定长度的数据' F" i7 n( n* ^+ u$ k) w- H$ }. A
  140. .AT24CXX_ReadLenByte = AT24CXX_ReadLenByte_t,   //指定地址开始读取指定长度数据, b5 \  a' k- i6 z& }) O
  141. .AT24CXX_Write = AT24CXX_Write_t,  //指定地址开始写入指定长度的数据
    ) T& \/ H; |) K) S
  142. .AT24CXX_Read = AT24CXX_Read_t,   //指定地址开始读取指定长度的数据
    1 S  g# I6 w/ n. U9 E; q: E. V
  143. .AT24CXX_Init = AT24CXX_Init_t, //初始化IIC1 @; I) G0 {' i
  144. .AT24CXX_Check = AT24CXX_Check_t   //检查器件
    : g% u* y# L) H/ _2 v
  145. };
复制代码

3 N6 o9 q! b5 D$ E
    简单分析:可以看出AT24CXX类中包含了IIC类的成员对象,这是一种包含关系,因为没有属性上的一致性因此谈不上继承。
    之所以将IIC的类对象作为AT24CXX类的成员是因为AT24CXX的实现需要调用IIC的成员方法,IIC相当于AT24CXX更下层的驱动,因此采用包含关系更合适。
    因此我们在使用AT24CXX的时候只需要实例化AT24CXX类对象就行了,因为IIC包含在AT24CXX类中间,因此不需要实例化IIC类对象,对外提供了较好的封装接口。下面我们看具体的调用方法。
6 p: \( M+ i4 v5 R5 j: z' t* S
主函数main调用测试
    在main函数中直接使用AT24C_64来完成所有操作,下面结合代码来看:
  1. #include "at24cxx.h"    //为了确定AT24C_64的成员方法和引用操作对象AT24C_647 }  ]6 p- b# ~, ]
  2. int main(void)
    ( L. N0 h7 F$ g- b. b# a& Q
  3. {: E" v6 ~# N) g+ u* V4 Q( y
  4. /************省略其他初始化工作****************/3 S! k$ v% e3 N  @  ?" n
  5. //第一步:调用对象初始化方法来初始化AT24C64
    6 n4 R0 z6 \% D, g  l: E
  6.   AT24C_64.AT24CXX_Init(&AT24C_64);( y; \- R  W+ z. c3 M2 l7 ~- N; V
  7. //第二步:调用对象检测方法来检测AT24C64           
    ' }7 a8 Y" H7 l4 L& M
  8. if(AT24C_64.AT24CXX_Check(&AT24C_64) == 0)- X4 e$ H$ x/ c$ w
  9.   {# R6 p6 |4 l" F9 e" G! \7 z( H( k' z
  10. printf("AT24C64检测成功\r\n");
    ; G6 L/ N- w0 t2 X3 d" \
  11.   }' U3 ^! h' G. n
  12. else{
    ' Q; d* i; c( R0 E6 |
  13. printf("AT24C64检测失败\r\n");) p/ A, U3 l/ Q0 N% n8 f" K. E3 n
  14.   }$ I# a4 z  V# _
  15. return 0;# T- K& O2 M0 F, f
  16. }
复制代码

/ f$ T# J! I! d# x1 [4 h. N; S% J
    可以看出所有的操作都是通过AT24C_64对象调用完成的,在我们初始化好AT24C_64对象之后就可以放心大胆的调用其成员方法,这样封装的好处就是一个设备对外只提供一个对象接口,简洁明了。

) _4 H& u7 J1 Y& T
总结
    本文详细介绍了面向对象方法实现IIC驱动封装以及AT24CXX存储器的封装,最终对外仅提供一个操作对象接口,大大提高了代码的复用性以及封装性。
! I0 i1 h' L7 }7 D% k% c
% _' p: w' \# ^) d$ ]  E. I
收藏 评论0 发布时间:2022-6-7 09:41

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版