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

STM32开发中使用C语言实现IIC驱动

[复制链接]
STMCU-管管 发布时间:2021-6-21 14:39
简述
/ q9 \% P; N; {6 W, [  m- j    IIC(Inter-Integrated Circuit)其实是IICBus简称,它是一种串行通信总线,使用多主从架构,在STM32开发中经常见到。0 W! e* S& w( v  a" o; z
+ m( e; Z+ ~" k4 v
+ G, e" g6 B: b- A
    关于IIC可以参考之前发的一篇文章《通信协议 IIC 与 SPI 最全对比》来了解。
8 a4 g/ s6 L0 `: Y- G) I* X) L/ d1 z& Q$ g8 ]
3 ?3 `& o8 m4 V- L& ]& Q
    使用面向对象的编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备时只需要实例化一个IIC对象即可,本文是基于STM32和HAL库做进一步封装的。3 s6 s4 X1 D+ q2 g
/ K/ \0 o+ U& O. `
( V# W% c! c. M+ b) Z
    底层驱动方法不重要,封装的思想很重要。在完成对IIC驱动的封装之后借助继承特性实现AT24C64存储器的驱动开发,仍使用面向对象的思想封装AT24C64驱动。9 L) j$ Y0 \" H$ B
: S3 B& k1 \; P; h* S$ w- H3 i' g

( F8 d- z& z0 b0 U0 x6 YIIC驱动面向对象封装
) H+ {4 H0 [+ N4 D: z- ~5 \+ X    iic.h头文件主要是类模板的定义,具体如下:
1 b1 u7 a& ^' B
  1. " i. x, S5 I9 c: }- y4 V5 P9 [
  2. //定义IIC类' [$ `3 I' L6 V' H! }+ D
  3. typedef struct IIC_Type/ j9 b* u$ c$ X- r
  4. {
    ! S% b/ u  Z- Z$ @0 Q, Z
  5.    //属性
    0 Y; O& w5 o, \" F
  6.    GPIO_TypeDef  *GPIOx_SCL;  //GPIO_SCL所属的GPIO组(如:GPIOA). v! K, }0 Y* X9 p% t- i
  7.    GPIO_TypeDef  *GPIOx_SDA;  //GPIO_SDA所属的GPIO组(如:GPIOA)' [' K, Q$ h, x# L  O" o0 C7 p
  8.    uint32_t GPIO_SCL;     //GPIO_SCL的IO引脚(如:GPIO_PIN_0)6 Q+ J0 ?. }: h( a  k1 f
  9.    uint32_t GPIO_SDA;     //GPIO_SDA的IO引脚(如:GPIO_PIN_0)/ S! ]* N4 A* a& ^
  10.    //操作5 }* |; f4 C* Z! b  i9 T
  11.    void (*IIC_Init)(const struct IIC_Type*);        //IIC_Init
    : g9 n$ ]/ N/ e; Z0 g, [
  12.    void (*IIC_Start)(const struct IIC_Type*);       //IIC_Start
      |$ x$ }& k- K7 R* G- B+ E4 ]
  13.    void (*IIC_Stop)(const struct IIC_Type*);        //IIC_Stop
    9 @# }) y- T9 Q/ T) {* I( a
  14.    uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*);    //IIC_Wait_ack,返回wait失败或是成功! g" i( x% l8 U# H
  15.    void (*IIC_Ack)(const struct IIC_Type*);       //IIC_Ack,IIC发送ACK信号
    & |4 h: M. m, z% \# J4 }
  16.    void (*IIC_NAck)(const struct IIC_Type*);       //IIC_NAck,IIC发送NACK信号
    ! N4 s! Z1 H. w2 c8 D+ H
  17.    void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t);       //IIC_Send_Byte,入口参数为要发送的字节8 ]3 `9 h" G" t! k: ~, ]/ R/ j
  18.    uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t);     //IIC_Send_Byte,入口参数为是否要发送ACK信号* e# \7 ?0 T  l) N6 U; a4 f
  19.    void (*delay_us)(uint32_t);              //us延时
    6 T- g3 A2 B2 l. O# ?4 E- f3 Q
  20. }IIC_TypeDef;
复制代码
  iic.c源文件主要是类模板具体操作函数的实现,具体如下:& m! G! S9 e9 i
  1. //设置SDA为输入模式
    7 q7 r- B5 L. V
  2. static void SDA_IN(const struct IIC_Type* IIC_Type_t)
    : a8 A- m& q) J' u0 L
  3. {
    2 T5 i4 K7 F/ g
  4.   uint8_t io_num = 0;  //定义io Num号* A9 g  G5 E2 W& V. f7 _, G
  5.   switch(IIC_Type_t->GPIO_SDA)
    1 V3 e/ G) {& Q' L2 K$ G6 V/ x0 U- |
  6.   {" q# \1 ?2 r6 N# }9 S& [9 s  p
  7.    case GPIO_PIN_0:" s  e  U6 K! ]* t
  8.     io_num = 0;
    $ h; l0 V: t  T9 }* {
  9.    break;
    5 J: L8 x0 s$ A2 I2 [: L1 C
  10.    case GPIO_PIN_1:
    - W' S% r  s- g0 S5 G/ N" R
  11.     io_num = 1;: ^" _2 t; O" H6 ~9 q' q
  12.    break; & y( w) C4 G8 D8 |* C
  13.    case GPIO_PIN_2:
    * ~# ~- |2 n: F1 T" ]
  14.     io_num = 2;
      t# P3 M! @4 d1 K9 |) o
  15.    break; " r' r4 }6 X! k5 L9 {% Z
  16.    case GPIO_PIN_3:
      a% V- h- u6 u( H% T3 T/ p
  17.     io_num = 3;
    3 o2 q2 ]+ h, C4 x* p  z8 M
  18.    break;
    3 p6 R6 F0 x) ^  K, p- q: r: C: l
  19.    case GPIO_PIN_4:4 a( L) O; f2 i
  20.     io_num = 4;# F3 P4 n3 g5 [0 ^; l& I3 ~, i" _
  21.    break;
    8 ~) w/ ^/ R/ v5 Z2 v" E% e
  22.     case GPIO_PIN_5:# b: T& v* D' e/ C5 q4 d  D6 f
  23.     io_num = 5;( x$ h( p5 E5 D; s2 `
  24.    break;
    - G2 o1 H  n$ p. q, |1 ]
  25.    case GPIO_PIN_6:* \$ ~, u6 ~0 v0 ]( A
  26.     io_num = 6;, A, M( j5 V5 F" y" S
  27.    break; : z( J( n6 ^- C$ f; C2 M8 {6 \6 k
  28.    case GPIO_PIN_7:
    ( F3 E% C) j9 j$ G  D( m0 r5 k
  29.     io_num = 7;
    - N  C* C$ d3 ?1 g
  30.    break;
    * w9 t2 h$ {' c
  31.    case GPIO_PIN_8:
    1 a4 j# Q0 v9 X  n
  32.     io_num = 8;. f( l1 L+ f- X5 V# z, V+ l: J4 P
  33.    break;
    ! `, g  e5 m$ ~" A) f& P
  34.    case GPIO_PIN_9:
    + E% U1 m. u$ m) U# ]# D- \1 [
  35.     io_num = 9;
    $ M# t" C0 q! E2 u
  36.    break;
    4 F! E; }6 }/ V! X
  37.    case GPIO_PIN_10:8 s! O& a7 p5 \5 d
  38.     io_num = 10;0 r; W" K0 s6 W! L. M% I4 s1 C6 Q
  39.    break;
    ( z" S1 ?4 J# J8 C' f" _
  40.    case GPIO_PIN_11:
    : C( }! I% X9 D' F, w
  41.     io_num = 11;
    , g% b! I; A* |; E
  42.    break;
    1 y/ C* @5 o. c* M
  43.    case GPIO_PIN_12:$ }5 K" U4 S  ?; X, q
  44.     io_num = 12;
    $ c& a3 B% ?# }3 h
  45.    break;9 y' U3 `" ~8 S" i% M, s
  46.    case GPIO_PIN_13:
    5 u- M3 ?9 x$ H# i6 j
  47.     io_num = 13;. F9 R8 y3 A! \
  48.    break;
    # j: p/ D6 o+ `
  49.    case GPIO_PIN_14:
    ! h" ^& G% L! K( Q+ H8 x
  50.     io_num = 14;# M; C- D6 ^9 c. O+ i
  51.    break; % d$ z7 i+ v4 k3 a
  52.    case GPIO_PIN_15:
    ! D6 C& c) ^/ S
  53.     io_num = 15;
    ( t8 e. n0 U% `0 t  r1 V; i) }
  54.    break;  H& g% Q" e1 d9 t1 \; A
  55.   }& o5 H1 h# \  ]& l" a
  56.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零/ B/ {' n5 I: N
  57.   IIC_Type_t->GPIOx_SDA->MODER|=0<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输入模式
    # X, }$ k/ A: \; V0 E5 Q" u- h
  58. }
    8 B; v$ i: W: `; {1 ~4 b7 f) S
  59. + n/ c) Z9 T1 q! I% |" Q. M+ X
  60. //设置SDA为输出模式
    1 u2 I, d2 }4 `! m/ L- X4 u
  61. static void SDA_OUT(const struct IIC_Type* IIC_Type_t)& U7 G; _1 Y! T9 s+ i
  62. {6 I: h" t# N* X" I; _# k  c
  63.   uint8_t io_num = 0;  //定义io Num号
    % O- S$ l8 e& W6 B
  64.   switch(IIC_Type_t->GPIO_SDA)7 X% W+ s% e& K
  65.   {1 _/ G, p8 I  @
  66.    case GPIO_PIN_0:
    1 w$ z( p7 y. p/ e7 D
  67.     io_num = 0;( k- c9 b( [: N4 U/ c0 b
  68.    break;
    ! M. @, L% x5 Y5 P4 B3 c
  69.    case GPIO_PIN_1:
    , r7 l) L5 d6 y) h! }- T
  70.     io_num = 1;) d6 ]; H" t3 T$ S& m7 u5 P  N) ~4 M
  71.    break; 0 d/ j, g8 t2 X1 k" O+ S& L
  72.    case GPIO_PIN_2:
    6 z/ ^+ Z: S) w% f/ m% x/ b0 G
  73.     io_num = 2;
    * I5 y0 _) F$ }, h
  74.    break;
    0 K( Z/ {  _. \; A
  75.    case GPIO_PIN_3:' C+ i" S  L0 A
  76.     io_num = 3;
    % ~4 H' B& j0 G6 z- K' O, k* U
  77.    break;  X) n1 a5 K4 J: K. {. I. q
  78.    case GPIO_PIN_4:) d  \2 H- Y* d& N: |5 I
  79.     io_num = 4;8 H% Q1 U6 o. M5 K, v  h
  80.    break;
    ' C& N- W3 r' F, L
  81.     case GPIO_PIN_5:  `! f: H2 J7 m/ T
  82.     io_num = 5;
    ; X9 d: H% J2 E; V& j
  83.    break;
    # d1 w9 g3 r5 k9 A
  84.    case GPIO_PIN_6:
    1 l. W) G% }# t& c
  85.     io_num = 6;! W# u% K. u" ]3 V: Q
  86.    break;
    7 w- F  B1 z' L, i6 e/ s3 D
  87.    case GPIO_PIN_7:
    ; u5 m7 e2 _+ ^4 ~! k( D  H
  88.     io_num = 7;9 _% f% C7 d4 p- v8 `
  89.    break;
    5 r. }" v- I% s6 |
  90.    case GPIO_PIN_8:, z4 `9 Q3 ]$ [. e0 R
  91.     io_num = 8;& L, w. x( }# Y  C/ S
  92.    break; ) [. ]; a4 J: ~5 p) z
  93.    case GPIO_PIN_9:
    6 \1 u+ k/ `/ F7 L/ r/ x, e* x& E5 P
  94.     io_num = 9;
    % I5 T# z( K0 `% U1 L/ }
  95.    break;% `+ E0 C' l: a/ ]" \$ J3 m& {
  96.    case GPIO_PIN_10:
    4 R- s( }8 \1 s& F0 A
  97.     io_num = 10;
    - s9 b" C; Z& O
  98.    break;, `* ]- S1 F) g3 `, L5 Z" J
  99.    case GPIO_PIN_11:/ e1 a# u( Z9 Z4 ~% t) _
  100.     io_num = 11;
    ; R/ C! f- c! q- u% S" f8 U
  101.    break;
    / }# l& ~3 q0 ~
  102.    case GPIO_PIN_12:
    8 Y/ e( b) m- p/ I4 o" N! B
  103.     io_num = 12;
    / {8 \0 `8 n# F" q* H) W
  104.    break;7 z! `. ]0 @7 w% f
  105.    case GPIO_PIN_13:0 O# b$ W. {4 s4 @
  106.     io_num = 13;
    3 A; _# k7 h0 {0 b3 r! C/ {7 w
  107.    break;: _2 v" i, w/ x5 {0 Z- y
  108.    case GPIO_PIN_14:
    % h  k, m$ g0 ^7 u/ @' d* T& G
  109.     io_num = 14;$ B" I& x7 c. Q$ C
  110.    break; 7 I% O4 E7 _: d- ^4 f
  111.    case GPIO_PIN_15:! l) h) z9 C# J$ z! e
  112.     io_num = 15;
    * N- B( r) Y4 L+ x* v
  113.    break;
    , o4 f5 n0 n% v3 b  Y
  114.   }
    " b7 @: ^5 {. b6 g2 S) `
  115.   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零
    , d+ f" b7 H/ {% m" u& H
  116.   IIC_Type_t->GPIOx_SDA->MODER|=1<<(io_num*2);   //将GPIOx_SDA->GPIO_SDA设置为输出模式
      `5 I  {4 t7 \* p0 g  H
  117. }/ y9 O1 E8 H7 [! v9 [, _* h1 }4 b
  118. //设置SCL电平
    9 I1 J5 u1 ^: [: A$ j6 J: b5 x; I
  119. static void IIC_SCL(const struct IIC_Type* IIC_Type_t,int n)
    ) Z, c; E$ E4 j
  120. {
    % H1 x; R" m" ?" p/ P9 f
  121.   if(n == 1)/ X8 ?% |, z9 H" j$ D3 ~5 ~9 b0 X
  122.   {
    6 a3 t4 c) d* h
  123.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_SET);     //设置SCL为高电平
    " U. X( O2 H9 V  y+ T" g
  124.   }9 l" [* E6 u. s( y
  125.   else{
    7 S, [) u/ ^7 c/ \0 Y4 e& z
  126.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET);     //设置SCL为低电平; P/ w3 m5 s- G. v2 G7 E# n) V- k
  127.   }8 b. q  [3 K: `' b& S, V0 Y
  128. }' S9 k3 d6 e2 w# ~; e( i& _3 Y  Y1 e
  129. //设置SDA电平% W0 c2 D8 x+ ]8 j
  130. static void IIC_SDA(const struct IIC_Type* IIC_Type_t,int n)
    . F3 l& V( q7 X) C4 q0 K0 N( m
  131. {
    4 ~. l: W+ I$ u- `) o6 `$ I& s0 u
  132.   if(n == 1)
    0 R9 {# r5 V( |
  133.   {
    8 o1 d; V$ f7 y3 F' Y! p
  134.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_SET);     //设置SDA为高电平
    & r  [$ I2 q0 Q$ [  j* G
  135.   }& S. R, Y( L. l5 }! X
  136.   else{# @$ o3 U  S2 U# \' V$ G3 ~4 M7 _
  137.     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET);     //设置SDA为低电平
    0 z) i# @$ o8 _; ]' b4 v% s
  138.   }. \7 X" J/ O* v8 u& _8 k# r7 F
  139. }2 D/ ~  w& D7 A$ h( f& C( Z! V
  140. //读取SDA电平- v1 s: o6 ^8 d* L
  141. static uint8_t READ_SDA(const struct IIC_Type* IIC_Type_t)8 S) E/ e$ i) C8 r5 X
  142. {! A9 B1 k8 w; p; u' \
  143.   return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA);  //读取SDA电平
    1 F. G4 j- C' I/ \# X* ?# c6 G
  144. }
    ; k- X& B: w, O: Y
  145. //IIC初始化3 c& h, e9 b/ e, G) Z
  146. static void IIC_Init_t(const struct IIC_Type* IIC_Type_t)
    2 i: \* S9 N9 s: j
  147. {- m3 X/ L; x0 y5 J
  148.       GPIO_InitTypeDef GPIO_Initure;
    ) B+ J# T- z, b, j( i- E9 |5 H
  149.    
    # X& Y0 ~* w% P5 B& f' ^
  150.    //根据GPIO组初始化GPIO时钟& ~2 d; c3 ?6 p( r2 {
  151.    if(IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)
    + F, m$ O5 j5 t3 i) a6 C  J
  152.    {
    8 _/ w$ T6 F) H+ y
  153.      __HAL_RCC_GPIOA_CLK_ENABLE();   //使能GPIOA时钟
    ( {" V! d' F0 O$ S  P- f' Y
  154.    }
    & q3 z' _% L8 A' A- y
  155.    if(IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)
    3 M$ [: [1 u% }1 Z8 E* R3 U% ?- C
  156.    {
    $ E/ S8 ~+ u) \, G6 A. \1 j4 `
  157.      __HAL_RCC_GPIOB_CLK_ENABLE();   //使能GPIOB时钟
    ; d- T$ v; g! x* Z
  158.    }
    * L) A- n: ^! o) L' ~2 l: \
  159.    if(IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)
    2 `( ?* q3 q( o0 |9 K! @7 l
  160.    {
    % o( c5 X% ~: m. |6 A) J4 [# W; V! R
  161.      __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟
    + d  L: e, g$ l4 M! K, x
  162.    }, ~# _/ v+ n) n
  163.    if(IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)1 Z% X; M& t/ q" X
  164.    {9 T' X- S: d0 G3 b
  165.      __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD时钟- P4 X) j8 L, K2 I  w& t7 k
  166.    }, w) n6 i+ \( \! H9 W6 U
  167.    if(IIC_Type_t->GPIOx_SCL == GPIOE || IIC_Type_t->GPIOx_SDA == GPIOE)
    % v; v+ x' i8 U, c
  168.    {
    - y1 P3 D/ L& I6 r
  169.      __HAL_RCC_GPIOE_CLK_ENABLE();   //使能GPIOE时钟
      Z; `# p/ W% N9 w4 b
  170.    } ) v! R" P: Y5 A9 f
  171.    if(IIC_Type_t->GPIOx_SCL == GPIOH || IIC_Type_t->GPIOx_SDA == GPIOH)
    # R) F) z' G2 j  c
  172.    {9 ?. ~* c4 _, n) ?" z3 h6 q+ D
  173.      __HAL_RCC_GPIOH_CLK_ENABLE();   //使能GPIOH时钟
    / ]+ \& y! T5 m) G
  174.    }     1 L7 t. S/ O$ `# M  v: h6 T' V/ |
  175.    
    # Z& R! c, `8 q
  176.      //GPIO_SCL初始化设置
      A; ^* q2 c+ N2 P& W1 v5 z: L  R4 S4 b
  177.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SCL;
    ; |! Z6 s; ~: S- ~' E2 \* M+ u
  178.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出/ i$ b, I1 z  `) s5 R8 E7 S( v
  179.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉$ g9 T3 e8 W+ W2 Y+ m
  180.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速
    * c% \: A4 F- J; N5 s3 Q1 Y; o
  181.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL,&GPIO_Initure);
    6 W: ~( X8 H2 ^6 T* l7 \" U
  182.      //GPIO_SDA初始化设置1 N7 y, z* O( Y  E+ j5 V& z" Q
  183.      GPIO_Initure.Pin=IIC_Type_t->GPIO_SDA;
    7 u) R: |" d  A6 ~7 O+ [
  184.      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    ) N' D0 G* _% e: j. K
  185.      GPIO_Initure.Pull=GPIO_PULLUP;          //上拉% s: H/ S" J+ u6 M5 O& V, U
  186.      GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速: v$ `* R8 R, J1 W$ R8 }
  187.      HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA,&GPIO_Initure);
    % A1 N  V/ ?- M6 k
  188.      
    % l- Y4 q, a! X% |' J2 S' M3 J
  189.             //SCL与SDA的初始化均为高电平
    2 U8 n$ R0 m$ D. `& t' T
  190.       IIC_SCL(IIC_Type_t,1);
    , Q& }, a) l% y! n
  191.        IIC_SDA(IIC_Type_t,1);+ F5 v3 i) d8 Z7 ]% L
  192. }4 f2 A. E! H. I9 g5 y- p
  193. //IIC Start
    ' P- d5 o5 N! C2 `5 q5 A
  194. static void IIC_Start_t(const struct IIC_Type* IIC_Type_t)
    7 W* k" N8 p6 O* R7 t4 K
  195. {
    ' L. Q. c. r, t% i5 Q+ Z0 \
  196.   SDA_OUT(IIC_Type_t);      //sda线输出
    5 E, @5 f8 o7 k, C" Q: P
  197.   IIC_SDA(IIC_Type_t,1);      
    * ?, Z1 `2 Y4 n7 d6 i( a  h
  198.   IIC_SCL(IIC_Type_t,1);2 u0 k' g: M- m
  199.   IIC_Type_t->delay_us(4);6 h/ l+ G1 ~4 u/ O& _" z
  200.    IIC_SDA(IIC_Type_t,0);  //START:when CLK is high,DATA change form high to low
    : r/ A* c  `9 c$ Y( D% n/ L- [; [" y
  201.   IIC_Type_t->delay_us(4);
    / L2 @& M2 |$ y( |( }' ?- a
  202.   IIC_SCL(IIC_Type_t,0);  //钳住I2C总线,准备发送或接收数据
    / ^. N5 C$ ~$ O* l  R$ j; [
  203. }# `3 a* D0 r/ @7 P% X  P
  204. //IIC Stop" V. F' o/ J( N; y
  205. static void IIC_Stop_t(const struct IIC_Type* IIC_Type_t)/ `4 a: a# t# X5 q& Q
  206. {* j" y# F  F- d+ s1 d1 g' H& H
  207.   SDA_OUT(IIC_Type_t); //sda线输出5 P. J1 b3 t$ u" G9 x  w" b/ B8 s
  208.   IIC_SCL(IIC_Type_t,0);
    - j1 O$ D3 B3 S' P! h) E
  209.   IIC_SDA(IIC_Type_t,0); //STOP:when CLK is high DATA change form low to high( ~8 T7 F' a  ]' }( E% B. F0 c
  210.    IIC_Type_t->delay_us(4);
    ) N5 `, Z4 \" e3 S" p- e
  211.   IIC_SCL(IIC_Type_t,1); 8 d% G' \* j9 b# i+ r
  212.   IIC_SDA(IIC_Type_t,1); //发送I2C总线结束信号
    ) j7 E8 q( f5 Q" A1 `! x
  213.   IIC_Type_t->delay_us(4);
    : A/ e( J) a9 T! s
  214. }
    0 V: S6 j. f% ?+ x' ^
  215. //IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败5 F3 v+ P! q+ R- U6 O. j6 x
  216. static uint8_t IIC_Wait_Ack_t(const struct IIC_Type* IIC_Type_t)   //IIC_Wait_ack,返回wait失败或是成功
    ' ]: r. o# m8 q/ R% T" j
  217. {
    & j9 T# J; ~, p# R% H  }
  218.   uint8_t ucErrTime = 0;' _' m1 e! {2 g/ n
  219.   SDA_IN(IIC_Type_t);      //SDA设置为输入  / a9 c6 C) F: t8 w  I
  220.   IIC_SDA(IIC_Type_t,1);IIC_Type_t->delay_us(1);   $ \* e) L8 g! b) q/ v3 k+ d% `- P
  221.   IIC_SCL(IIC_Type_t,1);IIC_Type_t->delay_us(1);
    + m4 \1 ^0 g( i/ p- u5 D8 G
  222.   while(READ_SDA(IIC_Type_t)); o0 t1 m" X- L3 E& t& |' a
  223.   {
    4 x/ j  o# p( [/ _3 H, K
  224.     ucErrTime++;2 W7 k4 |8 o5 W5 g: E& C9 Z
  225.     if(ucErrTime>250)
    + c3 U7 S) V  n4 P. m$ g
  226.     {! Y8 E" B6 c# L6 |3 c' e$ l
  227.       IIC_Type_t->IIC_Stop(IIC_Type_t);9 t( I/ A, p" z# l( @. ~' g
  228.       return HAL_ERROR;
    3 w/ W! @6 c: R. c3 m5 y5 R
  229.     }
    4 H$ ]$ A; H$ a/ e8 n9 N0 Q9 i* K! X
  230.   }
    4 }0 l- _, U7 X
  231.   IIC_SCL(IIC_Type_t,0);//时钟输出0     
    + h' v8 S; J8 d' T0 y( L+ Q
  232.   return HAL_OK;  + q. P+ \$ M) z" \; p4 [
  233. }
    + r0 Y! ~. J) F8 f8 M# ]
  234. //产生ACK应答
      y5 k+ y  R! u' c: _
  235. static void IIC_Ack_t(const struct IIC_Type* IIC_Type_t)      
    ! I& H6 }; E" w8 Q
  236. {
    ' ~8 Q; `9 i# u
  237.   IIC_SCL(IIC_Type_t,0);
      F8 w$ W/ ]' d9 z
  238.   SDA_OUT(IIC_Type_t);
    4 s4 V" f) a& T7 S, W; K0 I
  239.   IIC_SDA(IIC_Type_t,0);0 ^7 O. N0 j9 N3 r
  240.   IIC_Type_t->delay_us(2);  
    ' i5 i( u- ?" w: g$ a, u
  241.   IIC_SCL(IIC_Type_t,1);1 k0 W) [/ ?# F
  242.   IIC_Type_t->delay_us(2);  $ Q, k- Q) B; j5 q# n# ?; p! @& \
  243.   IIC_SCL(IIC_Type_t,0);
    / J8 o8 X" o' w$ x( F: N% K5 d9 o5 K
  244. }
    # c7 B% m2 A& \
  245. //产生NACK应答
    # @9 {: r( t. h5 M, h% {" ~2 t; s
  246. static void IIC_NAck_t(const struct IIC_Type* IIC_Type_t)      . g; n9 \$ N3 E
  247. {( Z+ P) N' w( M/ ]$ q8 `/ X) u
  248.   IIC_SCL(IIC_Type_t,0);
    1 L+ h- x. J5 M# n6 F7 h6 ?: G1 H3 s
  249.   SDA_OUT(IIC_Type_t);! Y  q  P! }: c
  250.   IIC_SDA(IIC_Type_t,1);
    4 t& x  o5 a" g) h$ L3 ]6 R0 G
  251.   IIC_Type_t->delay_us(2);  # Z( r. U7 l1 O) a* h
  252.   IIC_SCL(IIC_Type_t,1);- q5 ]/ g0 d  j- ?' e# a
  253.   IIC_Type_t->delay_us(2);  - R7 K5 {" q3 Q5 R0 Y; X8 z
  254.   IIC_SCL(IIC_Type_t,0);
    ) q7 O- X' M8 H" R; S( X
  255. }
    5 t) @) z0 r. E, A
  256. //IIC_Send_Byte,入口参数为要发送的字节2 {" n% s* Z' q4 L
  257. static void IIC_Send_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t txd)     8 U2 _4 u! ^! `9 U  j1 X
  258. {
    5 G, O( F$ u+ {" G, f' n
  259.      uint8_t t = 0;   ( S" [/ H) b' }, g, k* H  D% o
  260.      SDA_OUT(IIC_Type_t);      0 I8 u; V# `$ z' V
  261.      IIC_SCL(IIC_Type_t,0);//拉低时钟开始数据传输
    2 i8 r% C$ H5 L( E1 N
  262.      for(t=0;t<8;t++)
    # k" A8 E: d- c$ J
  263.      {              6 A; [* c4 C- ]. v
  264.           IIC_SDA(IIC_Type_t,(txd&0x80)>>7);1 I6 Q) T: S$ l- @4 ]( m8 D
  265.           txd <<= 1;   
      ~  e6 w7 g" j' l; c/ |5 F; s
  266.        IIC_Type_t->delay_us(2);     //对TEA5767这三个延时都是必须的, R$ X, t6 w' ]. J
  267.        IIC_SCL(IIC_Type_t,1);# |: I" F9 f) v- d. P8 P. h) s
  268.        IIC_Type_t->delay_us(2);  
    ( f$ t' M( q8 d
  269.        IIC_SCL(IIC_Type_t,0); ! ^8 L6 o" {' P+ p& g
  270.        IIC_Type_t->delay_us(2);  
    & I' H, L$ z$ n/ D1 @: Z' t# |
  271.      }  & R# {6 z. E3 O& u( o
  272. }7 V0 r7 [- u: h5 x
  273. //IIC_Send_Byte,入口参数为是否要发送ACK信号
    ( Q& r5 q6 G# j: W6 O3 p
  274. static uint8_t IIC_Read_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t ack)     ( O4 |- O" j$ B0 B* F) C% \* a: n
  275. {
    8 p* a: S: _9 o* X, F( ^  p
  276.    uint8_t i,receive = 0;1 V( p( q6 A: c
  277.    SDA_IN(IIC_Type_t);//SDA设置为输入
    ' d4 J$ }- U0 ]3 F, O" r6 v
  278.    for(i=0;i<8;i++ )4 ~9 M- |: P$ @2 K* s  `: a
  279.    {
    / Z: E( G- s! g
  280.       IIC_SCL(IIC_Type_t,0);
    ! Z$ [5 V6 _; S2 N. l# c, N' R
  281.       IIC_Type_t->delay_us(2);
    ) p' O; ^$ c; r- U
  282.       IIC_SCL(IIC_Type_t,1);3 V* k9 G( b1 T+ Y3 U8 o) H8 ~. X
  283.       receive<<=1;
    7 F$ p' z( w' u" ?3 Z4 [2 R
  284.       if(READ_SDA(IIC_Type_t))receive++;     ^  c2 C) K6 U; g" t  o
  285.       IIC_Type_t->delay_us(1);( J/ q$ I2 F+ K( h# Q( M3 I' W' v
  286.    }      % T1 t* w( V8 C2 p9 Z
  287.   if (!ack)
    ! J5 y9 b1 ]2 R# |8 _6 u) u# E
  288.          IIC_Type_t->IIC_NAck(IIC_Type_t);//发送nACK3 m! w% i- T6 s$ ^8 L( A
  289.   else
    . S$ L* p% p1 a, r5 @1 p
  290.          IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK   
    " }4 S; `2 U, N1 n7 a& z: z: E
  291.   return receive;' B) F9 z+ T& x! _- C
  292. }( q: q3 {4 k  f) T$ X$ g( v  p
  293. //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用
    9 F/ E5 W, \, y/ s
  294. IIC_TypeDef IIC1 = {# e9 z5 g7 S" a% B! @
  295.   .GPIOx_SCL = GPIOA,   //GPIO组为GPIOA
    & U5 C# S8 Y/ h5 T9 {9 C- [; n; a
  296.   .GPIOx_SDA = GPIOA,   //GPIO组为GPIOA5 _: L" |/ V2 [4 g) \! X, z& q. Z
  297.   .GPIO_SCL = GPIO_PIN_5,   //GPIO为PIN5
    8 E3 P' z& u1 q! K
  298.   .GPIO_SDA = GPIO_PIN_6,  //GPIO为PIN6; }* w/ U1 w6 R" d& V: X6 O
  299.   .IIC_Init = IIC_Init_t,) m0 G1 _, K: q, K: B1 y- I4 u
  300.   .IIC_Start = IIC_Start_t,. B5 Q& O7 N; B% S
  301.   .IIC_Stop = IIC_Stop_t,
    , v. H3 b$ y$ d, J$ Q3 C
  302.   .IIC_Wait_Ack = IIC_Wait_Ack_t,
    % Q7 u0 n9 x' E
  303.   .IIC_Ack = IIC_Ack_t,* v/ I4 F9 p) B$ W' c2 n' x& v' _
  304.   .IIC_NAck = IIC_NAck_t,
    + ~  P# }4 b4 y! s; |1 v8 n
  305.   .IIC_Send_Byte = IIC_Send_Byte_t,
    * ?( m* i& s1 l6 ~8 O) q: X
  306.   .IIC_Read_Byte = IIC_Read_Byte_t,5 |  y* m5 t0 {
  307.   .delay_us = delay_us     //需自己外部实现delay_us函数+ k3 i2 X  D, A
  308. };
复制代码
上述就是IIC驱动的封装,由于没有应用场景暂不测试其实用性,待下面ATC64的驱动缝缝扎黄写完之后一起测试使用。
( g3 C5 T$ v. Z; x7 h2 Z; m4 [; U/ c) k' O

* G6 c/ Q: p0 d. M' m/ XATC64XX驱动封装实现: ^. b! X( u: c+ f: l+ N
    at24cxx.h头文件主要是类模板的定义,具体如下:  T0 V$ `$ ^$ c; F* h. i
+ {; y! n2 j6 m( z, z
  1. // 以下是共定义个具体容量存储器的容量$ T1 T$ f' k6 E; @& V  g( G- q& F
  2. #define AT24C01  127
    % w" ]+ Q7 }. L
  3. #define AT24C02  255
    : n& M: {- q( }1 J, a1 h7 \* v
  4. #define AT24C04  511& `. [$ ]8 k$ `1 A0 E  N7 Z- o
  5. #define AT24C08  1023
    & c( D9 T0 L  O; R- L* l
  6. #define AT24C16  2047' H$ Y2 d. ?+ u% V" o: o0 A9 L: F" L
  7. #define AT24C32  4095' U/ p8 u6 W& ]0 x6 `( J+ r7 a
  8. #define AT24C64   8191         //8KBytes
    1 n* O6 Z6 j' o3 `0 Z/ a
  9. #define AT24C128 16383) _# \1 X" A+ e: ^9 T3 F" a% ]
  10. #define AT24C256 32767  
    8 G( m, X' v' }6 R" Q

  11. 5 @8 }& Q4 u( s
  12. //定义AT24CXX类
    ( |# i7 y4 T+ ~) |! S7 ^' e) x
  13. typedef struct AT24CXX_Type
    & N- ~3 t( E$ }! b7 s8 `
  14. {
    ( q' L8 e( ]1 u# C1 H- x
  15.   //属性7 Y- y; _* Y) s
  16.   u32 EEP_TYPE;           //存储器类型(存储器容量)7 `) J) [; w8 ]1 ?1 G
  17.   //操作
    5 z$ \& Q" l5 \" M
  18.   IIC_TypeDef IIC;       //IIC驱动$ Q* \. F( F, r9 S1 P
  19.   uint8_t (*AT24CXX_ReadOneByte)(const struct AT24CXX_Type*,uint16_t);  //指定地址读取一个字节
    , ~/ \. |3 D* o
  20.   void (*AT24CXX_WriteOneByte)(const struct AT24CXX_Type*,uint16_t,uint8_t); //指定地址写入一个字节$ Z# W! f5 y1 i1 l' q1 U9 L9 d
  21.   void (*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t); //指定地址开始写入指定长度的数据
    " N# {6 @9 [" s3 l; e: `
  22.   uint32_t (*AT24CXX_ReadLenByte)(uint16_t,uint8_t);   //指定地址开始读取指定长度数据
    8 K2 u$ N$ o, D! l! `1 S$ v1 Z
  23.   void (*AT24CXX_Write)(uint16_t,uint8_t *,uint16_t);  //指定地址开始写入指定长度的数据7 w+ y% d! `7 t* f. Y9 v, b2 w
  24.   void (*AT24CXX_Read)(uint16_t,uint8_t *,uint16_t);   //指定地址开始写入指定长度的数据! L: {+ Q0 H2 J3 e" r
  25.   void (*AT24CXX_Init)(const struct AT24CXX_Type*); //初始化IIC
    . S: e5 a5 P# C- O" k
  26.   uint8_t (*AT24CXX_Check)(const struct AT24CXX_Type*);   //检查器件* T3 Q1 x, t) \1 \
  27. }AT24CXX_TypeDef;
    6 W0 m4 h! w5 k) U

  28. 0 b4 l/ }; ~: a  _4 H; i
  29. extern AT24CXX_TypeDef AT24C_64;     //外部声明实例化AT24CXX对象
复制代码
at24cxx.c源文件主要是类模板具体操作函数的实现,具体如下:
# R' Y' X6 q& p6 K  F
  1. //在AT24CXX指定地址读出一个数据
    ( F7 C& }4 k5 [5 w0 k
  2. //ReadAddr:开始读数的地址  3 O0 N' b3 ~  G# T  T  C
  3. //返回值  :读到的数据$ L, E; S( V# n# X/ ]. B3 O
  4. static uint8_t AT24CXX_ReadOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t ReadAddr)
    6 b( L: ~7 A8 i' I" Z
  5. {      * x  n5 S4 j" U3 P9 c4 K- t
  6.   uint8_t temp=0;                          
    3 \4 \! s0 c& t. P
  7.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);  * ~3 X% \0 Z- f9 Q5 @6 {. e
  8.   //根据AT的型号发送不同的地址; h  m# w6 [9 A/ \* T: O; |- G
  9.   if(AT24CXX_Type_t->EEP_TYPE > AT24C16)
    7 }) _# M9 L% N9 ~, g  t
  10.   {3 n6 B0 f% W1 o
  11.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令! o+ a% ^) R& ?+ {. Y0 V
  12.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    ( ^5 a/ n" d  q" T
  13.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//发送高地址     3 O; k# d6 j9 ]; I$ P; U
  14.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据     ; W$ S' F7 R' ^4 I9 n) c$ s1 m
  15.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC); # h" H1 B/ H4 d  Q! Z, c1 w
  16.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256);   //发送低地址1 {* ~0 g; j& c2 Q6 L7 w5 s
  17.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     
    ( t) n4 c7 E$ ?4 D- V# q2 d" t7 q" g
  18.   AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);        
    ; b4 {: D# Y& v1 k5 v/ z
  19.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA1);           //进入接收模式      " t6 v& \. o- l- X- B# i
  20.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);  
    $ m# V3 r* S7 n
  21.   temp=AT24CXX_Type_t->IIC.IIC_Read_Byte(&AT24CXX_Type_t->IIC,0);     ' d7 O4 k) ^2 z! E1 p  R6 V$ o
  22.   AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件     ) L8 P1 ^" [2 o* a1 X
  23.   return temp;) t# E3 o, L- q! r
  24. }. b4 f$ P& U9 c# {5 ~
  25. //在AT24CXX指定地址写入一个数据  K* p# {( }* ~
  26. //WriteAddr  :写入数据的目的地址    + E( Y2 Y8 I. {8 L/ O, [8 }7 K. N+ `
  27. //DataToWrite:要写入的数据% T5 q3 B0 V6 V- F! z
  28. static void AT24CXX_WriteOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t WriteAddr,uint8_t DataToWrite); N- F+ {$ @3 V. ?' M- n- E
  29. {                                
    / `$ h: e) c1 Q
  30.    AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);   
    4 S3 B- _7 E1 R4 @2 D# {$ G1 J
  31.   if(AT24CXX_Type_t->EEP_TYPE > AT24C16)  V8 n: b3 b6 _. n2 S+ s
  32.   {
    4 k6 z# }  _. C4 `0 s$ `7 ]3 q
  33.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0);    //发送写命令/ [% b' y3 U" L0 a6 ^' y) `
  34.     AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);+ O- ]' E! P. ?& p- N5 {
  35.     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//发送高地址     
    * A' Y! T) O9 J" P' a* g) B) @
  36.   }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据     ( z/ a  c9 X8 t: m  v
  37.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
    ! M7 n; ^' Z, n, z
  38.    AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256);   //发送低地址
    0 W- o: y3 V- m
  39.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);               - t6 Q. P" t% f& H* b, P
  40.   AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite);     //发送字节          / X6 A- F7 E1 E% \# L
  41.   AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);            
    . P1 j) S9 f- ?" D. H: x0 w6 a
  42.    AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件
    ' u/ f. E" y' @6 D) K4 B- l4 Z& X
  43. AT24CXX_Type_t->IIC.delay_us(10000);  ( C& H' n" E6 a$ ^3 v, c7 p; w
  44. }# R- e+ y, G3 |, O
  45. //在AT24CXX里面的指定地址开始写入长度为Len的数据  A% p' j9 n: ]- g5 a1 H/ R
  46. //该函数用于写入16bit或者32bit的数据.
    * `( A* N! C$ x3 Z2 I9 v/ F
  47. //WriteAddr  :开始写入的地址  
    ( ]3 C! r8 m, v3 v0 \, a$ k
  48. //DataToWrite:数据数组首地址
    + M8 `! P6 k" Z& b
  49. //Len        :要写入数据的长度2,4. i) }$ R$ l0 i; Z( \  s
  50. static void AT24CXX_WriteLenByte_t(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len)
    % j" ]; K, S) G* p
  51. {   
    9 G/ O  U: C* [! o" g
  52.   uint8_t t;& p9 T* ~0 Y3 w5 g& B6 s
  53.   for(t=0;t<Len;t++)
    : v* k) |$ ^! u2 F: [, @
  54.   {
    . m: {; i( Q- C% p
  55.     AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
    : y1 b+ g/ ^+ {( g0 w- ]
  56.   }                0 s' E; \& W3 S/ a4 F5 G5 p6 V
  57. }) X* k; j2 ~& `$ D
  58. //在AT24CXX里面的指定地址开始读出长度为Len的数据
    5 w( _  z) o1 E/ k
  59. //该函数用于读出16bit或者32bit的数据.
    , d& d2 v+ w: B+ `
  60. //ReadAddr   :开始读出的地址 ; D6 O4 E, W8 B
  61. //返回值     :数据
    , Q1 @: l. X1 W$ h) P) S0 C
  62. //Len        :要读出数据的长度2,45 a/ |2 m( i4 X5 w4 ~* U
  63. static uint32_t AT24CXX_ReadLenByte_t(uint16_t ReadAddr,uint8_t Len)) Z$ ^  l) l& Q8 \  B
  64. {   + N. t# Q9 ^0 B( V8 j
  65.   uint8_t t;
    & E+ i- p+ S8 ]6 G% Z% K  o% d/ A/ x
  66.   uint32_t temp=0;
    ; C$ j$ p9 G( l6 ~( a& W- H  D
  67.   for(t=0;t<Len;t++)
    : O, N* J/ x6 @6 x/ `
  68.   {9 T0 W) k8 E7 V% @' \! T5 D
  69.     temp<<=8;
    : {# X; ~2 y$ U4 y' s) R) s7 ?; @, V
  70.      temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);          # j6 N  B% ]7 w
  71.   }" l7 C; ]0 Z6 }8 f) p5 M8 t5 I
  72.   return temp;               
    , L* z5 r7 l5 X9 [+ e/ F. ~( p$ k
  73. }
    0 H+ C7 ?  U8 n* A
  74. //在AT24CXX里面的指定地址开始写入指定个数的数据7 h: w# ], g) f* w9 a: [3 s
  75. //WriteAddr :开始写入的地址 对24c64为0~8191* I8 q& y& k) L
  76. //pBuffer   :数据数组首地址
    0 e8 K3 n- R. y0 ]
  77. //NumToWrite:要写入数据的个数
    9 d- V' p. F- F. s9 }+ F
  78. static void AT24CXX_Write_t(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)
      G/ ~& N+ X2 F& Z4 Q7 R  D
  79. {
    % ]- Q. _; h8 V$ E; d
  80.   while(NumToWrite--)
    , x. N( c3 B5 |4 u8 Y
  81.   {; z" Q9 Z( N% w4 y: q
  82.    AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    ) d- i0 m2 l$ r( P7 s3 I5 ]
  83.     WriteAddr++;2 p1 C3 ?8 ^& d5 A  a
  84.     pBuffer++;4 e1 t8 S+ y4 ]4 g9 A- H
  85.   }
    0 ^  s7 u4 t+ A
  86. }) r- O  v* \0 W' x. R: l+ H
  87. //在AT24CXX里面的指定地址开始读出指定个数的数据
    1 m. k1 }( P' }7 x
  88. //ReadAddr :开始读出的地址 对24c64为0~8191( G& d# q% s1 N* T" y& s
  89. //pBuffer  :数据数组首地址
    " V" u! c6 E/ L, `. L+ }8 Q1 V* h9 i
  90. //NumToRead:要读出数据的个数
    / B- ^) g4 ^: j$ j/ J
  91. static void AT24CXX_Read_t(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead)
    8 C$ H" _- s2 y' r7 G
  92. {
    : _7 ~% ]1 A7 y
  93.   while(NumToRead)
    3 D4 d( J0 }& H# I+ H  Z
  94.   {
    8 J; _4 \7 |0 y
  95.     *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); & e4 G$ r- q( q3 m1 [$ d
  96.     NumToRead--;: O. {3 |4 ]( H; b7 j
  97.   }
    ) |9 c5 ~- `- _' j
  98. } 0 {6 ?5 v8 {: o4 Y
  99. //初始化IIC接口  g$ Z) f6 ?/ Z( ]' v2 x
  100. static void AT24CXX_Init_t(const struct AT24CXX_Type* AT24CXX_Type_t)
    0 s7 E' y: n4 f9 n6 z8 [* B4 ^, G5 f
  101. {
    " V; F% A1 D3 L; M; h  j* d
  102.   AT24CXX_Type_t->IIC.IIC_Init(&AT24CXX_Type_t->IIC);//IIC初始化3 `' v' A4 V: B6 j8 z
  103. }0 a  h1 O, C5 c) t8 V& W1 x
  104. //检查器件,返回0表示检测成功,返回1表示检测失败
    . U6 Z% q1 F! {- @7 ~
  105. static uint8_t AT24CXX_Check_t(const struct AT24CXX_Type* AT24CXX_Type_t)   
    . M0 T" t% b7 C' I# s: a
  106. {
    & }; l5 b; f" k9 E( K# ~
  107. uint8_t temp;4 X% U, n; G' K5 A$ d- K! z
  108.   temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);//避免每次开机都写AT24CXX      * f6 R6 N+ G5 d
  109.   if(temp == 0X33)return 0;     
    ) p8 h9 ^9 k+ Z/ z
  110.   else//排除第一次初始化的情况
    $ e$ T+ v& z% c
  111.   {" Q$ r! |- U! C* g: [3 J
  112.       AT24CXX_Type_t->AT24CXX_WriteOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE,0X33);
    0 u* H% V9 J, ~0 e3 a$ U3 h* c4 I
  113.        temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);4 H# y& h. `, H# C: x3 b# ~5 K
  114.       if(temp==0X33)return 0;# H9 T% ~% v: |0 J+ r8 g  d. v; P
  115.   }
    2 s1 t) r. @* Q7 X
  116.   return 1;  ' }  Y- ]* r& @/ u6 p3 w3 j
  117. }8 Y5 p3 Z) f+ @5 l
  118. //实例化AT24CXX对象
      e' G$ ]8 r4 I6 n  K
  119. AT24CXX_TypeDef AT24C_64={: d% b5 y' e( ]/ a9 _6 `
  120. .EEP_TYPE = AT24C64,           //存储器类型(存储器容量)3 D! z" [5 k+ p8 P* D$ X! ~
  121. //操作
    5 x- N) M, f4 l) P
  122. .IIC={
    8 ]9 R: \7 M9 k) X! f( J+ C
  123.   .GPIOx_SCL = GPIOA,
    ( M( ]$ {* k0 `' g* U9 y
  124.   .GPIOx_SDA = GPIOA,; @; H" W0 C) N6 s7 w) m+ G
  125.   .GPIO_SCL = GPIO_PIN_5,* K; z3 t- l! H3 B) Q4 s5 o
  126.   .GPIO_SDA = GPIO_PIN_6,
    . v5 N1 d; N& z( n/ |, q" d
  127.   .IIC_Init = IIC_Init_t,
    + m. h3 |: T" X, u) `) O
  128.   .IIC_Start = IIC_Start_t,
      |2 K7 |8 T+ T$ T; q/ D# I
  129.   .IIC_Stop = IIC_Stop_t,
    1 V. y- e& }8 D. R8 i7 }# A
  130.   .IIC_Wait_Ack = IIC_Wait_Ack_t,
    4 [$ Q2 Q# P( a! R% H  x9 m
  131.   .IIC_Ack = IIC_Ack_t,4 L' L$ P: x& e" V. I$ m
  132.   .IIC_NAck = IIC_NAck_t,
    7 p/ b6 i/ N% h
  133.   .IIC_Send_Byte = IIC_Send_Byte_t,/ w  v/ G: h8 V
  134.   .IIC_Read_Byte = IIC_Read_Byte_t,8 t! u9 L1 n$ l% h4 M
  135.   .delay_us = delay_us5 N( }, Q) e( E( A7 ^+ H! ^
  136. },                   //IIC驱动7 ]; M- k* S) z" L0 b9 w$ R
  137. .AT24CXX_ReadOneByte = AT24CXX_ReadOneByte_t,  //指定地址读取一个字节8 \/ ^7 P+ U% i6 u
  138. .AT24CXX_WriteOneByte = AT24CXX_WriteOneByte_t,//指定地址写入一个字节" f! i$ N( D: b* E+ X
  139. .AT24CXX_WriteLenByte = AT24CXX_WriteLenByte_t, //指定地址开始写入指定长度的数据2 G; H4 l6 c4 n2 |
  140. .AT24CXX_ReadLenByte = AT24CXX_ReadLenByte_t,   //指定地址开始读取指定长度数据
    / ~" N. W  W  Z, k8 s/ D( q
  141. .AT24CXX_Write = AT24CXX_Write_t,  //指定地址开始写入指定长度的数据
    3 w0 y, }: {1 Y4 T7 Y: J
  142. .AT24CXX_Read = AT24CXX_Read_t,   //指定地址开始读取指定长度的数据
    3 Y6 a1 o' F0 v, b  R; C/ z
  143. .AT24CXX_Init = AT24CXX_Init_t, //初始化IIC& T5 d) D$ E  y- P. H
  144. .AT24CXX_Check = AT24CXX_Check_t   //检查器件
    3 i9 Q* M# d) b2 o: C0 {
  145. };
复制代码
简单分析:可以看出AT24CXX类中包含了IIC类的成员对象,这是一种包含关系,因为没有属性上的一致性因此谈不上继承。
. _" f2 Z8 \! L9 u" j0 Y+ b) U" ]
: r, ]5 n% q+ _: j1 c
2 e( A/ v$ D' e4 R* [( W
    之所以将IIC的类对象作为AT24CXX类的成员是因为AT24CXX的实现需要调用IIC的成员方法,IIC相当于AT24CXX更下层的驱动,因此采用包含关系更合适。
4 R) n: t- `: ?9 A' u
+ E; Y, u) J& y7 d; H6 @- B
, U! n5 k( P0 ~4 v6 t( e  e
    因此我们在使用AT24CXX的时候只需要实例化AT24CXX类对象就行了,因为IIC包含在AT24CXX类中间,因此不需要实例化IIC类对象,对外提供了较好的封装接口。下面我们看具体的调用方法。
" y9 b3 Q' k9 W8 d- Q. q! C8 L* d* ]- N
! d) N5 R4 V; U# R9 y
主函数main调用测试
+ q. w3 @: Q& d5 p% A! w    在main函数中直接使用AT24C_64来完成所有操作,下面结合代码来看:' M5 \- ?" ]( ?' f1 U. u
7 |! y' ~  e, Q9 r/ n  w: Y$ p+ H

  1. / H* N! L% A8 G1 q9 V1 B8 n# [" |+ U- S% m
  2. #include "at24cxx.h"    //为了确定AT24C_64的成员方法和引用操作对象AT24C_645 F# P) v  i9 C: L- [& G4 G
  3. int main(void)/ \7 p. r) p4 a9 W% b9 W2 A7 @
  4. {  v! j8 a% K7 \0 c! i
  5.   /************省略其他初始化工作****************/! e0 D/ g$ }3 \4 u2 G6 B$ k
  6.   //第一步:调用对象初始化方法来初始化AT24C642 n7 a( L) D% X6 ?! U
  7.   AT24C_64.AT24CXX_Init(&AT24C_64);' O  l6 r' p5 z8 j, b+ I
  8.   //第二步:调用对象检测方法来检测AT24C64           8 G6 Z: @2 K! }# g6 k# |: p5 Q0 N
  9.   if(AT24C_64.AT24CXX_Check(&AT24C_64) == 0)5 z' t3 S4 r+ _
  10.   {
    . l( N0 c" x! i* j! I
  11.     printf("AT24C64检测成功\r\n");
    ( E1 N# x  u! Z
  12.   }9 v% ~. u: P2 h0 [" Q$ S7 \* O
  13.   else{
    ) h! e! `3 _9 Q1 k* ]7 h) ]$ V
  14.     printf("AT24C64检测失败\r\n");" U& k1 ^( }7 a% \3 ]1 |
  15.   }
    4 q- ^/ U4 |1 F# N" h
  16.   return 0;
    # e9 s( J7 j# m- i. X
  17. }
复制代码
可以看出所有的操作都是通过AT24C_64对象调用完成的,在我们初始化好AT24C_64对象之后就可以放心大胆的调用其成员方法,这样封装的好处就是一个设备对外只提供一个对象接口,简洁明了。
2 q# K" N+ _  i% Z9 U5 g
9 Z4 u. c1 f, C: u' j; f
, D8 t& z# \, j% O# k/ j2 i# s1 f% V
总结6 U$ W8 `. H5 q! p/ ]$ U4 B
    本文详细介绍了面向对象方法实现IIC驱动封装以及AT24CXX存储器的封装,最终对外仅提供一个操作对象接口,大大提高了代码的复用性以及封装性。
9 ~9 s; O8 V6 {) r: [2 _. F
% ?. K8 U, N; {* s; Z- q2 j* [
% O3 ?; ?' i9 G

& q7 o1 w0 n# z) \+ D
赞 收藏 评论0 发布时间:2021-6-21 14:39

举报

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