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

【经验分享】STM32的I2C的原理与使用(24C02附代码)

[复制链接]
STMCU小助手 发布时间:2022-5-16 11:39
一、IIC的定义7 W6 `% K) R+ y1 K2 L) v
    I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS开发用于连接微控制器及其外围设备。IIC是一种多向控制总线,就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源。这种方式简化信号传输总线。: X) E; J  S% I2 O' K: G' w
/ g' }$ a# n/ o$ O
    它由数据线SDA和时钟SCL构成的串行总线,接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上,可发送接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。$ V5 c7 ^2 B1 C  E% x4 Y
/ N7 Q- b; f( E; W* ~" z6 \* S
IIC是半双工通信方式。
; j* e1 A# y0 S/ N. j7 c  Z, o% f5 v& {9 p( F$ `, ?. V
二、多主机I2C总线系统结构

) r3 a/ c7 m9 i* J. e
' \0 @8 B/ Z) [% }+ k6 P. A }M5]PGQMB1%OM2_4Y0~B8MT.png
9 v6 I2 y( }+ w1 a$ G+ ]# S8 Y7 t) a9 \1 T
2)多设备的使用举例  M$ B8 y+ B+ j3 W- |
) U! b3 P3 k6 R, B" ?6 T! Q7 l' ?
每个接到I2C总线的设备都有一个唯一的地址
7 f+ p! {% T: y
7 _, K9 H; a; ^. E# W/ } 5Z9N)E93D7]4(WCF2HDUC[G.png . K! L: B$ p/ J+ U* B. j3 R

& r0 p, _3 B* q. g0 \0 j" d2 H; P三、I2C协议
- L, @. C; R% X( L+ ]7 P& z空闲状态
( u8 G8 N+ ~9 x/ I2 E$ _! `5 d开始信号; b4 k; C( C6 n$ S8 b, |; L
停止信号" v7 m, L5 p- @" O, d
应答信号
& _3 q+ C$ H% A) t0 F! I: q. H数据的有效性! |+ O9 j$ j% R& W8 B. d
数据传输
  Z7 ~! `: c( J' g2 l我们以斗地主为例:7 X; s7 ~0 L" `+ M- e: v

8 i. v3 m2 @- |# `4 E, C 20190611223011427.png
; R: S  D# a  T! ~" V" g% L& V, A: z6 [
% s/ }' R# k& i2 y1 i* g0 X1)空闲状态+ J9 Z2 t! u! R: N2 Q
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。$ R( I# T$ h7 A; ]4 `. |& b+ N
/ ?( ?; G, M/ [$ \7 b3 y9 ]# }
2)起始信号与停止信号* Y9 b, P4 |- v
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
% W1 C" l2 J$ N: j6 O- Y停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
$ {& x( Z' V% p8 \
( R" N& ~% A7 _  K) a9 h4 P 20190611223045576.png
& d' J7 O9 h$ q
% a. \/ X- T: V3)应答信号ACK, \# ]  R8 S9 k7 B# E" u# l
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 8 C; s- w8 i2 R

5 W; F% \9 s, F: _& s) ]对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。- X! N+ ~, ?" c$ i

5 u% Z. J  a( K4 s+ [- i H1}S%IN@1{{B36EYI66SKD7.png
3 @9 e/ _. Y2 @, r% A& s1 `- \8 w2 q
4)数据有效性
3 q& i4 j# u. O, L  o7 FI2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
( q" ]/ c: }; [+ g5 G5 D" X
/ x6 W% r6 S7 Q& V即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。
, f# Z4 A* [5 E0 p, O, i; ]2 k2 _" O" R: J, [% e0 O2 s
28163734-16f9cd046fe34ad89f098aa2d5179f16.png 6 g" M% U/ ]! e3 a4 L& E6 \3 o
$ l9 e$ q" `1 K
5)数据的传送
% _! {) t% {$ I$ q! Y2 u6 D在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。9 e: a+ c% |& ?
( H" g, m& i$ H- p6 ?1 T
STM32F4的IIC代码如下:, u# f$ G. G$ \5 N- o! m1 x
  1. IIC.c
    3 R$ T! ?" F  o% B* X
  2. #include "myiic.h"
    1 O9 }0 G) w) [# {; k- s  f1 p
  3. #include "delay.h"
    & j- H' j5 N  y% x: }9 g
  4. ; B8 B1 x+ [/ L" n. ~9 p8 z% `( V5 T
  5. //初始化IIC
    ( W+ Y& o, O9 C9 R: v9 f! E
  6. void IIC_Init(void)% R7 j6 @& l) C- S' I
  7. {                        $ ]4 E. l# C2 q& H
  8.   GPIO_InitTypeDef  GPIO_InitStructure;
    $ l# S, ]  W5 ]- \2 n8 j% ~

  9. , P& q$ S: a+ U; o2 B
  10.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟- e* q3 b8 Q+ p$ q. }) [
  11. ' P9 w% L% d3 P$ ?/ h
  12.   //GPIOB8,B9初始化设置
    0 e) X( z6 H: [- v
  13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    5 D* f* k: \) N
  14.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式# [+ U9 C( O: j8 I; f
  15.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    . B# J% Z+ W6 T3 G% C3 C
  16.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    & b, X7 K; Y& I  \* G$ _
  17.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉: R% m0 p3 U6 w6 N( ?
  18.   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    2 D, d2 f, b/ T. C
  19.         IIC_SCL=1;3 L' v' B& O* U- Y3 @4 l
  20.         IIC_SDA=1;
    4 Q# B3 ]; K8 H7 f1 a. `
  21. }7 w1 H% a  w2 ]6 L3 H! ~; A! D
  22. * c9 ]- {; x& Y+ G4 C! E& q
  23. //产生IIC起始信号
    * L6 M( L( ~: Q$ K' Y
  24. void IIC_Start(void)' X  i, e- D% V; N0 A/ a
  25. {
    1 z8 {5 s2 s0 A$ z# _- B
  26.         SDA_OUT();     //sda线输出- N7 r; {, L& r9 j) f2 i! o
  27.         IIC_SDA=1;                    
    : {5 R- B, i. g& I( W
  28.         IIC_SCL=1;
    0 c9 u9 D" }5 G4 [
  29.         delay_us(4);
    5 x5 `( `( b. V) G0 h
  30.          IIC_SDA=0;//START:when CLK is high,DATA change form high to low / N, z" |$ N1 G- Y* ?# B% c
  31.         delay_us(4);" o5 `% b: x% C% K% ~& R
  32.         IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 ; W* ]1 [# R- ~. x# Y& |
  33. }2 t: {$ f; S# k
  34.          
    ' p. C0 {* J' q  @  q; Y9 w
  35. //产生IIC停止信号1 u) m3 ~+ [2 M' i7 ~
  36. void IIC_Stop(void)& N  m7 D( p8 e% R
  37. {2 I& v1 E; }+ [% L0 G* Y
  38.         SDA_OUT();//sda线输出, U0 w) {2 I( g5 X5 t3 K" e  ?
  39.         IIC_SCL=0;
    0 D* l! E% K/ p) R1 A. k4 v
  40.         IIC_SDA=0;//STOP:when CLK is high DATA change form low to high1 D# x0 ]- S! F" P4 e' {3 }" `
  41.          delay_us(4);
      z: ^7 h& H1 H/ y9 K  k* v
  42.         IIC_SCL=1; : d) r9 n( R- \9 p1 z
  43.         IIC_SDA=1;//发送I2C总线结束信号6 D0 o7 {8 u3 j2 Y. U% b
  44.         delay_us(4);                                                                   ' A- v; |1 l; p2 O9 Y. O% b: Q& J
  45. }7 P% @" Q0 ?0 Y/ ?: K7 c
  46. # g3 v$ ?9 f: t( Z7 y/ @! p, X2 V
  47. //等待应答信号到来
    * F( i, T5 J+ A" q- v+ X# |6 B# x) o' \  S
  48. //返回值:1,接收应答失败
    ) m3 L+ W! Z  l- Y* h9 R
  49. //        0,接收应答成功
    1 g3 W3 U+ D2 F% ?
  50. u8 IIC_Wait_Ack(void)* Z7 I- y$ a, l. }; `8 S4 |
  51. {
    ; j+ \9 [) i' @  ?/ H4 o6 f
  52.         u8 ucErrTime=0;
    ; I* d4 G* M& l5 d1 U0 g: p
  53.         SDA_IN();      //SDA设置为输入  " k! h. U! ?7 A! t; Z
  54.         IIC_SDA=1;delay_us(1);           
    3 p" R' E2 F6 \) P" F4 Y% D) l
  55.         IIC_SCL=1;delay_us(1);         5 q% J0 @+ L, h0 q5 f% f  [/ I' x
  56.         while(READ_SDA)
    1 h& w- Y2 b+ m4 @
  57.         {
    ) `8 h- n" m* F6 H3 ~9 _
  58.                 ucErrTime++;: A+ X) ^# U3 S) `. F" L
  59.                 if(ucErrTime>250)
    3 A& o. U" }; b8 o. _
  60.                 {0 ]* n. w+ c0 ~$ X! q  w
  61.                         IIC_Stop();# D3 r6 N7 C) u5 x# \" C
  62.                         return 1;
    9 @3 i: I8 ]  _9 g3 m7 o& T$ o
  63.                 }
    " n7 F3 o8 X  g4 c. C( |4 o0 p  `3 x
  64.         }9 _6 b" ^9 \; J& y/ S! I
  65.         IIC_SCL=0;//时钟输出0              M) @% ]3 B/ j2 }0 M
  66.         return 0;  1 ]( O1 {1 j" R9 ~0 I2 b
  67. } - H9 ^; D& K1 z# {2 N

  68. / q# y( S% e; `0 j0 T2 F% H6 G- J
  69. //产生ACK应答
    , {! M2 U: `+ P8 Z2 p! C, I6 f
  70. void IIC_Ack(void)# G! p7 o, X, C5 w0 m8 P# n7 a
  71. {
    " S2 Q* U0 F; `/ x" r4 B) o
  72.         IIC_SCL=0;3 U* s* @  `% {1 Y
  73.         SDA_OUT();) @/ B$ k: C1 \3 G  @
  74.         IIC_SDA=0;$ m0 \4 z" m- ^! o
  75.         delay_us(2);6 [$ @5 B0 Z4 x
  76.         IIC_SCL=1;
    % M% g$ s! C. H% n' m
  77.         delay_us(2);
    - z: V# S- z2 C) e& E' i' W
  78.         IIC_SCL=0;
    5 l- Y- Z, `) f2 q
  79. }
    - }3 u- H  e2 ^; O  p5 x/ _
  80. ! g2 B+ V# p# @% K5 c
  81. //不产生ACK应答                    
    : @+ G$ |7 q6 R: O
  82. void IIC_NAck(void)
    6 o6 L! H. D: R5 n) w( Y
  83. {
    * u* e, e5 x' G
  84.         IIC_SCL=0;
    2 o& Z7 G! q) x* _
  85.         SDA_OUT();
    8 r2 E- o+ t8 a( {
  86.         IIC_SDA=1;2 w8 }) T8 o. i- N1 n/ S; s
  87.         delay_us(2);
    8 A6 e3 m9 m: D; g( J( X# P' M; s
  88.         IIC_SCL=1;3 S" C6 {$ k/ \; ~0 G0 Q+ R& ?- m
  89.         delay_us(2);
    + G8 X; b6 b, p  z- r
  90.         IIC_SCL=0;; p9 L) `: j+ L. p/ h" g
  91. }$ N1 w+ i0 S- q. K; Q0 Q- s( [
  92.                                                                               8 c* A1 D2 I: `
  93. //IIC发送一个字节: R& a6 g' x. x  v) V
  94. //返回从机有无应答0 X$ H: Y  Z: I$ }3 f) B6 E6 ]! g
  95. //1,有应答
    ! {5 U/ _1 D4 `. i' P
  96. //0,无应答                          , q. C3 I6 N  q& g' g1 j
  97. void IIC_Send_Byte(u8 txd)8 c5 [0 x1 u1 N: S
  98. {                        
    % }! J1 A8 H7 V6 H
  99.     u8 t;   " j# F) w. N. s' Q! @
  100.         SDA_OUT();             # ]% {+ @! Y+ }& B
  101.     IIC_SCL=0;//拉低时钟开始数据传输% U" [6 e3 ]1 g1 }" z9 R+ r2 B
  102.     for(t=0;t<8;t++)' Q) z% |6 X5 Q/ C6 F  s
  103.     {              + }! d, Q) [4 w3 k+ g
  104.         IIC_SDA=(txd&0x80)>>7;0 P1 E4 h; n7 |: V8 l
  105.         txd<<=1;           
    & T" _  A9 t# U4 x
  106.                 delay_us(2);   //对TEA5767这三个延时都是必须的
    + @: v3 ?  e1 |2 o  v, X9 v' X+ f
  107.                 IIC_SCL=1;+ @- y& D% p" E1 C
  108.                 delay_us(2); 6 O* P; j9 C5 F3 e
  109.                 IIC_SCL=0;        
    " t; w  d/ v8 f5 d
  110.                 delay_us(2);) a9 H+ }! O; z
  111.     }         # f# R6 l9 G$ z& y1 c4 {9 x1 L$ \
  112. }- L4 M7 n& x0 M' I$ p7 V( [
  113.             
    ' y- C  e( ]" ~2 T
  114. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   * Y! a8 S2 Z- l* L2 C  ?8 L/ w
  115. u8 IIC_Read_Byte(unsigned char ack)
    1 T7 y# Y; j# X+ Q$ x
  116. {# [5 f; h2 i1 Z& p
  117.         unsigned char i,receive=0;0 t8 K- _% d% J- M+ A
  118.         SDA_IN();//SDA设置为输入% U9 C) d! @/ H- k7 l, F9 H
  119.     for(i=0;i<8;i++ )8 y$ b9 Y" b4 B/ C
  120.         {7 \# g% e( o& J  M2 Q' V
  121.         IIC_SCL=0;
    7 ~5 ^% p/ b! g5 E# f2 T
  122.         delay_us(2);) T6 I- e0 c0 e1 B
  123.                 IIC_SCL=1;
    0 b8 f( L9 S; @! o0 ]
  124.         receive<<=1;4 g2 T  m2 L; Q* ^9 z. L
  125.         if(READ_SDA)receive++;   0 o9 G3 u; f5 P/ i: E% S
  126.                 delay_us(1); 9 y0 n' G# R' ]( |, |
  127.     }                                         # F7 _# b  W! C+ I2 V7 M3 ?: d
  128.     if (!ack)
    * A' M9 F0 Y. n: @7 a: `, E. z% f1 a
  129.         IIC_NAck();//发送nACK
    / t5 B) s2 e( u: p  M; ~
  130.     else
    . i' W0 [1 u3 y8 a# x
  131.         IIC_Ack(); //发送ACK   
    3 G8 e' Q9 O$ ?5 K1 t
  132.     return receive;
    , A8 E- c6 x7 Q8 S: H0 h( p
  133. }
复制代码

# ]1 k* P( B( k8 Q
$ ^  }1 V+ I2 U
  1. IIC.h
    " i, v/ v! o3 P# F, I. o. S
  2. ) w+ \( O+ P4 S& s* w  v& u+ b% v
  3. #ifndef __MYIIC_H% G. E! z7 W, h+ j. k* s) ^
  4. #define __MYIIC_H
      k- W! M0 d) W/ a& V. O
  5. #include "sys.h"
    . B' v& ?' ?% l; V: Q+ F
  6. ' i* J) w% L! s: K
  7. //IO方向设置) f- C7 ]% m3 Y% q2 m7 G  c# r0 d
  8. #define SDA_IN()  {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}        //PB9输入模式  c- l4 E$ V/ v; c, u% Q
  9. #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
    " d9 g+ Y/ s$ _! G. L) ?
  10. //IO操作函数         ! T8 Q* R' C8 _6 N  R' I5 \2 G
  11. #define IIC_SCL    PBout(8) //SCL$ h+ x. j! J/ b2 c: U
  12. #define IIC_SDA    PBout(9) //SDA         
    # E& R- |1 L7 L& ~3 G
  13. #define READ_SDA   PBin(9)  //输入SDA 9 H% t- M' @+ U' ~6 \, D

  14. ! h8 M% x& _/ C0 _0 z9 I
  15. //IIC所有操作函数+ A$ s* i& }+ p; k% w# d$ j
  16. void IIC_Init(void);                //初始化IIC的IO口                                 2 q7 ?: ~! \4 v9 V$ q
  17. void IIC_Start(void);                                //发送IIC开始信号
    ; ~$ p) r' ~+ n! i5 H& z  f
  18. void IIC_Stop(void);                                  //发送IIC停止信号
    . k# `4 }/ P- L/ p7 d. L
  19. void IIC_Send_Byte(u8 txd);                        //IIC发送一个字节
      {, l! t% ~1 ]% [6 P: [6 |
  20. u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
    : @; l. a  P+ m* F
  21. u8 IIC_Wait_Ack(void);                                 //IIC等待ACK信号9 g% j, X; T# H0 a. {9 T+ h
  22. void IIC_Ack(void);                                        //IIC发送ACK信号
    $ G* _9 V) n- n* S5 W  U- h$ p
  23. void IIC_NAck(void);                                //IIC不发送ACK信号
    1 a; p3 E" V* ^- D0 s, q9 u

  24. + Y0 Q: h1 K0 X3 M- U
  25. void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
    * A! a) c. H, W9 V; h" W3 o
  26. u8 IIC_Read_One_Byte(u8 daddr,u8 addr);         
    3 z3 d8 H7 }$ G+ a, Q+ f

  27. ( ^# z' q; T, u2 @% a; u) J) D
  28. #endif
复制代码

2 d2 ]# c& s; q+ P6 K+ w; G四、EEPROM(24C02)的使用+ e! o* ~8 D; v4 T3 @* L
总容量是256(2K/8)个字节。接口:IIC; x: i, E; b& t

( ]$ D% G7 Z, }" L( c$ S$ P芯片图:
; u5 R$ k" t. A7 [5 n 20190611223242512.png
1 }7 [8 s) z9 Z1 ?; k; c/ v, ?9 a+ w- u5 E7 a4 H& f
这里的A0=A1=A2=09 d3 d8 ^3 q0 @3 j

- M. [! B9 X1 N9 [. C; z: E JS`5JXR7QVA6E`HPDC4A2[S.png
$ V1 ~0 p, w, y- e! K5 ?5 W- l3 W+ _% T$ V9 o2 T
`Y65BNI$J]2G}XA9(LU07`Q.png - ]! |; }+ K+ ?8 f5 j$ S+ j  j: ]
/ J2 e4 m1 y- q' E" @
24C02读写字节时序- ?/ ?9 [3 s0 B" e1 K- o

5 y( Z8 [& P( m* M写:+ }& _. ^1 P0 P- N4 f

2 S2 I0 {5 p, m# l: Y6 x9 Y5 i 51VD~3~B`7`EF45L0Z3KVVI.png
, W& u) j0 J6 Q4 `% U# J6 h  K9 z
- L  i& j+ }  _/ u  z5 ]读:
/ f* x  Y6 z3 |7 N! V) Z
4 }4 t0 _! Z- W" F 20190611223436818.png
& A: Z+ u4 P6 X: t& R
+ D" _9 ^$ e* m- p* e24C02的代码如下:) B  _6 W! ~$ S/ n& i. O* M; a$ f9 I
  1. 24cxx.c:
    + Q7 G7 e" y- Q& }- K! y
  2. #include "24cxx.h" 4 U8 C$ @% n) B
  3. #include "delay.h"                                  9 G  P* I( C5 v' \- C

  4. " E0 b* e& r: A5 J0 |! a
  5. //初始化IIC接口
    3 _4 V7 R: W, j% c
  6. void AT24CXX_Init(void)
    7 a3 U. M$ w. K1 u% l% S
  7. {" Z& M# f* y  P- H
  8.         IIC_Init();//IIC初始化7 d/ Q$ ~9 e! H# W" c  ?
  9. }
    $ Y7 s3 R- t- s
  10. //在AT24CXX指定地址读出一个数据
    5 B+ f  {2 J! O
  11. //ReadAddr:开始读数的地址  
    ( s- p0 q7 v  z: E* M
  12. //返回值  :读到的数据  _8 T' T% l" f! W' l
  13. u8 AT24CXX_ReadOneByte(u16 ReadAddr)
    . V4 ^; g5 g. z
  14. {                                 
    - `3 K. {# h' T/ D. S4 g
  15.         u8 temp=0;                                                                                                                                                               + P8 a5 R" H  \7 e# u5 D# [
  16.     IIC_Start();  6 P  l* y( R' d2 C9 H! k
  17.         if(EE_TYPE>AT24C16)
    % N) L: C# u8 R1 ~  g
  18.         {7 T9 M, r5 {, \
  19.                 IIC_Send_Byte(0XA0);           //发送写命令
    7 \4 Z5 P" X: c
  20.                 IIC_Wait_Ack();
    + X: Q  q/ l* \0 F
  21.                 IIC_Send_Byte(ReadAddr>>8);//发送高地址            
    . \+ P% O7 \7 L6 u! q  h
  22.         }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据            4 s  i5 g* |4 c7 S9 [& K- t
  23.         IIC_Wait_Ack(); ) K# \; S* g0 Y5 a3 [  F
  24.     IIC_Send_Byte(ReadAddr%256);   //发送低地址; u) ^0 A7 w- ^+ }& Y
  25.         IIC_Wait_Ack();            3 c/ l4 a0 g3 g; J! h' y% S
  26.         IIC_Start();                      7 n$ N2 b; B* O( n
  27.         IIC_Send_Byte(0XA1);           //进入接收模式                           
    6 ^, N" A8 A+ S7 h+ B
  28.         IIC_Wait_Ack();         
    # f% C# t3 X( l0 W
  29.     temp=IIC_Read_Byte(0);                   : p0 l# `6 ?( G0 m8 Z; K5 L3 h
  30.     IIC_Stop();//产生一个停止条件            7 e9 F; C4 {7 P1 N% f- i0 B
  31.         return temp;
    ' N- ], Y+ p0 L! |4 j
  32. }
      W7 j* f2 C* h; n) K% }
  33. //在AT24CXX指定地址写入一个数据
    + a+ [0 T: S8 H# _5 V# O  |
  34. //WriteAddr  :写入数据的目的地址    . o5 N; ]! N. \1 c
  35. //DataToWrite:要写入的数据7 D! ]. s/ E3 O( f
  36. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    9 T7 E% s* m( u8 X$ S! H7 m" `" d
  37. {                                                                                                                                                                                          
    6 J3 x3 K' d# Z. _
  38.     IIC_Start();  + d- c6 N. T/ q9 B
  39.         if(EE_TYPE>AT24C16)/ M1 n- _, j! F' d- B( Q3 h/ K
  40.         {
    ) o$ h# q; Q) K# s1 @" }
  41.                 IIC_Send_Byte(0XA0);            //发送写命令5 _+ [2 L* V* P; H" ^5 f
  42.                 IIC_Wait_Ack();
    & e3 v$ D0 F; v1 z% A: {0 J$ |
  43.                 IIC_Send_Byte(WriteAddr>>8);//发送高地址         
    ! U6 M/ {/ k  H) U
  44.         }else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据         
    5 a+ O9 @! O  T- w3 ^# m7 C. A
  45.         IIC_Wait_Ack();           
    ( p$ p' n. `2 v* X0 _$ ^( M' B
  46.     IIC_Send_Byte(WriteAddr%256);   //发送低地址0 L3 {% r6 b; G+ m9 U/ H, B
  47.         IIC_Wait_Ack();                                                                                                               
    ! Q& H  z6 w0 w; g
  48.         IIC_Send_Byte(DataToWrite);     //发送字节                                                           
    ! l/ f" h: L$ Q8 [2 U
  49.         IIC_Wait_Ack();                                 ( w& _' h! ~1 }
  50.     IIC_Stop();//产生一个停止条件
      d* R  t9 O8 t/ O8 [, Z
  51.         delay_ms(10);         4 M( f- e4 O" j. M! L/ B
  52. }
    - \9 ]3 n) @6 I3 c% ~- C1 R+ I
  53. //在AT24CXX里面的指定地址开始写入长度为Len的数据
    ; t5 Z+ J0 w. N0 D- j
  54. //该函数用于写入16bit或者32bit的数据., ?8 f+ w. E  l/ p; G  W3 N. e
  55. //WriteAddr  :开始写入的地址  
    ; ]& [( Z  |! ?" A! ]
  56. //DataToWrite:数据数组首地址
    ( P) W2 }. |5 f5 f
  57. //Len        :要写入数据的长度2,4
    7 ^  v" \( j- ?4 |
  58. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)/ f; T! F' f) ]' \
  59. {         
    ! J# G  g2 S, w( v  L% f
  60.         u8 t;
    & e2 L2 w: `2 q: K
  61.         for(t=0;t<Len;t++)& q) E7 [$ y8 o4 T1 R9 ]+ s* S
  62.         {
    . a! J* a5 D, E, s6 D0 I( A1 [
  63.                 AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);1 ]9 _- u% o9 S% C" P9 x+ |1 K
  64.         }                                                                                                    + l- Q" Q7 W# R! A
  65. }
    7 t) o3 S; L# |

  66. : l( B0 w$ A( `; Q( H8 J- Z5 g
  67. //在AT24CXX里面的指定地址开始读出长度为Len的数据
    5 p- ~8 e" V0 n2 a- K: _
  68. //该函数用于读出16bit或者32bit的数据.. i7 J! x2 n& F- Z: J% H
  69. //ReadAddr   :开始读出的地址 6 G( Y& b% u5 j: k( G9 L5 \
  70. //返回值     :数据0 t' p4 ~6 ]0 ?2 X. r# b3 ]/ c
  71. //Len        :要读出数据的长度2,4
    : B  ]  V5 T6 [2 a& p8 l
  72. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)1 _! s9 v5 M; @- m2 }# r  C1 e1 i
  73. {          + S' `% |& t/ X. R8 A3 R& Z
  74.         u8 t;- a3 I. r8 v$ p8 U2 g2 t
  75.         u32 temp=0;! K  y) A% [* Y, U9 r/ ?- F. C, E9 ?
  76.         for(t=0;t<Len;t++)* ^' L3 Z' `& W' }. n5 c
  77.         {
    - Z. X, q! Z  w* l1 T
  78.                 temp<<=8;
    ( W; a% i. `$ I# `* O4 S
  79.                 temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);                                             ) \- }- D; P0 W
  80.         }( P  M7 Q7 M) f& A+ A
  81.         return temp;                                                                                                    ) Q3 y5 U" ]$ L  O! F8 T* p
  82. }; R( ~' F  R1 N5 k* r9 q6 {
  83. //检查AT24CXX是否正常8 C& l: a: Z; J9 R; |7 Z
  84. //这里用了24XX的最后一个地址(255)来存储标志字.! O, G" u8 v) F% S" V5 W& u
  85. //如果用其他24C系列,这个地址要修改  ]  [" u+ ]& b; f' W* k
  86. //返回1:检测失败
      D3 A4 S. @: L0 v+ N
  87. //返回0:检测成功
    . ~9 Y1 O' W! ~: @2 C
  88. u8 AT24CXX_Check(void)0 {% }5 d1 ?& F9 ?6 Q& j7 o
  89. {2 ^/ S/ k  s2 D7 g5 F
  90.         u8 temp;- K6 w5 `1 |1 t) m( R- O+ O) ]
  91.         temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX                           
    1 X# g! F4 y8 ]9 W# C% ]) t
  92.         if(temp==0X55)return 0;                   : O6 Q; ?8 T2 ?# n7 H4 z4 ^, J6 k. t' `
  93.         else//排除第一次初始化的情况
    & m3 E* y$ v5 `+ d, q8 g
  94.         {; t' c6 L! ^/ U$ C
  95.                 AT24CXX_WriteOneByte(255,0X55);6 H/ ?; a% \: p' g" C! ?3 V
  96.             temp=AT24CXX_ReadOneByte(255);         
    6 x, r0 F0 o: n; n% v1 b7 Y
  97.                 if(temp==0X55)return 0;
    " _- b* R* O0 p$ [1 u" w; H# E
  98.         }7 w) n$ F/ c/ @/ i
  99.         return 1;                                                                                          
    # e9 z8 f3 g9 W! a" Z. [, _# h
  100. }/ v* K# o* o4 o

  101. 3 Z0 l9 n+ X9 q1 u
  102. //在AT24CXX里面的指定地址开始读出指定个数的数据1 B! P# n- i! y( X0 Q6 t! T( r2 }
  103. //ReadAddr :开始读出的地址 对24c02为0~2554 X. P( w, [% W* ?" q/ U
  104. //pBuffer  :数据数组首地址: w/ [9 |" K( V) ~% L2 `
  105. //NumToRead:要读出数据的个数
    ( [7 D& Z& W; i, c
  106. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)+ r* w- j9 p7 H$ {/ P/ C" y, g
  107. {- T/ {! Q- y( {5 r" S
  108.         while(NumToRead)+ T: Z# U. M6 D' ^
  109.         {% H5 y7 ~! R6 q6 Q
  110.                 *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);        ! Y' h; R; I( W/ W2 G/ c2 U# X7 b# S
  111.                 NumToRead--;# ^( T. L5 O7 @# h. z7 o
  112.         }% Y$ i% K- z' P# W! p* p
  113. }  . t# T4 J% W1 J' a  E" }0 k) f
  114. //在AT24CXX里面的指定地址开始写入指定个数的数据. F! n/ |" k) d7 q
  115. //WriteAddr :开始写入的地址 对24c02为0~2558 i2 C1 V) y8 c
  116. //pBuffer   :数据数组首地址
    1 O2 `: G2 X% K5 }( i: c, B
  117. //NumToWrite:要写入数据的个数
    ; }7 ~  s  `- u3 f7 p
  118. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)! y3 O: \8 O+ i. n! W9 X" X0 A
  119. {
    . M6 v( ^7 F9 n; K3 G% ~$ ^5 l. c
  120.         while(NumToWrite--)6 g& P5 K! `3 P  S5 `: w% A( j
  121.         {
    - p6 s5 Z$ O' N# W" V
  122.                 AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
      Y! m5 }' |) l9 ~. @" X, g0 R
  123.                 WriteAddr++;4 ~$ E# c+ B1 K: d8 Q4 ^, `
  124.                 pBuffer++;
    6 h  s- i# k2 d7 N( g+ A3 Z! [. _, v
  125.         }
    & |  h- Y9 G: u- n4 g) Q6 `) X
  126. }
复制代码
  1. 24cxx.h:9 n" Z* `; e# x5 p
  2. #ifndef __24CXX_H
    : h7 L$ H5 r) {
  3. #define __24CXX_H
    , L6 p& w- j8 {7 U5 c
  4. #include "myiic.h"   
    ' R3 `3 d" Q; z: }
  5.   k$ C9 ?# ~+ z  o
  6. #define AT24C01                127
    * q8 E0 \/ i4 j2 _& J! h3 }
  7. #define AT24C02                255
    * K  Z5 Z: u2 v
  8. #define AT24C04                5116 d& E9 h( E" W  {$ t
  9. #define AT24C08                1023
    ! z. P( E- q, D& w# ]
  10. #define AT24C16                2047' W/ M/ j0 z0 q1 ]) m) q- M
  11. #define AT24C32                4095
    ; Z: c- O+ n, X# [) z
  12. #define AT24C64            81912 K# b8 A" |1 l7 ^3 y
  13. #define AT24C128        163831 M/ _1 v, t( Z9 `
  14. #define AT24C256        32767  ; e% d( ^! _4 j
  15. //Mini STM32开发板使用的是24c02,所以定义EE_TYPE为AT24C02
    6 S' q+ N( P, r! p! ^
  16. #define EE_TYPE AT24C026 w: O3 m- Y0 C6 G
  17.                                           
    , U+ c0 r4 r( [
  18. u8 AT24CXX_ReadOneByte(u16 ReadAddr);                                                        //指定地址读取一个字节
    5 t6 c9 U" i: S7 y- M  t9 c
  19. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);                //指定地址写入一个字节5 B' H9 l+ K: i. ]+ @- B
  20. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据. S$ y4 e* ]) w3 T( c! I: F2 T  d; D
  21. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);                                        //指定地址开始读取指定长度数据) u/ u8 A& g: O9 a
  22. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);        //从指定地址开始写入指定长度的数据
    " ^9 W; q  t8 w- c
  23. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);           //从指定地址开始读出指定长度的数据0 O+ f2 k$ u# t, @5 ^

  24. / u' K7 s2 ?, J6 I& f% g) a6 w
  25. u8 AT24CXX_Check(void);  //检查器件0 N0 W( ^0 V3 ], A$ }- v' g( k5 K
  26. void AT24CXX_Init(void); //初始化IIC
    ! g4 @. A) c$ ]" o' {7 ^
  27. #endif# F5 [% c" D# ~; Y3 G0 _& ~

  28. 0 C( g$ P2 K8 t* C1 D/ [( H
  29. main.c:
    8 F6 h7 h/ W9 a; ^
  30. #include "sys.h"; t7 K  s' I4 K3 O
  31. #include "delay.h"- q5 Q+ l/ c1 B% {" H8 N$ I4 L5 Q
  32. #include "usart.h", h) \, W, v- Z2 r8 f; G1 J7 u
  33. #include "led.h"
    * k6 M1 |0 p7 v6 D
  34. #include "lcd.h"
    # P; C  l1 X& g  h' ^+ R
  35. #include "24cxx.h", c! k; t$ B4 J* S) t3 ]
  36. #include "key.h"  
    # I3 @9 \( s/ l$ {- V+ b. g

  37. / a9 m& P9 Z$ Y% z2 f) x
  38. //要写入到24c02的字符串数组" E, R5 d& i8 P! ~
  39. const u8 TEXT_Buffer[]={"Explorer STM32F4 IIC TEST"};
    , |# M0 i8 W# {* ~  `$ _
  40. #define SIZE sizeof(TEXT_Buffer)         . _. d+ p& l  v
  41.         ( L& U  g+ ?! ?
  42. int main(void)
    0 d' l6 \2 P2 V+ @0 j  {
  43. { 1 ^% _9 s$ s! c
  44.         u8 key;! f  p0 B2 T" [- ~* R
  45.         u16 i=0;2 L4 t1 p) x- x* ^' I# ?7 u/ b
  46.         u8 datatemp[SIZE];        8 N# R& L, x- ?6 ]& K: `3 R
  47.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2/ ?% G5 F7 v2 L% ]3 G3 G7 @. `: k
  48.         delay_init(168);    //初始化延时函数
    - m7 s1 [5 K  X. U8 M* h# q" C- ?
  49.         uart_init(115200);        //初始化串口波特率为115200
    " g. ?: ?& Q( U# Q
  50.         # W9 J* v: E6 A
  51.         LED_Init();                                        //初始化LED
    . V+ N$ d3 U' D$ Z
  52.         KEY_Init();                                 //按键初始化  & T- {, E# B0 J1 Y2 x& @  z
  53.         AT24CXX_Init();                        //IIC初始化 . n6 }9 K: ^; x. G+ u) A$ U4 C
  54.                          : X& Z1 |' ]# k# `! R) \4 T
  55.          while(AT24CXX_Check())//检测不到24c02( Q% k0 ^) D! G" a! z; |
  56.         {
    / p# q# z0 ]% N$ {. F% _
  57.                 printf("24C02 Check Failed!");
    + Y/ d4 e; p/ k7 V
  58.                 delay_ms(500);% h9 h' T' ]2 W# g
  59.                 printf("Please Check!      ");( [" Y& H# G. V5 u
  60.                 delay_ms(500);" Z- B$ _+ o6 A7 i  ?& Z
  61.                 LED0=!LED0;//DS0闪烁
    ) m: I# _6 e9 j  m3 ]3 D9 t
  62.         }0 S& ?! I% n, W0 i( C# u0 B1 A; f
  63.         , }$ x6 v# d2 [3 k6 k4 K
  64.         while(1)
    1 }' R- i4 Q7 i0 d( }; ]
  65.         {( Y0 H! l" _. B4 \
  66.                 key=KEY_Scan(0);6 w5 V* C' O" p/ X% Y
  67.                 if(key==KEY1_PRES)//KEY1按下,写入24C02
    8 P) W6 _" e( C; [. o9 d% T# q$ W  X$ i
  68.                 {! Z. a% @& r6 Y6 s- P
  69.                         printf("Start Write 24C02....");   
    8 o0 }$ J1 h, ~- {
  70.                         AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);; s7 z; W8 d/ ]! O, v  S
  71.                         printf("24C02 Write Finished!");  //提示传送完成
      B. N! |% @/ W, a( Z
  72.                 }* X' W7 S7 \! R+ o) ?9 f+ F
  73.                 if(key==KEY0_PRES)//KEY0按下,读取字符串并显示
    " Y7 R. ^! g, q2 L' h
  74.                 {0 ?- p1 o4 D4 d) m/ V  W
  75.                         printf("Start Read 24C02.... ");
    9 D2 g$ G- m3 L
  76.                         AT24CXX_Read(0,datatemp,SIZE);
    ! u2 D; j5 N  Q  k
  77.                         printf("The Data Readed Is: \r\n ");//提示传送完成+ Q# U' W) i" G4 k6 f
  78.                         printf("%s\r\n ",datatemp);+ c/ M: o7 t# r  s
  79.                 }           
    6 ?% V: G% \( ~: o( n
  80.         }             ; P$ r1 ]* \4 N3 e4 O; i
  81. }/ Y# f0 E- K1 p
复制代码

8 k& M7 d2 _, d' Q0 |4 V  U2 J- g$ V) Z9 X1 K$ N. E8 `+ @. f4 u! v8 I

1 C+ J6 N0 C+ }8 O) m
收藏 评论0 发布时间:2022-5-16 11:39

举报

0个回答

所属标签

相似分享

官网相关资源

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