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

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

[复制链接]
STMCU小助手 发布时间:2022-6-7 09:41
简述
    IIC(Inter-Integrated Circuit)其实是IICBus简称,它是一种串行通信总线,使用多主从架构,在STM32开发中经常见到。
    使用面向对象的编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备时只需要实例化一个IIC对象即可,本文是基于STM32和HAL库做进一步封装的。
    底层驱动方法不重要,封装的思想很重要。在完成对IIC驱动的封装之后借助继承特性实现AT24C64存储器的驱动开发,仍使用面向对象的思想封装AT24C64驱动。
$ I2 ?# i: V4 g) q: G
IIC驱动面向对象封装
    iic.h头文件主要是类模板的定义,具体如下:
  1. //定义IIC类
    + F1 I5 d- a/ f" A6 n
  2. typedef struct IIC_Type; w- m+ P' R: f6 _# e' A
  3. {8 u" n9 T2 ?9 ?' \( {$ J. S
  4. //属性8 t$ p  w+ h+ V% f. a
  5.    GPIO_TypeDef  *GPIOx_SCL;  //GPIO_SCL所属的GPIO组(如:GPIOA)$ G7 c5 G4 T% B: a6 I
  6.    GPIO_TypeDef  *GPIOx_SDA;  //GPIO_SDA所属的GPIO组(如:GPIOA)( N' U6 |$ A& E- ^- |
  7. uint32_t GPIO_SCL;     //GPIO_SCL的IO引脚(如:GPIO_PIN_0)& e/ l* W* W4 T) y3 E
  8. uint32_t GPIO_SDA;     //GPIO_SDA的IO引脚(如:GPIO_PIN_0)
    . d4 q  |* Y! S  ^* L& L8 X
  9. //操作% d9 B; c" T; `# r3 I6 h$ E
  10. void (*IIC_Init)(const struct IIC_Type*);        //IIC_Init
    ; ~4 Z1 t+ V9 E1 w) m. u
  11. void (*IIC_Start)(const struct IIC_Type*);       //IIC_Start
    6 H8 E( Q; W' Q; g8 I
  12. void (*IIC_Stop)(const struct IIC_Type*);        //IIC_Stop* c4 _* k/ D( _; n8 D/ G
  13. uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*);    //IIC_Wait_ack,返回wait失败或是成功
    ' O  N0 p+ f. v) c" U6 d
  14. void (*IIC_Ack)(const struct IIC_Type*);       //IIC_Ack,IIC发送ACK信号
    2 O+ v  H) E# w
  15. void (*IIC_NAck)(const struct IIC_Type*);       //IIC_NAck,IIC发送NACK信号; u5 U; J, q: |
  16. void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t);       //IIC_Send_Byte,入口参数为要发送的字节' U7 s" k! G- g4 Q  f8 |; E
  17. uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t);     //IIC_Send_Byte,入口参数为是否要发送ACK信号9 V- x% h9 L+ T) p/ T7 K* S
  18. void (*delay_us)(uint32_t);              //us延时, ?- R# ~+ A( v
  19. }IIC_TypeDef;
复制代码
- D6 U/ W8 L& w+ i  L

# A4 i4 k. q. t% c3 l) miic.c源文件主要是类模板具体操作函数的实现,具体如下:% L9 ^4 l  u# Q# a, y
  1. //设置SDA为输入模式  h; @. V6 U5 e9 j& L+ |4 A9 m
  2. static void SDA_IN(const struct IIC_Type* IIC_Type_t)8 X1 K" s% b( d  m9 l1 J
  3. {
    ! T5 n- k/ U* x+ J5 i
  4.   uint8_t io_num = 0;  //定义io Num号& k& `  E) L7 w4 h9 F9 v8 {
  5. switch(IIC_Type_t->GPIO_SDA)& L% O, L1 `4 K" o& R9 y
  6.   {' j7 h0 ^7 }+ _
  7. case GPIO_PIN_0:2 i' u: k& I& d
  8.     io_num = 0;' Q; o+ F8 }; p9 n% a$ X: U
  9. break;/ @( `6 N% n7 |- U& j$ F
  10. case GPIO_PIN_1:
    8 @: c7 Y& @. ^$ s
  11.     io_num = 1;
    2 g4 e' i# Z# c9 H4 \$ b7 j  o) j
  12. break; 1 x6 K7 H' m9 O. y. i7 [9 v; P
  13. case GPIO_PIN_2:9 A& y0 N6 b. e( h7 w3 d
  14.     io_num = 2;) f3 k/ \2 T, H) |: T4 B
  15. break;
    5 K% C7 q+ x: D7 u$ F
  16. case GPIO_PIN_3:4 \" n- @1 |+ \' W& e
  17.     io_num = 3;
    8 H: I4 X/ N; F: m
  18. break;
    , t- W1 o% v) e# b& k
  19. case GPIO_PIN_4:
    8 d3 j# Q& x% ~6 }) l
  20.     io_num = 4;. b9 s! n1 q  h; z
  21. break;
    * k7 K" v2 v) E' n# A# Y7 U
  22. case GPIO_PIN_5:- i9 U+ ~7 ~! o. L+ t; r: n$ o, h+ u4 D! `
  23.     io_num = 5;
      B; y! i/ a6 I' W. F; b, `  J" a1 X7 y
  24. break;
    2 @6 j& D4 d4 u4 c5 c
  25. case GPIO_PIN_6:
    , [2 b! a: e) l8 v8 Q% v2 T6 E
  26.     io_num = 6;) R; [! f1 Z# {# c( y6 X
  27. break;
    3 |) L& C/ ~2 c/ ~4 j( f# m
  28. case GPIO_PIN_7:
    8 Z" z+ |1 K/ B3 `3 S5 r
  29.     io_num = 7;
    : s; o5 }7 P9 \3 k
  30. break;
    / u* X( u* H2 t- e& e! a
  31. case GPIO_PIN_8:# P1 z! Z" I5 z+ _! i) z( x
  32.     io_num = 8;9 X+ B5 }* q* @$ ~' K( O
  33. break;
    % ~  ~. P4 ?' ^! x6 f8 O( }! L; @% }
  34. case GPIO_PIN_9:
    6 ]- r1 I- v6 Q/ d  a+ k
  35.     io_num = 9;  S4 |7 O! k$ j0 p: F7 S
  36. break;
    # }+ B  f8 k1 A0 P+ q# c* P) X! U% D
  37. case GPIO_PIN_10:3 C( R7 v! Y% I% n4 x% \7 P( G
  38.     io_num = 10;
    + @) y% _5 Z: C- K
  39. break;
    ) J8 }# p+ I% ]" \& i6 K
  40. case GPIO_PIN_11:
    * x0 r3 [2 o  @$ p4 h
  41.     io_num = 11;
    + J9 o' m" a0 h- b% l1 y) y0 W
  42. break; 6 I) R$ A5 ]; M1 X  J
  43. case GPIO_PIN_12:
    4 q7 |, u3 E3 k, a
  44.     io_num = 12;" Q. f! U* O. N* J. ]
  45. break;! Y# K0 i9 k& Y
  46. case GPIO_PIN_13:
    4 |9 V8 ?' [' \( Z$ p0 U* D6 C6 B
  47.     io_num = 13;
    4 o1 |4 e3 y7 w( N; m6 E
  48. break;
    4 M" x0 ]! f9 B- C7 H* r7 r
  49. case GPIO_PIN_14:" G0 E! e; _5 y. q. d) D
  50.     io_num = 14;0 U( `, j& e- l& ^3 j
  51. break;
    ) t! t: Q6 a& ^: O0 P, Z' M
  52. case GPIO_PIN_15:; d9 |# h2 C9 T) }$ R: A$ G
  53.     io_num = 15;
    1 x7 _% s  B- ^2 P$ _. X. Q* @
  54. break;
    " P) X' K5 }% |6 ^
  55.   }
    $ w: z8 D) z& b
  56.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零
    , \9 L9 U! Q6 J8 z+ \( c
  57.   IIC_Type_t->GPIOx_SDA->MODER|=0<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输入模式
    0 e& o3 R3 _6 \. u; W; z
  58. }3 m9 g0 ]/ L& P. k$ W& H

  59. 4 J8 A2 I, m. P( @2 H
  60. //设置SDA为输出模式
    9 Q+ F' U/ P) W. u
  61. static void SDA_OUT(const struct IIC_Type* IIC_Type_t)
    * ]; b/ `  S; e# X% r
  62. {
    6 |( c3 o1 `% G0 v! R8 j6 j9 b
  63.   uint8_t io_num = 0;  //定义io Num号
    6 G2 X5 P; |$ G! d4 d
  64. switch(IIC_Type_t->GPIO_SDA)
    6 l4 ?1 |  R: S, \1 o9 o
  65.   {1 \- x" r0 S: v' T+ b
  66. case GPIO_PIN_0:
    * Z6 s8 Q) X/ ]2 P- O' q$ G3 M7 R# c3 l
  67.     io_num = 0;0 C$ n  w) O: S" C5 A# k6 v; S
  68. break;
    ! r1 y7 s( P. b+ Y3 v8 Z
  69. case GPIO_PIN_1:
    + O; B* {: k6 a, k' O4 N/ m  f/ L
  70.     io_num = 1;, M2 Z4 q* M9 w( A
  71. break; 5 i$ V$ u) \! u0 g4 F  T
  72. case GPIO_PIN_2:
    , s( l  @6 _' |; P3 n
  73.     io_num = 2;' r0 G6 S3 n7 |2 F& v9 }2 z
  74. break;
    3 ?3 X; h2 Q$ I- L5 Z$ P, n
  75. case GPIO_PIN_3:
    4 A. x2 ~# }6 Z' g/ k
  76.     io_num = 3;% B6 J/ e& M' S: R1 \3 U: w( ~# L
  77. break;* x8 C! T6 N% L" B8 t* Q
  78. case GPIO_PIN_4:9 X8 ^% X4 w+ ~5 s
  79.     io_num = 4;
    $ k& P' a$ q  {$ x+ o
  80. break;
    . H, F+ p# E' `9 s% K7 d4 t8 Z& C
  81. case GPIO_PIN_5:
    * Y8 J. M- L' n5 j4 ]
  82.     io_num = 5;) s$ F  f5 h& t* f* J+ O% ^$ |6 ?
  83. break;
    ) ]( \& }. \- k
  84. case GPIO_PIN_6:
    8 w1 B% [# C# `, o& a- g, I
  85.     io_num = 6;
    ( H! |9 |5 T. t  X- A4 j2 K4 A
  86. break;
    ( o! i# }$ M; \9 \6 h
  87. case GPIO_PIN_7:
    , G- N4 M9 V/ \4 S
  88.     io_num = 7;
    4 W: s2 a4 h, g# B5 _
  89. break;
    . L1 _# Q5 O$ w$ G* k1 d8 z
  90. case GPIO_PIN_8:' b+ L  q7 Q# S& V/ F
  91.     io_num = 8;& V! `) ?3 n: `7 `, a: N
  92. break; 5 a5 R. I3 Q) M2 [6 {: h! }/ c
  93. case GPIO_PIN_9:' E: }" |- x; E
  94.     io_num = 9;% a1 S1 d# M4 S2 {& L0 v( q
  95. break;# p  d& h. O; Y* s4 J
  96. case GPIO_PIN_10:
    : `: V4 E5 b" W+ L# z7 k# }# y
  97.     io_num = 10;) q* L4 B' {- ~4 v. R' c, e
  98. break;
    2 y. T5 V( m8 B' ?0 i9 @
  99. case GPIO_PIN_11:; t( i" ?% q; V
  100.     io_num = 11;
    7 n" J9 m: n, r8 o1 R" e
  101. break; 2 N$ y, h7 w4 i' C0 p2 v  r
  102. case GPIO_PIN_12:) U2 x; y/ T/ S, A+ N* y
  103.     io_num = 12;+ Q* y/ e* h+ U6 W) Q" b; q
  104. break;
    0 @1 P7 t# R9 U3 L
  105. case GPIO_PIN_13:
    3 O- K$ h0 `( w) }7 m
  106.     io_num = 13;) }( A9 |1 V! v8 h
  107. break;; v  E+ |! B/ W  |) D% j! f
  108. case GPIO_PIN_14:. J; L4 }) {$ p
  109.     io_num = 14;
    9 p& s7 r/ s  H9 A
  110. break;
    # G4 b# m1 V9 v7 i& E3 F
  111. case GPIO_PIN_15:3 ]' L" Q% x& D# `7 x8 a
  112.     io_num = 15;
    4 C0 r- w+ x3 T
  113. break;$ j9 }, @1 O  C1 l( |: c+ n
  114.   }! [6 w' }% _1 z9 g% d
  115.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零
    4 y2 y" C* w3 ~3 t$ p6 v
  116.   IIC_Type_t->GPIOx_SDA->MODER|=1<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输出模式) e$ W  C4 s; y! U& o8 O: b
  117. }3 O8 b4 R' S1 p# c. b* d
  118. //设置SCL电平0 S; _, |# u2 K. \
  119. static void IIC_SCL(const struct IIC_Type* IIC_Type_t,int n), X( }- J; @  i- E4 v
  120. {9 X+ Y* ]3 v2 u& p4 f! h/ n
  121. if(n == 1)
    - [( }+ O# `% B0 h1 {
  122.   {
    1 V( ]) [6 c% D+ Q; w, T/ k& A: E
  123.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_SET);     //设置SCL为高电平
    ) c  a( s5 c% d1 p8 u
  124.   }0 i0 }% p* f2 _5 T0 S4 z4 ?
  125. else{
    ; [% E5 ?* _  {# E3 {9 [
  126.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET);     //设置SCL为低电平
    ' e) |* N: E1 H/ }
  127.   }8 A' `+ U' [* b! ~* Y7 _
  128. }
    8 ]/ f1 L" ~& M
  129. //设置SDA电平( d7 X$ G* M: y( O' D) r( B
  130. static void IIC_SDA(const struct IIC_Type* IIC_Type_t,int n)
      N3 z' w9 p% t8 Y, N
  131. {
    $ I$ P. H6 c* {% H5 s2 L1 A
  132. if(n == 1)
    % n8 d0 G8 t  q6 {
  133.   {5 Z' _# z/ o8 V# o3 Y! n: _
  134.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_SET);     //设置SDA为高电平% G" B* E% U, _# R2 E- l
  135.   }
    ) s( h7 G! _, @$ F$ A/ _
  136. else{/ P6 Y; C  e: e9 D0 t- ^9 z
  137.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET);     //设置SDA为低电平
    9 X; d+ O/ Y: d! `9 p7 `
  138.   }* ]& d3 m0 a1 f; K+ i1 l
  139. }' j( q. [  W3 R$ [5 p3 ^$ g; |! _' i
  140. //读取SDA电平. G) k4 g9 ?( c( u5 j1 P+ V* p
  141. static uint8_t READ_SDA(const struct IIC_Type* IIC_Type_t)$ j, ]. o! t3 z/ o! M
  142. {
    8 W1 \1 a; Y, G$ `1 A% P
  143. return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA);  //读取SDA电平
    $ |4 M1 V+ L! }  |7 l) K# b, w
  144. }" i+ B; M; B* [6 [5 v' v
  145. //IIC初始化3 p3 n( \' x5 j
  146. static void IIC_Init_t(const struct IIC_Type* IIC_Type_t)7 l% E% n) }0 D0 i% P7 t$ C+ ~. F7 ^
  147. {
    / E0 l8 N$ q: y7 i- ~
  148.       GPIO_InitTypeDef GPIO_Initure;
    ' c3 \% |! b8 Y8 a% I

  149. . r7 R+ s1 C- T/ E
  150. //根据GPIO组初始化GPIO时钟6 g( q- U  y8 L: t% X
  151. if(IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)% }% L4 H( l8 l5 P5 f$ A+ g
  152.    {, d3 Q! h4 y0 r# z" H* V9 Q: e
  153.      __HAL_RCC_GPIOA_CLK_ENABLE();   //使能GPIOA时钟
    7 [" y$ f: d: l# i8 z, `9 g
  154.    }
    3 z2 z$ O- r; ?# |, \9 J
  155. if(IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)" n  F4 S! }/ }/ ^. P1 [
  156.    {( A+ j8 I  d4 `# A
  157.      __HAL_RCC_GPIOB_CLK_ENABLE();   //使能GPIOB时钟3 C" j, L7 e2 F; f
  158.    }
    ! B/ q7 U; W; ^+ Q  M6 y! O
  159. if(IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)
    - u- u$ a5 G% w
  160.    {2 Q2 H! R& T, _+ S5 ]
  161.      __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟  A7 l% }, Y% s* u/ x5 X
  162.    }) @3 m% j6 ]4 |. f/ j
  163. if(IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)
    # v2 A- B' [1 x+ H
  164.    {! X+ U7 ]4 g) V5 v- L9 P1 M
  165.      __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD时钟
    . b1 r& U, R0 o. j# r- v
  166.    }0 o4 `$ y1 p/ D( N. H+ @! j
  167. if(IIC_Type_t->GPIOx_SCL == GPIOE || IIC_Type_t->GPIOx_SDA == GPIOE)
    : m- b2 \# ^: P/ v7 f
  168.    {
    , [' h# ^5 t9 V
  169.      __HAL_RCC_GPIOE_CLK_ENABLE();   //使能GPIOE时钟0 w0 a# F3 w% u2 M% P5 l; i0 _
  170.    } 2 U- ?' U+ H$ K+ |1 C
  171. if(IIC_Type_t->GPIOx_SCL == GPIOH || IIC_Type_t->GPIOx_SDA == GPIOH). K% J, ~% K: L. |4 A" N
  172.    {
    9 |4 \% n: Q' F/ ?8 P6 x
  173.      __HAL_RCC_GPIOH_CLK_ENABLE();   //使能GPIOH时钟
    - b9 ^" J( l8 f) h
  174.    }     3 |$ N" j! Y( I# r* W( w
  175. 2 ^9 M" D- m: n3 m% _* A8 ?& s, d0 c+ ^5 j
  176. //GPIO_SCL初始化设置  u$ ^' t, q% F
  177.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SCL;: [2 {! S; S3 b( m# i9 m; ]3 `
  178.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出% B6 y2 E/ Z# y, Y; [+ a) `" t- p
  179.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    0 r& @' R$ d- e
  180.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速( R7 T' n. s) u! _& `* y- ^
  181.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL,&GPIO_Initure);
    , a6 D# L& i3 p! x8 G% Z! r7 _
  182. //GPIO_SDA初始化设置
    # h' J: \" [2 L4 ^# t0 h; Q
  183.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SDA;+ a# G6 D1 h: k: C, D
  184.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    4 M# G  d7 b+ g1 o4 _
  185.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    # Y9 Q$ U9 ]8 \. x% Q
  186.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速( O( S0 f" Q' d9 I0 [+ z) u
  187.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA,&GPIO_Initure);
    6 [! w+ G0 L, l$ Q% p% t" b
  188. $ z* E, x# ~) X! b4 G
  189. //SCL与SDA的初始化均为高电平& k" n3 k. ?' L+ d
  190.       IIC_SCL(IIC_Type_t,1);
    3 e9 g6 s7 _" Y2 Y8 o
  191.        IIC_SDA(IIC_Type_t,1);
    4 D1 V7 |( W+ H; |
  192. }
    6 @! r- i% ?3 r. Y
  193. //IIC Start$ g4 V, C' f* s* _
  194. static void IIC_Start_t(const struct IIC_Type* IIC_Type_t)
    2 T! ^. o6 g3 I" e
  195. {
    4 N4 d" d8 f& M$ T. `+ Z
  196.   SDA_OUT(IIC_Type_t);      //sda线输出
    & y0 q" N! }0 T! x
  197.   IIC_SDA(IIC_Type_t,1);      
    & N. _4 Z5 j( U3 ~
  198.   IIC_SCL(IIC_Type_t,1);( K( [. o7 p6 B8 z% A
  199.   IIC_Type_t->delay_us(4);! Z% L; b" i3 l( Z. L3 s& Q
  200.    IIC_SDA(IIC_Type_t,0);  //START:when CLK is high,DATA change form high to low 4 N( u8 I* E$ Q1 V/ B& \1 j* v" j
  201.   IIC_Type_t->delay_us(4);7 ~, O: U* r- R! O% @0 p* c  u1 E
  202.   IIC_SCL(IIC_Type_t,0);  //钳住I2C总线,准备发送或接收数据 7 S% R& W) o6 B- Y
  203. }2 G# D$ L  p! e+ p$ t8 {
  204. //IIC Stop5 E2 I& @* j0 Q3 I4 j, P
  205. static void IIC_Stop_t(const struct IIC_Type* IIC_Type_t)9 h, D6 r7 q- s" U" V/ j
  206. {
    ) L& m: B* g2 V# i& I. n+ I" `  \
  207.   SDA_OUT(IIC_Type_t); //sda线输出% j& B( B0 R8 F1 O/ C+ C
  208.   IIC_SCL(IIC_Type_t,0);  v0 D) q! l9 y
  209.   IIC_SDA(IIC_Type_t,0); //STOP:when CLK is high DATA change form low to high3 |% c/ Y8 j6 M7 W4 f, ~4 y
  210.    IIC_Type_t->delay_us(4);- g. C. F3 S9 J) z+ \$ M
  211.   IIC_SCL(IIC_Type_t,1); 0 J% B  ?/ x2 p% A( K2 X( E
  212.   IIC_SDA(IIC_Type_t,1); //发送I2C总线结束信号# C: t4 `1 [, c/ u1 L! W- o2 L/ h/ U
  213.   IIC_Type_t->delay_us(4);
    . }9 W$ m8 T( Z) @
  214. }4 Z. C( ], D: t
  215. //IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
    : W8 X# w! j5 A9 k+ U8 a$ |1 [: |
  216. static uint8_t IIC_Wait_Ack_t(const struct IIC_Type* IIC_Type_t)   //IIC_Wait_ack,返回wait失败或是成功
    4 ]6 w% f9 a4 D! D3 p; K
  217. {
    1 |3 p* d* Z; d$ N. }: J( X
  218.   uint8_t ucErrTime = 0;
    5 e  O! r3 M0 q
  219.   SDA_IN(IIC_Type_t);      //SDA设置为输入  % ?. k$ S, p9 [3 }+ J
  220.   IIC_SDA(IIC_Type_t,1);IIC_Type_t->delay_us(1);   
    ! x# u6 `$ w3 ]$ b
  221.   IIC_SCL(IIC_Type_t,1);IIC_Type_t->delay_us(1);5 {- }! \" S! V" K+ p& _: U2 N7 w
  222. while(READ_SDA(IIC_Type_t))
    7 _& P# H! |" z3 U: s  m
  223.   {
    7 N- P! j* Z, C& U; B% i+ Y
  224.     ucErrTime++;
    0 b' M; V, p8 f! c9 c
  225. if(ucErrTime>250)- [4 _' ?+ Q- Y0 g- H
  226.     {
    7 h+ m+ F7 P! F2 j& ?6 p' a
  227.       IIC_Type_t->IIC_Stop(IIC_Type_t);
    ; u- ?3 s: D% A, Z, X7 e
  228. return HAL_ERROR;
    ' A9 _6 ~2 G' q( q* r
  229.     }
    . Y& t; H$ @+ q- Z! E
  230.   }3 [. y' c' m4 z8 A$ @& u
  231.   IIC_SCL(IIC_Type_t,0);//时钟输出0     
    3 v" U9 h' p5 w, L( V2 u
  232. return HAL_OK;  
    3 Z# A3 v: v7 X8 Y( k- q  l
  233. }+ u: o+ o- X: i. O2 k" r
  234. //产生ACK应答
      l) e% f- A2 w+ h+ x
  235. static void IIC_Ack_t(const struct IIC_Type* IIC_Type_t)      
    ) m, `- |9 W1 Y0 {9 x
  236. {; |" i8 k. e" w  T' B. `% W3 i
  237.   IIC_SCL(IIC_Type_t,0);9 G6 P8 G: e8 V! y9 u- e  D% P3 ]9 u/ X
  238.   SDA_OUT(IIC_Type_t);% Z4 e, U& p5 k' k" B8 O6 o
  239.   IIC_SDA(IIC_Type_t,0);! ^; R- t" Y2 j$ n
  240.   IIC_Type_t->delay_us(2);  1 q- D8 n- o; F7 ?+ W) U! P# `- m
  241.   IIC_SCL(IIC_Type_t,1);
    . u, i) g1 b) ^& j- b! a* j
  242.   IIC_Type_t->delay_us(2);  & h+ ~5 v: H1 {5 t8 F- a3 G
  243.   IIC_SCL(IIC_Type_t,0);; y- ~, `7 ^, d5 T- k- I4 N
  244. }/ ^9 K2 k) K/ O, W9 S2 }
  245. //产生NACK应答
    7 A* f* H) m/ N
  246. static void IIC_NAck_t(const struct IIC_Type* IIC_Type_t)      
    4 }0 K. }: U* g  x; H* `* k2 J
  247. {% M7 B% N/ p* j* m
  248.   IIC_SCL(IIC_Type_t,0);
    9 P. C4 Z) e1 }2 g* d
  249.   SDA_OUT(IIC_Type_t);
    3 K% T1 E& b+ M9 r. S, q
  250.   IIC_SDA(IIC_Type_t,1);
    ) z/ Y0 }9 F8 E: L2 w4 ^& W. D
  251.   IIC_Type_t->delay_us(2);  1 F5 s4 C+ i  {& B9 J/ z! u7 M3 S
  252.   IIC_SCL(IIC_Type_t,1);
    6 i, B+ N$ N* r  a  g' V3 `1 e
  253.   IIC_Type_t->delay_us(2);  
    ! l4 f4 }: v: ?* j
  254.   IIC_SCL(IIC_Type_t,0);
    - M2 e0 A$ d% M: j
  255. }
    3 g# g0 k1 W5 {) d5 S# D+ g
  256. //IIC_Send_Byte,入口参数为要发送的字节
    - i4 L) a3 `1 g1 X! c
  257. static void IIC_Send_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t txd)     
    5 i4 S/ o) b, \9 x& b# \( ~& _
  258. {
    ( R! B/ u6 ?2 [3 g$ ]0 B
  259.      uint8_t t = 0;   5 n! O& R, P+ `2 V
  260.      SDA_OUT(IIC_Type_t);      
    7 l# n- \7 z) v* S, ?( `+ a
  261.      IIC_SCL(IIC_Type_t,0);//拉低时钟开始数据传输
    , H* K# H9 F) A
  262. for(t=0;t<8;t++)& w) ^" w& _4 L* g  c8 A1 O" v/ p; N
  263.      {              4 [. e  h6 y# D# h) z2 ?0 g
  264.           IIC_SDA(IIC_Type_t,(txd&0x80)>>7);
    : d' ?) H0 w9 X+ r5 L8 J, r! K
  265.           txd <<= 1;    " s  q1 j$ r& {) i5 N$ ^
  266.        IIC_Type_t->delay_us(2);     //对TEA5767这三个延时都是必须的# A! m4 U. v: z  U: K
  267.        IIC_SCL(IIC_Type_t,1);: [/ i2 y4 v% S. c5 [3 R
  268.        IIC_Type_t->delay_us(2);  
    2 N  c% \0 j6 ~! C! ~5 H6 b
  269.        IIC_SCL(IIC_Type_t,0); ' z! C1 i8 S) r2 a/ x
  270.        IIC_Type_t->delay_us(2);  # D! D! L( P7 n. g( A
  271.      }  
    ! i4 }  p0 _$ X" x% g
  272. }
    & h( T. T- c, J) S' e1 t+ D9 A
  273. //IIC_Send_Byte,入口参数为是否要发送ACK信号2 |: M8 T0 i& y) Y& h2 r/ T
  274. static uint8_t IIC_Read_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t ack)     - N+ h7 H0 ~5 P" a$ b
  275. {
    ! f8 c9 y% `1 ?- `
  276.    uint8_t i,receive = 0;( |! f/ @2 K! ~" u& R+ X
  277.    SDA_IN(IIC_Type_t);//SDA设置为输入: j+ v) [7 I' e5 m  u* ?. [: l& ~6 @
  278. for(i=0;i<8;i++ )2 J$ ?4 r) h6 z+ k" A
  279.    {/ n5 ?" O' e% `
  280.       IIC_SCL(IIC_Type_t,0);
    ; ^. x9 X7 o6 |& x* ], O% D& G
  281.       IIC_Type_t->delay_us(2);% D  B$ y: z3 K7 ^  N* D
  282.       IIC_SCL(IIC_Type_t,1);0 ]$ O7 V; E8 x! y  v6 S
  283.       receive<<=1;
    9 w. j  v. s& K( ?, v: a
  284. if(READ_SDA(IIC_Type_t))receive++;   - c0 \; `. {% }9 O0 i
  285.       IIC_Type_t->delay_us(1);& R  m! V- G" L2 n; H
  286.    }      9 T, }5 u2 D3 V+ o. ~4 k, W
  287. if (!ack)
    5 U$ k) E1 u7 |* I
  288.          IIC_Type_t->IIC_NAck(IIC_Type_t);//发送nACK) p5 @1 l3 I. [
  289. else& J7 B0 M0 A7 g: @3 t
  290.          IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK   
    - V. R6 ]: F9 s6 w) Y& }
  291. return receive;
    4 ^" X) V, f9 A1 i1 }, u0 @
  292. }
    ' g2 V7 F6 K: |- y5 e' h: m6 {+ O
  293. //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用1 ^0 t/ Z) y. J$ x1 m8 R; m' w
  294. IIC_TypeDef IIC1 = {
    & c  x/ f" M- y/ o( y" S& b: G
  295.   .GPIOx_SCL = GPIOA,   //GPIO组为GPIOA
    ' E. t' l7 Q+ l5 s) D1 o% |- S- Z" C
  296.   .GPIOx_SDA = GPIOA,   //GPIO组为GPIOA
    8 h; _9 J& K& f: [
  297.   .GPIO_SCL = GPIO_PIN_5,   //GPIO为PIN5! C* e" c) {* `5 o7 @
  298.   .GPIO_SDA = GPIO_PIN_6,  //GPIO为PIN6# b! l! o( K6 S% @
  299.   .IIC_Init = IIC_Init_t,- K4 n4 ~1 n. `/ w* L+ L5 C
  300.   .IIC_Start = IIC_Start_t,
    5 G2 W0 a- B% V
  301.   .IIC_Stop = IIC_Stop_t,/ O, U/ k: ^: j, y
  302.   .IIC_Wait_Ack = IIC_Wait_Ack_t,* v9 D* C9 w  ^, L+ `0 h) g/ J
  303.   .IIC_Ack = IIC_Ack_t,% _7 `  [& E& H; Z. `
  304.   .IIC_NAck = IIC_NAck_t,5 ^1 ?, d% v& h: A2 X. ~# V* C
  305.   .IIC_Send_Byte = IIC_Send_Byte_t,
    . ~3 Z# F8 D8 E: A/ o+ y
  306.   .IIC_Read_Byte = IIC_Read_Byte_t,
    0 g6 I/ P3 Z" V6 l0 ]% U" x, |3 h
  307.   .delay_us = delay_us     //需自己外部实现delay_us函数3 y) Q2 H( E4 n
  308. };
复制代码

3 w3 G0 N. D( F3 a4 B% E
    上述就是IIC驱动的封装,由于没有应用场景暂不测试其实用性,待下面ATC64的驱动缝缝扎黄写完之后一起测试使用。
ATC64XX驱动封装实现
    at24cxx.h头文件主要是类模板的定义,具体如下:
  1. // 以下是共定义个具体容量存储器的容量
    7 j5 g, [1 w* g1 \/ q; P- |5 _1 c) W* S
  2. #define AT24C01  127& {' r& h( [' G: c2 c0 e3 P
  3. #define AT24C02  255
    * X- a; W  U' N: L& y" ^
  4. #define AT24C04  5115 w1 G3 d7 D0 \# R" t3 @
  5. #define AT24C08  1023
    4 `" e( i# h; n, o% |$ S
  6. #define AT24C16  2047
    , l0 h" m' m0 U3 t$ M$ o( J
  7. #define AT24C32  4095
      P8 p. T; }& C7 x2 S
  8. #define AT24C64   8191         //8KBytes
    - q/ B0 L0 W* U* L9 R
  9. #define AT24C128 16383
    + X9 g- q% N3 N# L
  10. #define AT24C256 32767  
    ) M& v( w$ F0 |5 Y3 f8 [& T
  11. 4 v1 z  b* k- q" B0 o$ M
  12. //定义AT24CXX类
    % a4 ]; Y9 D) B& g; K/ M9 V) |# E
  13. typedef struct AT24CXX_Type
    & k' B$ A/ h1 I* U) _( B
  14. {
    / i& t. O& j5 P  q0 h' z
  15. //属性
    " O0 [4 x; _  u. h* f7 J
  16.   u32 EEP_TYPE;           //存储器类型(存储器容量)
    % U0 l) s: X# D0 W3 @6 X
  17. //操作: p5 Q% x/ K. f* ?8 I9 I8 F0 l
  18.   IIC_TypeDef IIC;       //IIC驱动& j0 A" {, Z# X: U4 h7 u
  19. uint8_t (*AT24CXX_ReadOneByte)(const struct AT24CXX_Type*,uint16_t);  //指定地址读取一个字节, v0 c/ b: V! q0 y8 ~; r+ g
  20. void (*AT24CXX_WriteOneByte)(const struct AT24CXX_Type*,uint16_t,uint8_t); //指定地址写入一个字节6 d. p% `4 ^+ h  r" t
  21. void (*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t); //指定地址开始写入指定长度的数据% E7 b; f- V7 W7 W
  22. uint32_t (*AT24CXX_ReadLenByte)(uint16_t,uint8_t);   //指定地址开始读取指定长度数据9 A5 }5 ~( K7 v8 B: I
  23. void (*AT24CXX_Write)(uint16_t,uint8_t *,uint16_t);  //指定地址开始写入指定长度的数据
    6 e6 G) h; c) U5 D( E. E
  24. void (*AT24CXX_Read)(uint16_t,uint8_t *,uint16_t);   //指定地址开始写入指定长度的数据
    : b2 |* C, _! \6 D! m3 e; F
  25. void (*AT24CXX_Init)(const struct AT24CXX_Type*); //初始化IIC
    # W" H8 y) d9 ?) R" m8 h- ~7 B; o, P) {
  26. uint8_t (*AT24CXX_Check)(const struct AT24CXX_Type*);   //检查器件
    4 C& B( t. p6 T* N1 o3 G
  27. }AT24CXX_TypeDef;
    ; w( T9 _% @4 M3 O8 G6 o

  28. . X4 _! O6 e* }5 P
  29. extern AT24CXX_TypeDef AT24C_64;     //外部声明实例化AT24CXX对象
复制代码

1 P% E5 s4 U( P$ D" r2 c& h
    at24cxx.c源文件主要是类模板具体操作函数的实现,具体如下:
  1. //在AT24CXX指定地址读出一个数据
    ' ^* \2 h# z- `3 E: y+ p
  2. //ReadAddr:开始读数的地址  
    5 O: [3 M" A: Z5 h
  3. //返回值  :读到的数据
    : x8 ]" S! {4 Q2 ^
  4. static uint8_t AT24CXX_ReadOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t ReadAddr)
    * D8 T: @4 g6 x$ O1 m. v5 B1 P
  5. {      ! O7 W: f% f# ?: o
  6.   uint8_t temp=0;                          - V% j: M( X8 D: w
  7.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);  
    0 ?, M! s* A4 f# R/ M0 L. J
  8. //根据AT的型号发送不同的地址
    & ~$ ]) u& u1 h3 ?+ A% I
  9. if(AT24CXX_Type_t->EEP_TYPE > AT24C16)
    2 i# r" ]( W8 S; i7 Q# z$ Z3 }
  10.   {
    + P3 {8 l: k- P, o* N4 |! f; p
  11.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令: ]' l" V/ e& u8 ^4 t
  12.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);) a/ @- R5 A3 e6 p1 d
  13.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//发送高地址     1 S) [. [5 G! @- m% P
  14.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据     5 q4 c, [4 p/ A( J' X
  15.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    ' F6 J0 C! v  n: G& o- E0 H
  16.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256);   //发送低地址  Z7 L) W$ K- D
  17.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     
    7 C$ y0 a4 o+ w
  18.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);        ) Q, B5 i' a8 J' @8 c/ L# N
  19.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA1);           //进入接收模式      - ~" k9 s8 w5 `
  20.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);  
    ) i0 Y" o, n% z4 d  O' w$ c
  21.   temp=AT24CXX_Type_t->IIC.IIC_Read_Byte(&AT24CXX_Type_t->IIC,0);     
    % \0 R, h8 E1 Q3 L  E7 t* T
  22.   AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件     $ f  b/ l" Q; d& `. x
  23. return temp;9 {7 I2 I3 y( E8 e$ P% |
  24. }
    . b; b" h" L1 y- R, b
  25. //在AT24CXX指定地址写入一个数据8 j0 ?# B; E2 q0 T4 o
  26. //WriteAddr  :写入数据的目的地址   
    3 Q8 v7 m+ J: o3 N
  27. //DataToWrite:要写入的数据4 ?2 C- V6 y% Q  K# R9 m: K
  28. static void AT24CXX_WriteOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t WriteAddr,uint8_t DataToWrite)0 L3 |, C. u% S6 E- o
  29. {                                . E* D0 u8 t, c, V; n& U" V* r- p" O
  30.    AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);   3 H+ @0 }, M+ Z0 k! S
  31. if(AT24CXX_Type_t->EEP_TYPE > AT24C16). r0 [, j. D4 e. I" R0 _
  32.   {
    - ]# M; ~/ P5 X* b1 s# B
  33.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令, H# f! `; X! G5 n8 r' e/ P5 r. h
  34.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);. [* Q0 I* F% \3 o$ G5 c
  35.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//发送高地址     : E" U$ U" G$ T
  36.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据     2 G+ D- h# u8 ?& n3 I
  37.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC); 9 D( H4 }- \; N% Q
  38.    AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256);   //发送低地址4 |3 N- }% P! u0 l5 [! h/ ~
  39.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);               
    ( Y& E1 g% x6 y4 D, H
  40.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite);     //发送字节            Z9 C$ X; i- N& H  E
  41.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);            
      X7 }& c7 G" Z. t4 D- S
  42.    AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件 3 ^* H- t. a( n- c1 [  m
  43. AT24CXX_Type_t->IIC.delay_us(10000);  
    2 ^4 d) j# U4 `/ T' ?4 I( |
  44. }1 H  ]+ D; }5 P2 w9 }
  45. //在AT24CXX里面的指定地址开始写入长度为Len的数据* c) l, ]: k2 H0 h
  46. //该函数用于写入16bit或者32bit的数据.* ^9 _$ e8 p4 _- i6 i0 m
  47. //WriteAddr  :开始写入的地址  # ~+ y0 V2 w: i, G  @; w
  48. //DataToWrite:数据数组首地址8 M4 y2 E$ I; `0 d, i1 w' N
  49. //Len        :要写入数据的长度2,44 y  o9 q* u: ?3 \0 G
  50. static void AT24CXX_WriteLenByte_t(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len)
    ' q7 b1 q" s9 _% G) J& k+ K
  51. {   
    . L/ r# W7 j* l0 q  Q
  52.   uint8_t t;
    4 p: u- }$ S7 \4 \9 m) ]$ K
  53. for(t=0;t<Len;t++)
    - \6 X* ]- k, x5 d8 u
  54.   {4 O( Q7 ?4 D* i/ z4 J
  55.     AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);7 P: Y% W" f: H+ K! ]! r
  56.   }                # w1 M* u( f/ w% [, P: l' N
  57. }
    ) Q/ X2 u0 Z$ v. ?: j
  58. //在AT24CXX里面的指定地址开始读出长度为Len的数据3 R* ]* N( T+ x) {* z' L
  59. //该函数用于读出16bit或者32bit的数据.
    $ Z0 t0 x- t1 N4 z3 w1 E
  60. //ReadAddr   :开始读出的地址
    " l# x+ S, {7 {% }, G, r5 M; M; t( r$ h
  61. //返回值     :数据
    : Y0 ]# n, Z8 c0 |- @
  62. //Len        :要读出数据的长度2,4$ U0 H" e' y$ b  E) ^8 y" K
  63. static uint32_t AT24CXX_ReadLenByte_t(uint16_t ReadAddr,uint8_t Len)) l' C/ a5 c. `! h! z
  64. {   
    4 j" j; z  H) d( h
  65.   uint8_t t;
    ; i  I; ^- l6 G$ o
  66.   uint32_t temp=0;) d% C, q% H2 G  P  `5 c
  67. for(t=0;t<Len;t++)
    7 C1 ]5 C! X1 d; E, t3 J% ~8 o
  68.   {& }* s! ~+ H# b+ n
  69.     temp<<=8;
    : N) X5 _8 R  J4 G8 {
  70.      temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);          # R% Y, v( @+ b9 g" Y
  71.   }$ w% u$ j  |7 Y- k# N+ C5 e5 Y% E
  72. return temp;               
    0 k7 w3 `% d0 _. B! o8 K
  73. }6 _6 Y9 W0 q$ [" q0 X* F1 Q0 r5 t
  74. //在AT24CXX里面的指定地址开始写入指定个数的数据# _- \, `! a+ S: z6 M( b
  75. //WriteAddr :开始写入的地址 对24c64为0~8191: f& c  a6 k4 l4 P
  76. //pBuffer   :数据数组首地址
      E3 N7 Y. @, \. ~  Q8 ], a
  77. //NumToWrite:要写入数据的个数
    * m5 H/ n# a( g* s8 n' \
  78. static void AT24CXX_Write_t(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)
    : ?" X6 I. z3 z/ M& I
  79. {8 \5 Y( {8 ]" }: h+ [: n6 ?/ \4 l
  80. while(NumToWrite--)" c+ c3 q( U4 p+ C# @. r6 j
  81.   {
    " N; ~: V+ v  w0 F4 s
  82.    AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    " S7 k0 {% |$ O" P
  83.     WriteAddr++;
    ; ^* K1 t! `$ p9 O
  84.     pBuffer++;- w# K0 t/ p. d- K
  85.   }
    % ]) C; F/ J9 K0 v
  86. }
    + f1 X4 _6 _% ]) ~
  87. //在AT24CXX里面的指定地址开始读出指定个数的数据
    3 |# q% r* s% v* ~
  88. //ReadAddr :开始读出的地址 对24c64为0~81919 m6 M& c2 O1 `2 z9 _/ o
  89. //pBuffer  :数据数组首地址: q( ?, F- X  ?7 q
  90. //NumToRead:要读出数据的个数
    8 d/ h, P9 y6 W. f$ p/ m' ~
  91. static void AT24CXX_Read_t(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead)- B: M0 K2 W! m' {' B
  92. {* l1 e' ?! u; u6 c+ S, k
  93. while(NumToRead)
    1 A, ]+ y' G$ g. D
  94.   {  Q. h( m" c4 a2 \3 Q! u' G
  95.     *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    / y$ J& P; B0 g1 o6 b
  96.     NumToRead--;
    ; R1 n7 l: Y( J/ Z& H
  97.   }
      a; d' q9 d! P/ @% @
  98. }
    ' o. v: A8 l' W! z+ @
  99. //初始化IIC接口  v5 U; i5 }* D: P* a4 y
  100. static void AT24CXX_Init_t(const struct AT24CXX_Type* AT24CXX_Type_t)
    $ H# m0 a: E/ y% M0 x. y, s
  101. {
    9 Y2 M. T  X3 u* }# D
  102.   AT24CXX_Type_t->IIC.IIC_Init(&AT24CXX_Type_t->IIC);//IIC初始化
    . |, O+ q# w1 o& j$ i- E' |# k3 }
  103. }
    & _0 E! R! P6 T) m7 U' y8 t
  104. //检查器件,返回0表示检测成功,返回1表示检测失败- ?0 t9 j- b; z8 c
  105. static uint8_t AT24CXX_Check_t(const struct AT24CXX_Type* AT24CXX_Type_t)   - @. g( ?8 ^: S  y
  106. {
    " C& e. _  i& a% v- t6 h8 I3 H
  107. uint8_t temp;( `2 x8 a% s4 `! g
  108.   temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);//避免每次开机都写AT24CXX      5 X" P) l# P$ N, p9 G. k
  109. if(temp == 0X33)return 0;     # X, g- h& m- m5 v
  110. else//排除第一次初始化的情况
    ) p, D/ a& R) K
  111.   {
    5 A$ O4 i$ B- @4 C6 J
  112.       AT24CXX_Type_t->AT24CXX_WriteOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE,0X33);
    ' o- w$ e9 h" D0 n4 z8 |
  113.        temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);( i6 d2 [6 d; B0 M1 o
  114. if(temp==0X33)return 0;
    0 b. q7 I/ f8 g$ t. v) o! h
  115.   }
    ! m5 @& I1 J3 M7 }' g" _
  116. return 1;  
    # h1 n0 M. q# U/ _0 U: d" s
  117. }8 f9 R0 V$ X7 k# t
  118. //实例化AT24CXX对象
    % I  I$ ^' Q/ I) f1 C
  119. AT24CXX_TypeDef AT24C_64={7 m. g0 p, @( y3 h/ Y* N: ]1 H2 f& A+ |
  120. .EEP_TYPE = AT24C64,           //存储器类型(存储器容量)# ]' b9 O7 t" H4 y+ Z* y
  121. //操作
    4 X0 S9 o; ?" F  a$ N9 V; [& O
  122. .IIC={
    ) {, y4 K7 S, c$ q, g
  123.   .GPIOx_SCL = GPIOA,
    ! @# f2 e0 L4 _. P- p- N3 i0 @$ `/ P5 E
  124.   .GPIOx_SDA = GPIOA,* V3 Z' v( P. {' {5 w
  125.   .GPIO_SCL = GPIO_PIN_5,
    4 ]# o: T/ k/ o( I: F
  126.   .GPIO_SDA = GPIO_PIN_6,
    # ?5 v6 q% e( K) ]$ {3 @
  127.   .IIC_Init = IIC_Init_t,! i0 A( q3 z, y, m1 C3 L
  128.   .IIC_Start = IIC_Start_t,
    9 d) i$ H, V3 T  @9 A8 d" h) C( g- A
  129.   .IIC_Stop = IIC_Stop_t,
    3 k* x* e8 A3 d
  130.   .IIC_Wait_Ack = IIC_Wait_Ack_t,
    / [2 z2 O( j6 X9 }: v2 \$ P% S
  131.   .IIC_Ack = IIC_Ack_t,6 U+ u0 G3 l9 E1 a+ S& Z" @
  132.   .IIC_NAck = IIC_NAck_t,. W( J6 ~9 m& u2 l$ g
  133.   .IIC_Send_Byte = IIC_Send_Byte_t,, r7 @6 s7 C8 m7 [4 o& r
  134.   .IIC_Read_Byte = IIC_Read_Byte_t,
    % Q% W& R, c, k/ b
  135.   .delay_us = delay_us
    . n( {0 _$ _) f8 h# ~
  136. },                   //IIC驱动
    4 f8 C* Q$ ?: b# M/ t& z
  137. .AT24CXX_ReadOneByte = AT24CXX_ReadOneByte_t,  //指定地址读取一个字节0 _, C! _9 K7 v. `( ^" a
  138. .AT24CXX_WriteOneByte = AT24CXX_WriteOneByte_t,//指定地址写入一个字节
    * v% f) P  G8 m: D' G5 z
  139. .AT24CXX_WriteLenByte = AT24CXX_WriteLenByte_t, //指定地址开始写入指定长度的数据
    7 r; ?% i: n: l9 i$ r
  140. .AT24CXX_ReadLenByte = AT24CXX_ReadLenByte_t,   //指定地址开始读取指定长度数据$ C; C" P8 Q4 l' N
  141. .AT24CXX_Write = AT24CXX_Write_t,  //指定地址开始写入指定长度的数据5 O6 _" Q. n8 |1 d! r8 l8 O
  142. .AT24CXX_Read = AT24CXX_Read_t,   //指定地址开始读取指定长度的数据# k- Z% @: k8 G; F! C0 u9 b
  143. .AT24CXX_Init = AT24CXX_Init_t, //初始化IIC2 C) Z# N5 c! n5 j1 T
  144. .AT24CXX_Check = AT24CXX_Check_t   //检查器件
    8 b9 T2 v& R; G" v
  145. };
复制代码
& r8 d; q* V% k& S) v
    简单分析:可以看出AT24CXX类中包含了IIC类的成员对象,这是一种包含关系,因为没有属性上的一致性因此谈不上继承。
    之所以将IIC的类对象作为AT24CXX类的成员是因为AT24CXX的实现需要调用IIC的成员方法,IIC相当于AT24CXX更下层的驱动,因此采用包含关系更合适。
    因此我们在使用AT24CXX的时候只需要实例化AT24CXX类对象就行了,因为IIC包含在AT24CXX类中间,因此不需要实例化IIC类对象,对外提供了较好的封装接口。下面我们看具体的调用方法。

1 P: _4 f' B/ J6 }2 V" ~7 e6 `
主函数main调用测试
    在main函数中直接使用AT24C_64来完成所有操作,下面结合代码来看:
  1. #include "at24cxx.h"    //为了确定AT24C_64的成员方法和引用操作对象AT24C_64
    . x& M- Y/ A# ]& q8 r* I  N
  2. int main(void)1 s3 i# v, c  c# u
  3. {
    , u, G: B$ F2 v2 I7 R7 p& y/ ?
  4. /************省略其他初始化工作****************/
    & L+ C2 U7 K4 C+ C
  5. //第一步:调用对象初始化方法来初始化AT24C64
    1 q: {) Z5 g5 M; e# R/ X
  6.   AT24C_64.AT24CXX_Init(&AT24C_64);, @4 C3 V' K: ^. z/ p$ Y6 ~2 R
  7. //第二步:调用对象检测方法来检测AT24C64           
    ( x. _6 a8 D  M
  8. if(AT24C_64.AT24CXX_Check(&AT24C_64) == 0)8 ^; Y  ?7 E9 X& `, j
  9.   {- R& k, U. |2 r1 y9 j
  10. printf("AT24C64检测成功\r\n");
    / b( [/ q$ f8 q( i
  11.   }7 @5 @) |, I" c/ C0 o1 v) v
  12. else{
    6 e& s/ g1 C& T* Y" O* Z, v
  13. printf("AT24C64检测失败\r\n");
    . ?( e  T% `: O) V. \) W. x
  14.   }
    , R4 n8 N4 L8 a. A8 i$ s/ a
  15. return 0;
    2 y0 P6 I9 t  v1 ^
  16. }
复制代码
& H* D' M6 q7 ]3 f
    可以看出所有的操作都是通过AT24C_64对象调用完成的,在我们初始化好AT24C_64对象之后就可以放心大胆的调用其成员方法,这样封装的好处就是一个设备对外只提供一个对象接口,简洁明了。

9 \* t" T+ c. ?: f& O3 `8 s" K
总结
    本文详细介绍了面向对象方法实现IIC驱动封装以及AT24CXX存储器的封装,最终对外仅提供一个操作对象接口,大大提高了代码的复用性以及封装性。
7 a  W$ T" t& x9 {! f
+ v! e3 f# T/ f) k
赞 收藏 评论0 发布时间:2022-6-7 09:41

举报

0个回答

所属标签

相似技术帖

官网相关资源

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