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

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

[复制链接]
STMCU小助手 发布时间:2022-6-7 09:41
简述
    IIC(Inter-Integrated Circuit)其实是IICBus简称,它是一种串行通信总线,使用多主从架构,在STM32开发中经常见到。
    使用面向对象的编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备时只需要实例化一个IIC对象即可,本文是基于STM32和HAL库做进一步封装的。
    底层驱动方法不重要,封装的思想很重要。在完成对IIC驱动的封装之后借助继承特性实现AT24C64存储器的驱动开发,仍使用面向对象的思想封装AT24C64驱动。
. l; J1 r4 N/ U0 Q8 p
IIC驱动面向对象封装
    iic.h头文件主要是类模板的定义,具体如下:
  1. //定义IIC类
    ( d# e1 k4 H. M, |) U) F
  2. typedef struct IIC_Type
    # H/ C. {! }8 i
  3. {8 S2 s+ N( S3 H  K& D0 S
  4. //属性1 Z, p: [+ A8 L4 K
  5.    GPIO_TypeDef  *GPIOx_SCL;  //GPIO_SCL所属的GPIO组(如:GPIOA)
    0 _* u; Z. z# q; }" y% ]" m. M7 a
  6.    GPIO_TypeDef  *GPIOx_SDA;  //GPIO_SDA所属的GPIO组(如:GPIOA)5 V9 s! h2 N3 o: J1 e1 Z
  7. uint32_t GPIO_SCL;     //GPIO_SCL的IO引脚(如:GPIO_PIN_0)( C; L- R$ {3 U6 k4 n6 y
  8. uint32_t GPIO_SDA;     //GPIO_SDA的IO引脚(如:GPIO_PIN_0)2 s* q1 l8 A0 k5 B5 ~
  9. //操作
    3 H2 T. r6 g( k9 I+ X+ {
  10. void (*IIC_Init)(const struct IIC_Type*);        //IIC_Init8 m) A' m- r* B7 Z
  11. void (*IIC_Start)(const struct IIC_Type*);       //IIC_Start3 j$ |2 Q5 P! l7 A1 j$ E1 K* i6 h
  12. void (*IIC_Stop)(const struct IIC_Type*);        //IIC_Stop
    , K% ^1 B4 n# z+ m, _
  13. uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*);    //IIC_Wait_ack,返回wait失败或是成功  ]3 z4 W8 {' M& J6 e
  14. void (*IIC_Ack)(const struct IIC_Type*);       //IIC_Ack,IIC发送ACK信号
    ) G& I/ a1 j! g7 v* q0 \7 X
  15. void (*IIC_NAck)(const struct IIC_Type*);       //IIC_NAck,IIC发送NACK信号$ ^% X* c6 K. G' N: u2 q
  16. void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t);       //IIC_Send_Byte,入口参数为要发送的字节# v3 B5 W, s1 \
  17. uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t);     //IIC_Send_Byte,入口参数为是否要发送ACK信号
    # Z! M& A* f- [5 C$ U2 w5 x
  18. void (*delay_us)(uint32_t);              //us延时
    ( k. c4 y' M4 ~' v' N
  19. }IIC_TypeDef;
复制代码
3 @' E! C0 H( j
8 Q* p5 ]% J3 i1 n* j: k4 q
iic.c源文件主要是类模板具体操作函数的实现,具体如下:
) B# s4 H  j' j) C2 M9 i8 B
  1. //设置SDA为输入模式4 v  e  b9 ]4 @3 f7 t0 [  z
  2. static void SDA_IN(const struct IIC_Type* IIC_Type_t)
    6 _/ b: `3 b' F  E; N, z
  3. {+ b: _- N- T3 k1 J( F8 L1 E
  4.   uint8_t io_num = 0;  //定义io Num号
    ; i$ {: @9 Q2 L" l' ]! ]/ ^4 ]( U
  5. switch(IIC_Type_t->GPIO_SDA)7 s& v, \; {7 f& t1 X5 {5 N
  6.   {
    4 b( t4 r* a6 I
  7. case GPIO_PIN_0:2 P1 c1 h$ K# \# U( B1 a
  8.     io_num = 0;) D, P/ ?; w5 b& @( h' e
  9. break;1 n; O3 v4 c. A
  10. case GPIO_PIN_1:
    " q! ~% Z% k; j" _# f' J" j+ y% k
  11.     io_num = 1;
    # F) t+ ^- `  f; ?/ ~- f& A
  12. break;
    3 t9 P7 Z  H; p  }. Q, n6 J/ g; _
  13. case GPIO_PIN_2:
    ! ^% ^% |/ c1 ?2 s
  14.     io_num = 2;, t, `, T3 {5 \& M; h1 Q5 T7 P& k- i
  15. break;
    1 Y& b# M, }/ i2 o* r/ [" W1 t5 p" w
  16. case GPIO_PIN_3:2 v1 ?+ C; z: e6 L0 r' z( @' T* E0 e
  17.     io_num = 3;
    : m. N8 l1 b4 Q; L  _6 H, u3 n
  18. break;! g. _. t2 h- c& d" M
  19. case GPIO_PIN_4:" _) }5 R/ X, Z9 b$ G  w0 A% Y
  20.     io_num = 4;
    - Z) `7 I% ~$ G8 q
  21. break;
    4 R7 Z9 d3 o0 B8 \6 m; X
  22. case GPIO_PIN_5:
    $ D( `1 B; }6 M# B- o
  23.     io_num = 5;* Y/ x* e* F4 M. R& S
  24. break; 4 W# m5 k% ^5 u3 t9 `5 R/ f& @3 `
  25. case GPIO_PIN_6:
    2 [0 i" Y; C% y% x, b' }- `- `
  26.     io_num = 6;7 T5 o) @1 ?0 `/ R' r/ r4 S* e+ K
  27. break;
    8 M  m+ }( @4 }  [/ Y
  28. case GPIO_PIN_7:
    % A! W) i2 M+ C* O" R
  29.     io_num = 7;
    2 p, B# m/ ~$ q" R6 L9 p
  30. break;& ~$ s% R' Q8 P
  31. case GPIO_PIN_8:5 |6 G; m) H/ n) o
  32.     io_num = 8;. L- Q0 R& ^; V: z
  33. break; 5 E) k3 n$ e7 G& U* ?
  34. case GPIO_PIN_9:
    ' ^& C' p! h, k1 h' j7 [$ I) ~
  35.     io_num = 9;( L! m1 k. o' b8 q& m5 W2 c
  36. break;
    1 P7 G0 P4 |2 B% C2 p( j3 E" T
  37. case GPIO_PIN_10:- v( Y$ b. f# r  F6 O4 J
  38.     io_num = 10;
    0 @! K& _4 v( S* D* o7 H7 w
  39. break;
    * x. s( ]0 I  b$ G% L2 k  P3 c
  40. case GPIO_PIN_11:
    9 f* f" q2 f, B0 C( p0 B9 H
  41.     io_num = 11;
    0 A# ~. G  ]+ m  {% O" l0 Q/ P; v
  42. break; 0 T$ G+ e7 Y. s% x/ Y  [, V. P' G3 G
  43. case GPIO_PIN_12:+ T/ L/ B/ L' M; C! h
  44.     io_num = 12;
    , ]/ k1 c, T" W7 n
  45. break;+ P) @( X0 `; v, `" G' |2 j# U
  46. case GPIO_PIN_13:& h2 l, t6 j9 w/ L! ~+ k
  47.     io_num = 13;0 X% N* B' U/ \  J# ^
  48. break;
    ) M: C8 A$ R- S( J
  49. case GPIO_PIN_14:& d* h$ |5 X3 X% z$ T+ x
  50.     io_num = 14;
    * [5 ~( i0 a$ P; a! m$ |/ o0 V
  51. break; 8 Z, A- u0 X3 E6 ]
  52. case GPIO_PIN_15:
    3 b# k/ L4 Z& s/ g4 M* [: h8 i
  53.     io_num = 15;& \+ }' S( O+ L( y
  54. break;
    8 t: a2 I- A. A. H7 B8 Y8 M( j
  55.   }4 r/ R, W: Z6 r8 g& [% ^
  56.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零1 O+ C) `3 D- K2 `# ]
  57.   IIC_Type_t->GPIOx_SDA->MODER|=0<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输入模式; N# J7 i  ?, O
  58. }
    - N2 o+ d: B5 \% x- S# i9 U% Q1 f3 \: K
  59. 2 A" k- W2 n; x9 q7 n7 h  Z
  60. //设置SDA为输出模式0 w& K1 I- P9 {* h! \& ]
  61. static void SDA_OUT(const struct IIC_Type* IIC_Type_t)
    " i4 g% T- D' i6 r1 l' m
  62. {- t* v! x$ s  [# x# t$ b# k8 h
  63.   uint8_t io_num = 0;  //定义io Num号
    0 Z5 W& @$ I$ h6 |% ]8 `, q
  64. switch(IIC_Type_t->GPIO_SDA)
    # w* j8 d, i5 z# X. ^
  65.   {
    ) w. Z& l5 D# I: p3 v! S0 b
  66. case GPIO_PIN_0:
    % u9 {. f0 |2 v$ d, N6 A: x7 d
  67.     io_num = 0;
    % @5 V; o% P2 N0 x5 Z
  68. break;
    1 a/ m+ v: R/ r( L; Q: T( `
  69. case GPIO_PIN_1:; N1 t2 _1 A! [6 j0 ?5 x4 x
  70.     io_num = 1;
    % d- [6 Q9 d% ~) b1 u
  71. break;
    % S( k1 P9 \( v5 z
  72. case GPIO_PIN_2:
    : H( Z2 p' V! o5 o1 \* @
  73.     io_num = 2;
    4 m4 `$ N, ?. c0 f0 s
  74. break; ' K0 Z; R, c1 F* S- u3 k! x
  75. case GPIO_PIN_3:
    8 A, f" q# \- \1 a  b
  76.     io_num = 3;; Q" o& Q; [" f( ?
  77. break;
    5 {' S! B; w# H3 E* @2 i) w
  78. case GPIO_PIN_4:
    " _: T5 e5 s/ W$ K3 X, v  s- e
  79.     io_num = 4;
    ) y% U6 o5 a3 [  t# o
  80. break;
    * A  _! P  p& E8 E5 @- f
  81. case GPIO_PIN_5:
    * ^) a2 H, @' C
  82.     io_num = 5;
    2 I% a! [% @. _- z; b4 R
  83. break; ( ^3 G9 _. w4 q( K
  84. case GPIO_PIN_6:
    * I; |1 O5 ^6 `' J0 A8 z
  85.     io_num = 6;2 {4 C* R  T1 ?' q) F9 E
  86. break; - l) o$ l: h' O3 V
  87. case GPIO_PIN_7:  q. Z; `3 M( r; h
  88.     io_num = 7;( T% N! W& `. R0 {) v# D& r3 q4 f
  89. break;
    ! G" [1 I  K  ~
  90. case GPIO_PIN_8:  W8 o% K1 N8 a
  91.     io_num = 8;5 y# Z8 {! ?) G2 I% a
  92. break;
    " k( u+ e8 Y+ C* A# G
  93. case GPIO_PIN_9:
    " A% w9 K3 R9 L$ x# W
  94.     io_num = 9;9 d! {; B+ Z, d) M
  95. break;
    - B; L5 u2 O1 ?0 |6 v$ J
  96. case GPIO_PIN_10:8 d; A& Z0 a" k6 V$ B& M
  97.     io_num = 10;
    ) |4 c, ~5 \( `) n
  98. break;
    4 i: U% V9 V  u0 `1 \+ A4 s
  99. case GPIO_PIN_11:
    . R+ _: ]% {% \0 R
  100.     io_num = 11;& X1 \: ~! k+ L, k! x
  101. break; - {( R: f/ I5 F3 J3 I4 Z/ i8 B* V
  102. case GPIO_PIN_12:
    ) c, i- f7 `4 @- G0 z! u) N
  103.     io_num = 12;
    / e' @4 ]" p$ y7 i( ^+ T  v
  104. break;8 ~/ r8 V# Z. C6 q
  105. case GPIO_PIN_13:
    + ^( H! |% }. p' Q5 C- w
  106.     io_num = 13;  e% ^6 ?9 P3 Z  x
  107. break;  B9 e5 r# |/ p5 S, T. A
  108. case GPIO_PIN_14:
    ' y6 x' r8 j& t1 y# p; A8 J* |
  109.     io_num = 14;
    , `1 g7 c) L' G$ z( {
  110. break; . Z& ~- V3 ?8 R0 |# f* J" c! P5 Z+ ]
  111. case GPIO_PIN_15:
    # A8 ]7 k8 K5 I" y4 a$ t9 o; _. s
  112.     io_num = 15;8 e) U2 H; K9 u2 A
  113. break;
    2 H, k& S. J; M! ~7 W
  114.   }" N" G& e0 c! ]
  115.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零* |; a8 Z6 a6 [- y' k- h0 I& i8 n
  116.   IIC_Type_t->GPIOx_SDA->MODER|=1<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输出模式$ y' J, U  E4 q
  117. }6 H' F* J) R) a1 R' ~+ K9 D0 {0 H, B
  118. //设置SCL电平
    + X# [. Z- m; O' e5 S- n
  119. static void IIC_SCL(const struct IIC_Type* IIC_Type_t,int n)
    2 q! u. v4 f4 K
  120. {
    9 t* P+ [. l# ^0 p3 h) V
  121. if(n == 1)
    / b( B# y6 f/ p) }' m3 E3 }
  122.   {, j. K$ o7 m0 p; X0 t6 R* V4 S- w: j! m
  123.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_SET);     //设置SCL为高电平$ L% X  C) q+ i9 S# j
  124.   }
    1 ^0 j2 L& }# P. W. ^+ `
  125. else{$ U' `5 F  R) F$ t% @2 ^! G
  126.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET);     //设置SCL为低电平
    8 y7 R9 r; H2 h# i! m, {  {
  127.   }" L; \1 h6 q1 D2 C9 [
  128. }
    1 t3 N% O, C8 w1 P5 t0 Y
  129. //设置SDA电平; E; m) M/ c9 k' ^( ~, g
  130. static void IIC_SDA(const struct IIC_Type* IIC_Type_t,int n)5 B) w; z- v' O" |, N3 C
  131. {- H9 _9 W: j4 u- t6 X
  132. if(n == 1). u3 H0 ?& j" \7 B% c, J( J
  133.   {. W1 l; I- y8 j- p# n+ s' L  ?
  134.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_SET);     //设置SDA为高电平
    / d) s: `2 c6 r. K
  135.   }: J1 H% ?- l- t: P9 N: e) R0 l
  136. else{
    ( B: u2 |/ y- }6 y: g; h! }
  137.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET);     //设置SDA为低电平
    ) M/ Y6 Y' n8 b1 r+ g
  138.   }3 t& C4 X' P) p1 }
  139. }
    1 W0 u/ X1 P2 Y# b
  140. //读取SDA电平
    # M8 o' [$ a' v( x
  141. static uint8_t READ_SDA(const struct IIC_Type* IIC_Type_t)
    : P( G1 G1 n% x* I
  142. {" e6 ]! n5 e4 x! z- s% d5 N' h
  143. return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA);  //读取SDA电平* X. E- Y( X& n& y" a0 }/ o' J
  144. }
    . o  w5 s8 D9 C6 i2 X/ V  e0 v
  145. //IIC初始化
    7 O/ }: k0 b2 B" Z; s" I
  146. static void IIC_Init_t(const struct IIC_Type* IIC_Type_t)
    " h5 j8 S' x% ~1 k
  147. {7 Y) V6 T7 \% w3 q: E
  148.       GPIO_InitTypeDef GPIO_Initure;1 M" \& u' p8 X" A' L

  149. 4 U1 a2 Z6 x! E  _) {4 |. q
  150. //根据GPIO组初始化GPIO时钟: R( F, j; x2 F' Q
  151. if(IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)
    - }# l7 W& L: C' T
  152.    {8 P+ t8 J3 k3 o) d) J1 A+ u
  153.      __HAL_RCC_GPIOA_CLK_ENABLE();   //使能GPIOA时钟, \4 `- J! q, i' e. K- `* y* }
  154.    }
    4 ^% ~! l; E  j/ Q
  155. if(IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)
    0 Q5 f7 @  ?3 ~# Z0 T: W" ]
  156.    {
    / k2 E# j% \' y
  157.      __HAL_RCC_GPIOB_CLK_ENABLE();   //使能GPIOB时钟
    4 w$ @. _3 ~- Y
  158.    }
    / {& M5 F7 o( [! A& D9 i
  159. if(IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)) Q. @' x5 B: u6 d0 X, _
  160.    {
    ( ^0 j2 F& @! k( `" \3 d
  161.      __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟  z& N$ Z! @; }( z9 ^
  162.    }$ b0 h# r4 q! o/ u1 C/ M) k. R
  163. if(IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)! l8 F2 p: H6 V+ i7 c
  164.    {6 Q4 w7 w: Q7 I$ ]8 ~( v# V: Z1 E
  165.      __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD时钟' J( m0 w0 w+ ~$ m2 c% v* G
  166.    }) M7 h- Z) @0 [1 c3 Z
  167. if(IIC_Type_t->GPIOx_SCL == GPIOE || IIC_Type_t->GPIOx_SDA == GPIOE)
    6 ~& f6 L1 X. r/ ?! d* `0 h3 F
  168.    {
    - A( P( p# [0 O" ?1 b
  169.      __HAL_RCC_GPIOE_CLK_ENABLE();   //使能GPIOE时钟4 W) ~* j$ z7 B! f
  170.    }
    + w: n  A2 d" c  L
  171. if(IIC_Type_t->GPIOx_SCL == GPIOH || IIC_Type_t->GPIOx_SDA == GPIOH)
    + r/ l9 [6 k! V, f+ \" K* Y+ g/ E1 m
  172.    {
    3 p, ]" @" l2 Q  f4 D
  173.      __HAL_RCC_GPIOH_CLK_ENABLE();   //使能GPIOH时钟
    0 f. u0 }2 f6 p3 L/ u0 D5 m
  174.    }     : U7 Y( B% ~: j7 W. q$ [

  175. ) A( p6 h4 s" S) P7 j4 c; s( {: I/ I
  176. //GPIO_SCL初始化设置
    5 A/ W  D7 _* a! `9 j' m" l
  177.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SCL;1 }& X3 V2 U9 ^+ Y" k4 n
  178.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
      w  M. E2 I8 d. i& y# D
  179.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉" K; T5 S" N' [. p
  180.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速( ]8 r% X! [# Q3 \
  181.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL,&GPIO_Initure);/ p' M9 i. f& S- u  s# W2 ?* ]  I) l
  182. //GPIO_SDA初始化设置
    ' e4 {0 S% a8 B- q" B0 `* t, N
  183.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SDA;& m7 d& z! k$ |
  184.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    ; {( Q( w+ a7 m- g+ z2 c1 L
  185.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉7 ^' P/ L1 e8 z& [
  186.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速; M8 f4 w) r! b9 `" y* \/ D
  187.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA,&GPIO_Initure);
    3 [* i" E; h) |3 e; j% G/ r$ H

  188. 3 ]3 L( y) [+ }) g* N, B- X9 w
  189. //SCL与SDA的初始化均为高电平5 O: e9 b7 ]% [  c9 u
  190.       IIC_SCL(IIC_Type_t,1);
    % a  N  f" k( e7 z: c: J% x8 ]
  191.        IIC_SDA(IIC_Type_t,1);
    - v+ r2 W0 L- w9 s- K0 \
  192. }
    ' Y: |( b0 V+ n  e9 o7 t
  193. //IIC Start
    * d9 `# h; P) b4 }
  194. static void IIC_Start_t(const struct IIC_Type* IIC_Type_t)2 }, o2 G" G/ W! ]4 I0 a( u, V8 B
  195. {
    3 n* C* R. b" X4 j( x3 j
  196.   SDA_OUT(IIC_Type_t);      //sda线输出  b. M% k4 V9 m- l' O
  197.   IIC_SDA(IIC_Type_t,1);      
    2 u- o8 U* s) l; `$ Y2 y; Y
  198.   IIC_SCL(IIC_Type_t,1);
    & i3 K  `  l, G  G3 \8 F
  199.   IIC_Type_t->delay_us(4);% k, L/ q( @% b  T. \7 K: z' f
  200.    IIC_SDA(IIC_Type_t,0);  //START:when CLK is high,DATA change form high to low
    " ?6 O- e6 {0 ~3 s
  201.   IIC_Type_t->delay_us(4);
    ) k* p* y* ^2 g7 t% Z
  202.   IIC_SCL(IIC_Type_t,0);  //钳住I2C总线,准备发送或接收数据
    ; _* k: O) I: |( o3 k
  203. }' K, B3 E1 y' a7 L1 c
  204. //IIC Stop/ [' U9 o& V  Q0 s
  205. static void IIC_Stop_t(const struct IIC_Type* IIC_Type_t)
      d8 O# I1 P3 _5 n+ X/ z* `% {
  206. {
    ' P% O$ A& Z" m0 V9 w0 V8 g
  207.   SDA_OUT(IIC_Type_t); //sda线输出/ p1 c6 z  E  {: q% z- E8 i
  208.   IIC_SCL(IIC_Type_t,0);9 D7 @" ~' ]( m& P( ~
  209.   IIC_SDA(IIC_Type_t,0); //STOP:when CLK is high DATA change form low to high4 m% F' |1 T9 @+ c( q
  210.    IIC_Type_t->delay_us(4);% `9 R0 Y+ p! x  B/ ?3 p  y
  211.   IIC_SCL(IIC_Type_t,1); ! i0 i! J! Z9 ]% \# \
  212.   IIC_SDA(IIC_Type_t,1); //发送I2C总线结束信号' E( X: e" ~% E& l; G$ f
  213.   IIC_Type_t->delay_us(4);
    1 a- F+ {- v+ X+ g
  214. }
      R2 @1 t1 X! I, t. m9 D' L2 a
  215. //IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败; X# f+ u0 N' q8 p9 J9 W5 ]; {
  216. static uint8_t IIC_Wait_Ack_t(const struct IIC_Type* IIC_Type_t)   //IIC_Wait_ack,返回wait失败或是成功4 p+ |+ R9 W1 D
  217. {
    ( U. Q1 O, B; v
  218.   uint8_t ucErrTime = 0;1 F% o- H1 w: w8 h+ M
  219.   SDA_IN(IIC_Type_t);      //SDA设置为输入  ; O: \1 P5 k  X! v" P) Y7 A7 u
  220.   IIC_SDA(IIC_Type_t,1);IIC_Type_t->delay_us(1);   4 H8 H# g" R3 n& x5 }0 D% Z
  221.   IIC_SCL(IIC_Type_t,1);IIC_Type_t->delay_us(1);
    4 \' \' q3 I* R4 G* Y9 H' I- x
  222. while(READ_SDA(IIC_Type_t)), c% r; d$ S8 Z) p" x) N/ c' h
  223.   {
    7 k. i# T! x  C: ?
  224.     ucErrTime++;
    " q6 J* U1 {, [# u3 f
  225. if(ucErrTime>250)* _" ^; s$ _% Y3 E' {+ f
  226.     {$ I* M. j; z8 w% q# a
  227.       IIC_Type_t->IIC_Stop(IIC_Type_t);
    9 M, V7 g: V6 A! p/ H
  228. return HAL_ERROR;" U7 T. r) C5 b% Z
  229.     }3 l0 l$ a+ B+ U/ F4 m9 ?
  230.   }
    7 f1 `' j% Y7 P* b
  231.   IIC_SCL(IIC_Type_t,0);//时钟输出0     + s. f/ V) i7 Z6 ]( X! ~6 z
  232. return HAL_OK;  
    $ j% z/ E  E/ z% Y! F: O
  233. }
    6 m4 j* b% T; d2 Z! ?
  234. //产生ACK应答2 Z( ]7 B, B5 Y/ I4 I+ X6 |/ A
  235. static void IIC_Ack_t(const struct IIC_Type* IIC_Type_t)      ! `, l1 V% K$ @! Y) s: @
  236. {, ~: v5 n- M7 z' f
  237.   IIC_SCL(IIC_Type_t,0);
    4 s1 l& o: P3 N5 Q/ Z8 P/ r
  238.   SDA_OUT(IIC_Type_t);' T- {0 d0 O! e7 V3 Q3 p
  239.   IIC_SDA(IIC_Type_t,0);4 \$ d) _/ J2 r3 l
  240.   IIC_Type_t->delay_us(2);  
    " X: ?: u. ~+ m2 q* C! I
  241.   IIC_SCL(IIC_Type_t,1);
    # M0 O5 I) R/ v3 {# B* W' h* t
  242.   IIC_Type_t->delay_us(2);  
    . ?) g7 ~, f+ ~+ b7 o
  243.   IIC_SCL(IIC_Type_t,0);- }; R7 y6 B7 Y3 `) r5 w; T- g& L
  244. }4 i6 b6 i# ~' G- C1 K
  245. //产生NACK应答
    , d+ q/ I' ^: K) p% h
  246. static void IIC_NAck_t(const struct IIC_Type* IIC_Type_t)      8 @& X6 _& P- f8 [9 `4 ?8 [9 \
  247. {
    ) p4 Q9 z: E0 _! N
  248.   IIC_SCL(IIC_Type_t,0);
    % |" U/ H, k% y1 S
  249.   SDA_OUT(IIC_Type_t);
    , g# j( Y: G( L( l1 `$ T  Z+ V
  250.   IIC_SDA(IIC_Type_t,1);
    - X; c. ^2 P7 p. ^6 r) k* U
  251.   IIC_Type_t->delay_us(2);  
    , Y2 d. `: c6 ~  @, s# [* R
  252.   IIC_SCL(IIC_Type_t,1);; T' O* m# W# T) |0 x
  253.   IIC_Type_t->delay_us(2);    |0 M. t" n+ D3 [/ c$ ?
  254.   IIC_SCL(IIC_Type_t,0);( S! n8 u  _) a3 n8 \% Z( A" i8 U4 M
  255. }
    5 T' X) b; y9 H  z
  256. //IIC_Send_Byte,入口参数为要发送的字节8 p6 o$ n+ S$ Y
  257. static void IIC_Send_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t txd)     7 |2 A( C# k/ j, L1 v
  258. {% I2 _( G- ^. R  K) _
  259.      uint8_t t = 0;   
    4 I; |% q; x# a! X2 i( i7 f
  260.      SDA_OUT(IIC_Type_t);      9 {7 j6 D- y5 C: j/ w. z
  261.      IIC_SCL(IIC_Type_t,0);//拉低时钟开始数据传输" e1 r5 U* k, ^, k6 c) X
  262. for(t=0;t<8;t++)) z' R& ~3 L" |" }
  263.      {              1 w  n2 |: m0 V9 o7 a
  264.           IIC_SDA(IIC_Type_t,(txd&0x80)>>7);
    7 {3 g# J+ V( l
  265.           txd <<= 1;   
    ) z6 ]$ l5 V' C3 S
  266.        IIC_Type_t->delay_us(2);     //对TEA5767这三个延时都是必须的
    * g# U6 |- |7 n4 v" v2 @
  267.        IIC_SCL(IIC_Type_t,1);
      s3 Z: f& ^4 s1 e+ l" G
  268.        IIC_Type_t->delay_us(2);  
    9 Q2 Q7 o: ]2 x1 e# w
  269.        IIC_SCL(IIC_Type_t,0);
    ! f2 _8 i- A" d- F" e* G+ b
  270.        IIC_Type_t->delay_us(2);  
    , m/ @9 F& b' l# Q
  271.      }  
    2 p6 D8 a9 M! s# x  e
  272. }8 B! [; @1 Q1 S% y3 h- Q8 }! a
  273. //IIC_Send_Byte,入口参数为是否要发送ACK信号
    ; ?4 A( y6 w* [. |% U
  274. static uint8_t IIC_Read_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t ack)     
    . b9 G: J1 j* U6 Q
  275. {
    0 |3 `+ L; v, N6 G: B5 r
  276.    uint8_t i,receive = 0;
    , C1 l& _' P0 K, x& \' H
  277.    SDA_IN(IIC_Type_t);//SDA设置为输入
    " Q. R; P$ r' t' X! ]
  278. for(i=0;i<8;i++ )
    7 x  q2 N* [0 J! x8 b8 J
  279.    {+ ^) h5 Y- g9 x# }( R* h( q, \
  280.       IIC_SCL(IIC_Type_t,0);   s  E2 @5 Z8 _4 ]) J+ ~
  281.       IIC_Type_t->delay_us(2);
    9 O( l' P7 i5 o7 E" ?
  282.       IIC_SCL(IIC_Type_t,1);
    2 A! ~( F3 M9 W; U# g$ y
  283.       receive<<=1;" Z) i$ k& h% c
  284. if(READ_SDA(IIC_Type_t))receive++;   
    5 N4 a; n* y- G( y) O  W; T8 }+ V
  285.       IIC_Type_t->delay_us(1);
    , k6 Y2 I5 }/ c5 G- H6 j
  286.    }      ) D  @0 A% d  k! @* y" V# u. s
  287. if (!ack)" _. K. t% ]/ ?8 J$ i
  288.          IIC_Type_t->IIC_NAck(IIC_Type_t);//发送nACK
    5 n+ Y  Z5 w3 S; b" L% B
  289. else) s' ^0 |& j. Q7 ]6 ]6 c
  290.          IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK   : A  S- L( L9 S; S  M4 K* ]
  291. return receive;
    7 w  n. y0 B4 M
  292. }2 F) ~3 E# ^. L& }
  293. //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用
    8 a4 s, f: |" R9 W0 u
  294. IIC_TypeDef IIC1 = {" l. C! u3 c6 s
  295.   .GPIOx_SCL = GPIOA,   //GPIO组为GPIOA
    & h- w- v. `+ P& p6 |/ }
  296.   .GPIOx_SDA = GPIOA,   //GPIO组为GPIOA+ |0 J- o$ ?( a' l  z/ r% W. Z
  297.   .GPIO_SCL = GPIO_PIN_5,   //GPIO为PIN51 N; _$ A5 N8 q$ |+ x
  298.   .GPIO_SDA = GPIO_PIN_6,  //GPIO为PIN6
    ! n- B( w/ B/ c/ v  I- u$ z: S
  299.   .IIC_Init = IIC_Init_t,8 q4 l* Q) o2 n$ e1 W0 k
  300.   .IIC_Start = IIC_Start_t,  S5 e! \8 {: q1 u4 C
  301.   .IIC_Stop = IIC_Stop_t,
    - Z' V$ c! N7 K$ \. M2 g
  302.   .IIC_Wait_Ack = IIC_Wait_Ack_t,: A; U( W4 j+ K+ t3 z' ]6 ~
  303.   .IIC_Ack = IIC_Ack_t,
    6 k& r( B, }5 N; S7 q
  304.   .IIC_NAck = IIC_NAck_t,; _' |3 m# S$ T
  305.   .IIC_Send_Byte = IIC_Send_Byte_t,
    . M, @$ r7 L* |2 W) _7 I  {
  306.   .IIC_Read_Byte = IIC_Read_Byte_t,& \+ g# k$ G/ H! f, X$ y, A5 ^3 [
  307.   .delay_us = delay_us     //需自己外部实现delay_us函数- Q" N' O1 d6 w5 `, c% ?
  308. };
复制代码

  J9 F! o/ c3 W
    上述就是IIC驱动的封装,由于没有应用场景暂不测试其实用性,待下面ATC64的驱动缝缝扎黄写完之后一起测试使用。
ATC64XX驱动封装实现
    at24cxx.h头文件主要是类模板的定义,具体如下:
  1. // 以下是共定义个具体容量存储器的容量
    - @3 b' r' {$ y
  2. #define AT24C01  127. [3 N' U+ K/ [. c7 h
  3. #define AT24C02  255
    ; f5 t- w# `. n$ g5 j- T
  4. #define AT24C04  511
    . u: z7 [4 I* w( H: e" I
  5. #define AT24C08  1023
    9 V* m2 T$ j. V. l) H8 g
  6. #define AT24C16  2047
    ; |8 ?, n  I; I+ m* Q* x2 a+ i
  7. #define AT24C32  4095& o/ y: d  [& z8 {
  8. #define AT24C64   8191         //8KBytes
    5 i  L$ J' h* B$ n. j! E4 o
  9. #define AT24C128 163831 x( `. d8 j# U3 p, t
  10. #define AT24C256 32767  
    ; `; f, I4 D+ \" x

  11. ' r4 ^$ O: M; X2 y' [" L. F
  12. //定义AT24CXX类* @. c2 D+ U3 r" T
  13. typedef struct AT24CXX_Type7 G; }& }  D0 H3 V
  14. {& w3 C* f, e. r3 G# u" O5 P) r
  15. //属性- w: \! ~# `- [' e3 W
  16.   u32 EEP_TYPE;           //存储器类型(存储器容量): I4 f& B% S" _+ M9 J
  17. //操作
    ) g! E- U! n% f0 {3 C& Y
  18.   IIC_TypeDef IIC;       //IIC驱动9 h- N$ R3 j" W' B9 r
  19. uint8_t (*AT24CXX_ReadOneByte)(const struct AT24CXX_Type*,uint16_t);  //指定地址读取一个字节
    # b( ^! j- R, t% V) Y, L
  20. void (*AT24CXX_WriteOneByte)(const struct AT24CXX_Type*,uint16_t,uint8_t); //指定地址写入一个字节
    # B9 D: U" @" [, D: r1 N' s3 k3 I$ G3 X
  21. void (*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t); //指定地址开始写入指定长度的数据
    - D) p) l0 ^( G- {+ u
  22. uint32_t (*AT24CXX_ReadLenByte)(uint16_t,uint8_t);   //指定地址开始读取指定长度数据% A% T* y1 O' n/ |) O2 f& }6 t7 @
  23. void (*AT24CXX_Write)(uint16_t,uint8_t *,uint16_t);  //指定地址开始写入指定长度的数据
    ) i6 G" I/ G: K/ E
  24. void (*AT24CXX_Read)(uint16_t,uint8_t *,uint16_t);   //指定地址开始写入指定长度的数据) Y0 S0 p, g: x0 r: s+ S, F; b
  25. void (*AT24CXX_Init)(const struct AT24CXX_Type*); //初始化IIC7 T5 z+ U; c- C5 \+ R, v$ h9 t
  26. uint8_t (*AT24CXX_Check)(const struct AT24CXX_Type*);   //检查器件" P7 s! Z: m3 j9 P3 G9 C/ ^+ h
  27. }AT24CXX_TypeDef;) G5 ^) m2 V4 y  u) c( I) ?
  28. - r6 a2 S/ [0 G7 B0 N% b$ M
  29. extern AT24CXX_TypeDef AT24C_64;     //外部声明实例化AT24CXX对象
复制代码

; W5 K) D" T# z4 x0 V2 @- i0 m
    at24cxx.c源文件主要是类模板具体操作函数的实现,具体如下:
  1. //在AT24CXX指定地址读出一个数据5 o1 t+ t# x0 G$ A9 G+ g0 K; o
  2. //ReadAddr:开始读数的地址  
    7 O8 m$ ~. k' V6 ?3 y- X
  3. //返回值  :读到的数据& X& \# i  ?) v6 t" A4 E
  4. static uint8_t AT24CXX_ReadOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t ReadAddr)
    9 U4 m( G& F( y2 o  x6 C9 H
  5. {      ! D- _# ^# B0 ^5 f* _
  6.   uint8_t temp=0;                          
    & t; c" Y* {7 @
  7.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);  
    : m, z# W9 l7 D
  8. //根据AT的型号发送不同的地址
    7 z$ Z: f' q; F; {0 w
  9. if(AT24CXX_Type_t->EEP_TYPE > AT24C16)
    * N. {! y) g: w. K: Y( Y) O7 p
  10.   {$ [) f: X0 e9 q( f" g8 }4 |
  11.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令0 U# w- \% D: p2 D$ M4 L: [
  12.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    . f* C; e# H8 T8 t/ B" r/ H% g2 a
  13.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//发送高地址     
    7 K7 d, }$ `+ ^
  14.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据     
    ; g+ M# c6 B& `+ l" t4 W3 M
  15.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    $ f* }- }+ A+ N# o
  16.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256);   //发送低地址
    6 @( [+ h% n  @) R
  17.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     
    " {; F+ [' U0 e
  18.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);        
    ! b5 z3 U, n. l% C2 r' L4 ?5 g
  19.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA1);           //进入接收模式      
    ( d7 `* d. x4 J6 e/ c
  20.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);  " R7 N* q- q: g2 C$ P# O! f
  21.   temp=AT24CXX_Type_t->IIC.IIC_Read_Byte(&AT24CXX_Type_t->IIC,0);     
    1 @: P7 X  h' O/ k5 [  Z& y/ z
  22.   AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件     
    " g* x, E. w+ ~* h" p
  23. return temp;
    2 O  z1 b& |) h. r) B# Y
  24. }
    4 E/ ^& }& E8 y8 F8 o* Q& b
  25. //在AT24CXX指定地址写入一个数据: A* |# W8 B+ S2 G- U1 T
  26. //WriteAddr  :写入数据的目的地址   
    % N7 q+ x& n7 n! d* \8 G+ w
  27. //DataToWrite:要写入的数据
    4 Q( }8 F( X* ?+ h
  28. static void AT24CXX_WriteOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t WriteAddr,uint8_t DataToWrite)
    & l% ]! z* d  h' @3 Z- N0 x
  29. {                                9 d) d$ i( S# r) _0 F
  30.    AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);   
    $ ?3 g: T( @: C* x2 y9 a
  31. if(AT24CXX_Type_t->EEP_TYPE > AT24C16)( r6 D% E4 H# r3 R2 d2 q. |/ h, w
  32.   {; W8 C. x! X# K. B
  33.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令
    ; S/ O/ h$ u4 B- W* p
  34.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    , N" p) F" X& V+ h+ D% M3 O
  35.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//发送高地址     9 j6 r3 \# q' b& Z
  36.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据     
    5 ~4 r5 `* y; W1 g/ c$ ~* }
  37.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC); " K/ C3 G+ |- c  K6 ^5 _7 Z
  38.    AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256);   //发送低地址8 c3 V  ^, b: v2 i, m" f9 _
  39.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);               % _  ]2 k$ B1 |& Z
  40.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite);     //发送字节          3 ~/ ~! S# p8 Q. r
  41.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);            
    ) r, B) ^& g; n; g6 ]' t
  42.    AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件
    ; O  ?7 x8 E. n2 S- \
  43. AT24CXX_Type_t->IIC.delay_us(10000);  
    % |' X5 I" R" }  V8 G! ~- K  f) K8 M
  44. }) f- `' O' l( U6 o+ \7 q7 k
  45. //在AT24CXX里面的指定地址开始写入长度为Len的数据# @; F% x: h% K6 Q, X! S: r
  46. //该函数用于写入16bit或者32bit的数据.6 P$ |  `  i1 I2 U
  47. //WriteAddr  :开始写入的地址  
    , ~* z- l7 `  b3 j8 M- N- S# W* `
  48. //DataToWrite:数据数组首地址
    - Y* E; I# H8 T- ?
  49. //Len        :要写入数据的长度2,46 j# |' f; S, e5 i0 a& e% P
  50. static void AT24CXX_WriteLenByte_t(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len)
    # i0 ^& @; N: b3 s6 l
  51. {   9 J* R5 q: W) o3 _) ^$ ^! z# l
  52.   uint8_t t;3 H1 p: I' Y( B+ X" t6 x& u! l- e
  53. for(t=0;t<Len;t++)" Z7 }  k0 h) l. g- u& ^
  54.   {" }# |8 j4 j5 d5 l* S
  55.     AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
    * O, i) X5 y% I% N. F! j" v
  56.   }               
    ) W4 q8 X* o; i7 o
  57. }' o6 Y+ {- i0 }* i+ y! [
  58. //在AT24CXX里面的指定地址开始读出长度为Len的数据
    % w/ `% f. O4 F7 Y# \1 E) M
  59. //该函数用于读出16bit或者32bit的数据.
    & T' E5 I, U3 k3 v$ I
  60. //ReadAddr   :开始读出的地址
    * y; D0 Z% T: x8 H# r- G) ?4 |
  61. //返回值     :数据
    6 e% D5 F! N  i3 W4 Z3 Z
  62. //Len        :要读出数据的长度2,45 @% r* s( o  E/ s: o
  63. static uint32_t AT24CXX_ReadLenByte_t(uint16_t ReadAddr,uint8_t Len)
    2 x; G% o# ]# D* o6 T# F
  64. {   
    ; |1 r# {* F; a' J7 Q+ H/ [
  65.   uint8_t t;" C. C2 n- Y% @$ G( S) s3 m
  66.   uint32_t temp=0;
    2 z6 i2 ^) j  k& S7 r6 O8 O
  67. for(t=0;t<Len;t++). R; X( u0 P3 J6 f, k
  68.   {
      R! G' S/ e( Y- [' H  H1 X; ?3 e, @
  69.     temp<<=8;- Q: a4 V) Z! U% e- t
  70.      temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);         
    ) y. g" ?$ @8 @& [8 i
  71.   }
    % y0 y/ z, G+ R3 k' p2 `, w
  72. return temp;               
    : Z: v5 u( h, I5 I; I
  73. }9 ^8 P. F& [9 p* u3 W$ A2 J! `
  74. //在AT24CXX里面的指定地址开始写入指定个数的数据
    ; i2 C7 m# W! u  @3 S
  75. //WriteAddr :开始写入的地址 对24c64为0~8191
    0 U0 t* R+ Y; _4 r1 P
  76. //pBuffer   :数据数组首地址
    ; A, L' C- ~  |( E5 J9 r
  77. //NumToWrite:要写入数据的个数- k+ k" Q1 u' s+ q3 M0 |( `; U2 M
  78. static void AT24CXX_Write_t(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)! i6 {( Y* _0 r: Q' @* P# h
  79. {. r% r$ ^/ z5 m, L& G$ V
  80. while(NumToWrite--)
    2 j, p9 I6 R. Q5 y5 k' T
  81.   {. u" W, l7 r% y, G4 `8 I1 c( M
  82.    AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    5 q7 M" c* I+ x, L8 v3 b! d0 a3 i
  83.     WriteAddr++;# _% Y! [; E/ I' q
  84.     pBuffer++;& y6 f: I7 c2 k% U  |0 x* H
  85.   }
    8 o  s0 T( B$ s! u* S
  86. }
    # t7 V0 b2 {4 c0 ?3 Y
  87. //在AT24CXX里面的指定地址开始读出指定个数的数据% ?  I; K0 x% ]
  88. //ReadAddr :开始读出的地址 对24c64为0~8191
    % @3 X& {/ r/ A8 D/ f
  89. //pBuffer  :数据数组首地址. b$ x. I/ I3 l( B( n0 `/ u) W8 p
  90. //NumToRead:要读出数据的个数$ U6 ~4 }+ ~( R5 E5 [
  91. static void AT24CXX_Read_t(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead)9 j  w1 r" }( Q+ F% \" l
  92. {
    4 g- K/ R1 ~% b' h' P! z7 o
  93. while(NumToRead)
    ( Y+ x. U% w( X; [* V( O& m
  94.   {8 ^/ Z3 t6 }9 ^$ _+ N
  95.     *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    # E3 m; A: \4 S; H5 W
  96.     NumToRead--;
    + N6 [  |- I. A. p% \9 Q8 Z, H  Z
  97.   }
    * B7 P6 E1 M3 ^( a
  98. }
    6 X" m3 r0 S3 H" v
  99. //初始化IIC接口1 _2 q4 y0 A3 V) q
  100. static void AT24CXX_Init_t(const struct AT24CXX_Type* AT24CXX_Type_t)) c5 E, L8 H( S+ y2 h+ G$ x
  101. {) g; K7 O2 T, ^
  102.   AT24CXX_Type_t->IIC.IIC_Init(&AT24CXX_Type_t->IIC);//IIC初始化
    4 N) u* \; b! F1 c6 l2 R* `: a
  103. }/ [; d, d# E# A; O9 j0 p  E2 t
  104. //检查器件,返回0表示检测成功,返回1表示检测失败: ?7 R  Y" O! o7 G7 @( Z2 u* l
  105. static uint8_t AT24CXX_Check_t(const struct AT24CXX_Type* AT24CXX_Type_t)   " O* U$ y9 S1 j
  106. {
    4 y) H% s, o* d0 f* A. ]* U7 G. ~
  107. uint8_t temp;5 M! L+ k9 g' f8 ^  `7 M% ^! P
  108.   temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);//避免每次开机都写AT24CXX      
    . m0 S: y1 r, J0 h7 Z
  109. if(temp == 0X33)return 0;     1 E8 ^  P& @$ ]+ s. W8 A' _
  110. else//排除第一次初始化的情况
    9 \8 T" c, \6 |9 y* p
  111.   {
    7 {, J! \* f9 X9 R& B4 x
  112.       AT24CXX_Type_t->AT24CXX_WriteOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE,0X33);
    3 k3 h, {* {  Y/ ~! H5 r
  113.        temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);3 c3 Y6 o$ U6 L  M( D( B8 s5 y
  114. if(temp==0X33)return 0;
    . [9 d+ i; ]: g% R! ~
  115.   }
    3 k4 y# Z- R  \& l+ Q; b# e
  116. return 1;  
    4 a2 b- C0 t. L
  117. }  I/ e0 |1 |8 g5 \) Y2 U
  118. //实例化AT24CXX对象
    4 `: m3 s" b" w& v! v- c
  119. AT24CXX_TypeDef AT24C_64={
    ' m& l' q0 h2 E2 w
  120. .EEP_TYPE = AT24C64,           //存储器类型(存储器容量)
    3 }% C, V- p0 P; V( N# A" l3 L
  121. //操作
    2 ?1 w1 E! ?/ U% x9 ~1 A
  122. .IIC={/ r/ ^# G% b6 h, B; t& p" {) m# y' s
  123.   .GPIOx_SCL = GPIOA,
    1 o) V0 ?( Y! X/ Z1 h- f
  124.   .GPIOx_SDA = GPIOA,/ ?& R5 F1 M" v' m
  125.   .GPIO_SCL = GPIO_PIN_5,  b/ C* J2 c4 w( @
  126.   .GPIO_SDA = GPIO_PIN_6,
      j, l3 \/ c$ a1 W" W( l/ L; e8 a9 ^
  127.   .IIC_Init = IIC_Init_t,
    ; ~- J% Q' R1 ?5 n! `2 k
  128.   .IIC_Start = IIC_Start_t,2 F1 ^$ A* {2 A2 w3 Z* R
  129.   .IIC_Stop = IIC_Stop_t,
    1 r. g3 x2 ^# S- q; i* ]6 C
  130.   .IIC_Wait_Ack = IIC_Wait_Ack_t,
    7 H) M8 n& I1 F% b
  131.   .IIC_Ack = IIC_Ack_t,- O9 {. Y3 b* ]2 B$ h8 Q4 O
  132.   .IIC_NAck = IIC_NAck_t," H+ f9 |/ t4 l2 d7 g# K
  133.   .IIC_Send_Byte = IIC_Send_Byte_t,' M0 c' S3 x, m2 S, S) t6 J" \1 I
  134.   .IIC_Read_Byte = IIC_Read_Byte_t,8 D* T/ c6 P% t. U9 r( P
  135.   .delay_us = delay_us
    ; ]6 r3 `( ?- G; Z/ `! ^* e- U
  136. },                   //IIC驱动
      V6 F* O# V4 B
  137. .AT24CXX_ReadOneByte = AT24CXX_ReadOneByte_t,  //指定地址读取一个字节% N; V; r8 b3 v% s" _! M/ F
  138. .AT24CXX_WriteOneByte = AT24CXX_WriteOneByte_t,//指定地址写入一个字节" m0 g4 X1 y# T" {* P. b
  139. .AT24CXX_WriteLenByte = AT24CXX_WriteLenByte_t, //指定地址开始写入指定长度的数据, y# ?- i+ C, Z7 V" ]2 q
  140. .AT24CXX_ReadLenByte = AT24CXX_ReadLenByte_t,   //指定地址开始读取指定长度数据7 v/ b0 M* a6 ]  r- N% j( {
  141. .AT24CXX_Write = AT24CXX_Write_t,  //指定地址开始写入指定长度的数据3 f7 Y% _! \" `
  142. .AT24CXX_Read = AT24CXX_Read_t,   //指定地址开始读取指定长度的数据$ f3 c3 K5 |+ J, |9 j! J
  143. .AT24CXX_Init = AT24CXX_Init_t, //初始化IIC
    ! J+ n! H& L! j. j
  144. .AT24CXX_Check = AT24CXX_Check_t   //检查器件
    / |* t1 e. s# i* h- r
  145. };
复制代码
5 @: g# v& V( I8 G) ~& R8 Z
    简单分析:可以看出AT24CXX类中包含了IIC类的成员对象,这是一种包含关系,因为没有属性上的一致性因此谈不上继承。
    之所以将IIC的类对象作为AT24CXX类的成员是因为AT24CXX的实现需要调用IIC的成员方法,IIC相当于AT24CXX更下层的驱动,因此采用包含关系更合适。
    因此我们在使用AT24CXX的时候只需要实例化AT24CXX类对象就行了,因为IIC包含在AT24CXX类中间,因此不需要实例化IIC类对象,对外提供了较好的封装接口。下面我们看具体的调用方法。
% i2 P. W& U# X8 W1 @
主函数main调用测试
    在main函数中直接使用AT24C_64来完成所有操作,下面结合代码来看:
  1. #include "at24cxx.h"    //为了确定AT24C_64的成员方法和引用操作对象AT24C_64# j( q' x+ G- k* R4 j+ j7 Z. o
  2. int main(void)
    2 x! a4 c8 x2 l% g1 ]
  3. {. L4 Z; Q* L& G/ ]7 u# [" f' x
  4. /************省略其他初始化工作****************/9 A+ _4 M2 q) P6 `3 w# W# p. q0 u
  5. //第一步:调用对象初始化方法来初始化AT24C64% _  V* k8 `& i
  6.   AT24C_64.AT24CXX_Init(&AT24C_64);" _; J( v8 M" T. ^) v
  7. //第二步:调用对象检测方法来检测AT24C64           
    2 U" ^8 d6 W0 f
  8. if(AT24C_64.AT24CXX_Check(&AT24C_64) == 0)
    ! U! a% g, D1 q1 Q4 k
  9.   {, G7 \" l- T/ N5 {+ F7 }
  10. printf("AT24C64检测成功\r\n");- S- z) l! c, p# x4 E
  11.   }9 i$ W: I2 N! g, @! e% \4 j2 C: \$ M
  12. else{8 ~4 \' D: ^& y
  13. printf("AT24C64检测失败\r\n");% r7 E& s+ W) B+ q
  14.   }- H% r5 u1 |( `
  15. return 0;# G* V' ?$ E/ o5 _) M
  16. }
复制代码
4 `% R3 f; x& B1 w' j- C0 p* W
    可以看出所有的操作都是通过AT24C_64对象调用完成的,在我们初始化好AT24C_64对象之后就可以放心大胆的调用其成员方法,这样封装的好处就是一个设备对外只提供一个对象接口,简洁明了。
: o6 {; z3 D. ]8 R: C
总结
    本文详细介绍了面向对象方法实现IIC驱动封装以及AT24CXX存储器的封装,最终对外仅提供一个操作对象接口,大大提高了代码的复用性以及封装性。
+ N0 r/ g* O$ s3 J$ A

! ]1 s. ]3 F8 K& J  R
赞 收藏 评论0 发布时间:2022-6-7 09:41

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版