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

基于STM32F1的CAN通信之EEPROM(AT24C02)

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介
7 ]& I- ~3 f" |& NAT24C01/02/04/08/16...是一个1K/2K/4K/8K/16K位电可擦除PROM,内部含有128/256/512/1024/2048个8位字节,AT24C01有一个8字节页写缓冲器,AT24C02/04/08/16有一个16字节页写缓冲器。电压可允许低至1.8V,待机电流和工作电流分别为1uA和1mA。该器件通过I2C总线接口进行操作,这里就不再对IIC做详细介绍了,具体可见外设系列OLED篇。+ l" w  _( V+ u( g  z
9 K2 e) ], u8 G

' j% ^. }( ~  G7 P: f二、AT24C02引脚

3 u$ y; G# ^5 u# m
3 O+ W- N  ?* b. j
$ c* F; F; r( o, l
微信图片_20231023203334.png

- m2 K. w8 b3 m  h
AT24C02引脚定义

$ C# S$ `$ _: Y5 `9 \6 D4 V
2 R3 V+ M8 D6 N. \* e+ W* C

9 s- H# x8 O9 Z# K8 N4 N三、AT24C02寻址
. x% @* a% H& H, @7 C  R% w/ L+ g' b+ ?
使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。( }( \* Q4 z' k. f! |0 v

+ d, k7 o& p; ^+ }" K6 u' m; i
微信图片_20231023203357.png
' R% z( }* L) x4 x$ P7 l
AT24C02地址信息
$ \7 E5 `# @% d

( x- @  n5 L% @2 Q( O+ o
# H" K7 F6 j( W- \
器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。
4 X: {+ v" Q, d6 c3 _( ]# u) S: W5 K8 S4 [6 C
四、AT24C02读/写操作" ]6 a/ V! O2 e+ h1 y9 p; |; L. c
4.1 AT24C02写操作

& R/ D  @1 ^5 G4 R( P; _! z! O写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下
; T* `7 x" Q9 S/ \) {$ [7 z5 |; P$ F7 j' Y( Y
  i5 u) z. w/ }
微信图片_20231023203352.png

8 {6 Z7 {  s" J( b% V# i
写操作时序图

9 o* k( B0 j; ?! x" o! p1 S* P
0 l; x7 i  F0 V
0 F5 ?2 F; I; f" G# ]- y
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。! z7 n) [7 T5 y8 Z2 h3 T* a% v
# H" y$ R$ Q5 s
接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。
+ B8 ^+ |7 ]' o9 z+ X* Y. ~/ n. c! Z+ D9 P
+ W; E) Z1 ~7 y1 {5 L
4.2 AT24C02读操作

! X& H! c& r: Q0 y# E4 S) SAT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。
% @2 J2 ~! L7 g9 S• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下( a/ f" y/ Y+ P
  b# }9 c3 q% u$ u
; f+ h6 @, w- F% u2 h8 ~/ [: J
微信图片_20231023203350.png
3 h7 W" E+ |4 L/ r
读当前地址时序图

" u6 L0 s; ^; }, G7 B7 x' C. y+ I; k
% T& @2 h7 X# h( _, W' F
) k% g+ O6 Q2 F$ k3 G
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下. s3 k+ Y0 X) N3 p4 C/ J
) h1 q; {8 B) j
% W3 X. n+ `9 _  V3 J; U
微信图片_20231023203347.png

" Q: R% Q! Q6 l$ b, \
随机读时序图

; a" M8 M. o2 ]
1 B' B" n, G# M6 W" ]% O( T! C

! _" H$ O9 \) ~+ G! Q0 L
! w7 e# X* N. d
• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下$ k% Q; R5 z. z; C* j% S- Q

& a/ b/ A# {3 J) A, O
" f8 \  e. L' x3 U9 Z+ [
微信图片_20231023203342.png

0 w& P  c2 K  e" Q$ i" @; m( v' R) K, F* _
顺序读时序图

# t  M7 v/ e' B. R3 f

# ?5 H4 b' _6 R6 U# t0 u3 z, p0 b+ s9 C" J0 P$ s+ ]2 e
五、AT24C02程序5 U3 {; J1 |. _* s8 k
这里给出一个AT24C02的程序,仅供参考* b* @8 U4 F- @& w2 c# T" G
  1. /*******************************************************************************
    # \& Y, @" @  u/ H1 u, K$ ~1 Z
  2. * 函 数 名         : IIC_Init
    . w  o( l4 n3 S1 E& F, b1 E2 L1 E
  3. * 函数功能     : IIC初始化
    1 ~# [$ V+ ^, M: A6 D. {& b* p0 N
  4. * 输    入         : 无9 ~9 R7 V/ r, @3 S
  5. * 输    出         : 无
    4 c' K/ \) Y( C! L# A; m" N% M6 R( w
  6. *******************************************************************************/
    2 q" @; m7 {1 C0 i" a, n
  7. void IIC_Init(void)
    3 k8 ?$ w8 u  K9 W
  8. {
    , D6 E6 m% E0 H
  9.     GPIO_InitTypeDef  GPIO_InitStructure;
    . F3 f7 S/ N$ G6 k  ^# @5 `
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);. `$ `- q! M  S% R, ?
  11.     ( k3 V# s+ H2 V' a( }) y
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;( A6 q0 X, z" `$ c) C
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;( s) z" `  [/ j& g2 [9 t
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    0 o, y4 d+ _" r' H- i  [/ E) S# B  ]& ]
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
    % q5 l( u% g# u( M3 o) N  v
  16.    
    2 M' h. w; u" A$ u, s8 U5 T
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    * f3 t' R, k3 q, g
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    ; X) s: G: [6 @; I2 t: g6 [  q
  19.    
    1 }+ j5 M% r9 b5 B& y
  20.     IIC_SCL=1;7 \  B7 P* b1 h3 F# z
  21.     IIC_SDA=1; 8 [" g  m( Z* d. ]
  22. }
    6 l! ^0 C+ G3 w, N
  23. /*******************************************************************************2 n0 M( Q0 e2 e% n% z
  24. * 函 数 名         : SDA_OUT/ {0 L) @# b' Z" R
  25. * 函数功能     : SDA输出配置   
    8 D4 G* n$ ~, i) ~4 D+ j3 T
  26. * 输    入         : 无! L! I5 a1 o. K1 e- W, S$ B
  27. * 输    出         : 无
    : A, \/ {$ R; I
  28. *******************************************************************************/
    5 c& c: W; ~  m6 U# Y) O
  29. void SDA_OUT(void)
    . t. a7 r; d  W
  30. {5 S5 Z7 d) K( B3 s
  31.     GPIO_InitTypeDef  GPIO_InitStructure;
    9 B9 {+ ~( V4 ]
  32.     9 }5 N8 x% i6 o* E! y
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    6 P9 c' K* @& }% G
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;/ h4 e% _6 E! j
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;* [( u: J/ ?) w) @4 i; ^, {0 T
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    / n" X' l6 h% _( P/ _
  37. }, c& P5 d/ ]+ V0 w* y
  38. + r7 w. C, q: V$ J, u& E' c
  39. /*******************************************************************************; y, S& e" i3 q( }8 n7 t. i7 C# \
  40. * 函 数 名         : SDA_IN
    : ^. M' X5 S7 m+ v  i* j9 N( p7 w
  41. * 函数功能     : SDA输入配置   
    - [. g4 ?& Y- G+ F2 z2 ]
  42. * 输    入         : 无
    $ ^$ `: e* T" G8 ]- @+ w# a* M0 g
  43. * 输    出         : 无
    # e  m' c$ a* p
  44. *******************************************************************************/+ T8 j$ \- ?6 d, \3 H' w  X$ e( w
  45. void SDA_IN(void)8 l; v/ r6 G% v& b
  46. {2 U; _' U* f4 X& R" x+ K
  47.     GPIO_InitTypeDef  GPIO_InitStructure;( ^, R' X: u! D
  48.     # }' f: }7 C2 k' }3 }
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;) a) Y, \- t7 ?  p7 o
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
    " ]: H& ^+ i( {$ t  [2 c0 n
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);% y+ l  `0 K+ j4 I! d
  52. }# U& j! f0 @/ ?: T4 C
  53. ; X9 N8 I1 l- P" a- F
  54. /*******************************************************************************
    ( [6 q# C# `; V& G
  55. * 函 数 名         : IIC_Start6 \  \( l* Y- p3 q1 M$ I0 m0 h
  56. * 函数功能     : 产生IIC起始信号   4 \$ @4 M9 z/ w. f( D) [; F1 Q! z9 r
  57. * 输    入         : 无: |$ V7 m+ \$ O( o! ~) A
  58. * 输    出         : 无3 `/ s( b5 n8 \2 I! l  e3 i; m* B
  59. *******************************************************************************/
    * z9 U- M7 D/ S4 Z$ D& I! Z4 a
  60. void IIC_Start(void)
    9 r, \5 l; e! t& s* a; x* R
  61. {
    , C+ Q! h/ R2 O9 W
  62.     SDA_OUT();     //sda线输出
    - B& B# z3 A' O# H
  63.     IIC_SDA=1;      
    & H% F/ @# w9 u( S" g
  64.     IIC_SCL=1;
    , F( Q+ z& S3 k; ~9 D9 F3 a
  65.     delay_us(5);
    ' ]* u# w, U6 M7 n' u
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low
    ; F% B1 B$ i9 V* b7 \
  67.     delay_us(6);
    " Y' Z, a0 n2 R. _
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 & O5 ?4 q/ A- |6 j1 E
  69. }
    6 w' y2 G; ]8 K
  70. 8 b4 }  y; G4 \( f1 ?: [
  71. /*******************************************************************************! F4 a- P, B* C  h
  72. * 函 数 名         : IIC_Stop
    * q* P" w) a. w0 p
  73. * 函数功能     : 产生IIC停止信号   
    4 c/ m! l  w1 W) f
  74. * 输    入         : 无( Y6 L* U7 R, _
  75. * 输    出         : 无. `" ~+ O8 w; M" `0 ]* e
  76. *******************************************************************************/2 P7 a/ h3 K! L: {' O$ F
  77. void IIC_Stop(void)
    6 J& F7 R, K5 h2 f8 k
  78. {0 w1 q1 C0 j2 _: b7 ]
  79.     SDA_OUT();//sda线输出* H3 a. M4 J% c/ h0 E2 b
  80.     IIC_SCL=0;. E: z% s' ~7 {/ x
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high. M( N0 g1 d. x& y& c
  82.      IIC_SCL=1;
    8 B' J0 B8 B, {( {- K: w3 r
  83.     delay_us(6);
    ) w) ^; ~3 z/ E" ^  P" P4 r; H
  84.     IIC_SDA=1;//发送I2C总线结束信号
    / K5 M5 s8 W1 }! Y2 U
  85.     delay_us(6);           5 p) t) M! T7 s' e+ r. X' z' B* x
  86. }
    * j: c9 x& w3 m4 E) R3 P. C* X

  87. 1 I- n, y" A5 a- l2 C9 p8 c) x
  88. /*******************************************************************************
    * S/ v6 I9 j1 e9 {% h# H
  89. * 函 数 名         : IIC_Wait_Ack8 K, k& M; P- E9 ~1 M% f0 g" ^
  90. * 函数功能     : 等待应答信号到来   % K* z' X+ f% U/ a/ F; Y
  91. * 输    入         : 无3 Z4 z/ ?3 z/ f9 }( I, F, X
  92. * 输    出         : 1,接收应答失败
    7 W2 v  H* D7 [% r
  93.                      0,接收应答成功
    + z, |  m  z& B: c7 {) e
  94. *******************************************************************************/
    8 L5 W! p" R0 S: M* r
  95. u8 IIC_Wait_Ack(void)
    2 ]  m. g9 d) d1 L' L
  96. {
    ! K$ F; [; }0 M  G% g% F
  97.     u8 tempTime=0;4 c3 y/ `% p! U! O
  98.     SDA_IN();      //SDA设置为输入  
    9 r; I6 Z- U0 y: Y4 O  V
  99.     IIC_SDA=1;9 F" s: D$ k7 p% x
  100.     delay_us(1);    , d. g! z4 ]8 L3 ^$ ^" [. \1 i
  101.     IIC_SCL=1;
    0 G7 {7 F4 j$ L! G# W( o8 w4 b4 X
  102.     delay_us(1);  
    + m8 E% U; D; @
  103.     while(READ_SDA)
    7 k( d9 x- _7 v) s0 `7 l3 d( p" U
  104.     {4 g2 |7 K* S/ U4 y
  105.         tempTime++;
    5 [5 R2 z' H0 L4 o- m3 T
  106.         if(tempTime>250)
    5 B$ c5 y0 a2 }. ~
  107.         {
    ' Y- T# E2 c# T  d
  108.             IIC_Stop();
    + o! |- B# b9 }5 n
  109.             return 1;4 z; N2 L/ S0 o. y
  110.         }
    9 E( y; p8 U7 D$ D* f4 ^
  111.     }) t% u, p9 E1 |) V) q
  112.     IIC_SCL=0;//时钟输出0       B# W% w. H$ u
  113.     return 0;  7 n1 b( P- h& U  v+ p
  114. } . ~% n8 ?* a" Z/ q, a: v6 k

  115. ; Q! E- [8 c4 t7 x2 }
  116. /*******************************************************************************
    $ q9 E) K* v+ c. R; _; I
  117. * 函 数 名         : IIC_Ack
    * C4 k- Z( V6 U/ _) V1 q1 m( U
  118. * 函数功能     : 产生ACK应答  
    8 C1 N. [+ U3 W: K$ i
  119. * 输    入         : 无: r8 M8 e* L3 s) T
  120. * 输    出         : 无4 B2 {3 O9 _; ^- v5 S. \0 p
  121. *******************************************************************************/2 ~) q( f; i1 s  e5 ?
  122. void IIC_Ack(void)0 ~0 d- O0 r; |3 h$ s
  123. {
    * H) C5 |; y% B9 L. O- f5 Y
  124.     IIC_SCL=0;7 n+ t% @- n) q7 V1 U# S
  125.     SDA_OUT();% C+ c7 D- B: T0 \( z+ J7 L. q
  126.     IIC_SDA=0;
    5 B( p( s" W' _
  127.     delay_us(2);
    & v  q1 ]9 `# l/ ?: G7 @
  128.     IIC_SCL=1;
    : |" n0 h$ ~% H( Q* u
  129.     delay_us(5);$ R4 d9 T) y. q5 V& R* J. W# f
  130.     IIC_SCL=0;8 m0 O7 ^) T' T; L( r
  131. }
    ( u( B+ E. A& N8 ~0 ]

  132. 9 z- l" R# [* w; p
  133. /*******************************************************************************- v* W% U/ @* w' ?. B
  134. * 函 数 名         : IIC_NAck2 u# v% z, i9 W# U4 |: c
  135. * 函数功能     : 产生NACK非应答  ) N" U5 `9 k0 H# a9 d
  136. * 输    入         : 无
    5 s' y4 R" ]/ R+ E$ h' E
  137. * 输    出         : 无8 z8 q. E; m9 ~4 }; L5 Z# ], w
  138. *******************************************************************************/      
    * {& F* ]0 E' Y1 A" J! e, K  {
  139. void IIC_NAck(void)
    " Y' _. a' |* o( D. k0 X) `' p& `; F  X
  140. {% a+ b" Y6 p% W
  141.     IIC_SCL=0;  y/ {" N  w: p/ E% z
  142.     SDA_OUT();
    ! |/ D" G2 K. n; r
  143.     IIC_SDA=1;
    5 F2 Z: X  Z0 \1 i& y7 t( W
  144.     delay_us(2);$ a7 r8 U2 H7 k1 A
  145.     IIC_SCL=1;
    , N+ E. u4 @$ D1 Q- W* W
  146.     delay_us(5);4 h1 c1 x1 j5 m1 I; d) ?. x
  147.     IIC_SCL=0;* G2 x% n. l' Q* a
  148. }
    + R8 v/ R$ y. u# I4 K; u
  149.   O0 Z6 K2 V9 V
  150. /*******************************************************************************
    . m* n( m8 x# d/ n2 O4 x2 ?' y, K& H
  151. * 函 数 名         : IIC_Send_Byte
    ! g5 C' \, L9 s- ~/ o4 v* a
  152. * 函数功能     : IIC发送一个字节
    - ?" A8 B$ O; c" q! B( D
  153. * 输    入         : txd:发送一个字节
    + I" E1 e7 K2 ^/ P
  154. * 输    出         : 无
      u  z6 c& n- B' Z
  155. *******************************************************************************/    ! s7 j2 i: S  _8 l
  156. void IIC_Send_Byte(u8 txd)& Y. G/ W' Z+ i- K4 T
  157. {                        / e  K7 h6 {2 Z  q- n9 q; G( B3 T6 E
  158.     u8 t;   : X; U5 D! v+ o
  159.     SDA_OUT();      ( L, v! ]# S& H# c3 k8 f
  160.     IIC_SCL=0;//拉低时钟开始数据传输7 ^0 y2 p2 c0 g0 [# x7 @! i: q
  161.     for(t=0;t<8;t++)6 f9 n! e! `3 q, @
  162.     {              
    5 D1 Q- p. {! `2 e
  163.         if((txd&0x80)>0) //0x80  1000 0000
    $ _* K. K+ Y; U+ Y
  164.             IIC_SDA=1;
    * m: }0 w3 g; d/ z) K
  165.         else
    . J" o# ^6 g# _# q0 E. j
  166.             IIC_SDA=0;
    1 P4 V3 d$ i8 [$ p6 W1 w
  167.         txd<<=1;    : F7 P& o& `" F1 U! t; ^
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的1 y! p' |6 I  Q% R
  169.         IIC_SCL=1;3 ^) s: G3 z" g8 C! p% A
  170.         delay_us(2);
    0 m1 }; R" q, b" z6 f$ N5 m: {
  171.         IIC_SCL=0; $ a, g8 |$ A' x$ W
  172.         delay_us(2);5 u" H  S+ s7 I/ ?! W
  173.     }  
    , ]) X' T7 ]3 z) T2 V
  174. } 0 y5 V3 C1 m3 D6 I8 n0 y9 p
  175. % [0 {- |4 ?# \5 }
  176. /*******************************************************************************
    7 V& u/ L8 H2 u. w+ f$ J2 U( X: O* s& C
  177. * 函 数 名         : IIC_Read_Byte6 b* s/ y. x7 r; u
  178. * 函数功能     : IIC读一个字节 % r+ z: _1 F  D' L7 V
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK
    . u7 O* g8 y" N# {* U4 g! r0 S3 r+ b
  180. * 输    出         : 应答或非应答( J  Q  a4 H- L
  181. *******************************************************************************/  
    : b& B. T7 y4 m4 |3 i# P+ _
  182. u8 IIC_Read_Byte(u8 ack)
    # F3 {/ ]$ K" l: {8 B
  183. {
    ! L* K; i) o8 C: ?
  184.     u8 i,receive=0;' i; _+ T4 ^8 l2 X  P
  185.     SDA_IN();//SDA设置为输入1 R+ r, P6 G/ l) {' i" v0 |
  186.     for(i=0;i<8;i++ )  }0 ]% E1 i1 e' C4 J; W
  187.     {$ [/ s# C* E. Z* t# a: [) \
  188.         IIC_SCL=0; # g0 N& {+ M* a5 N
  189.         delay_us(2);5 R5 c2 ^& J& ^
  190.         IIC_SCL=1;7 o$ `* [% `2 g* g6 @
  191.         receive<<=1;# N% P; f0 F/ @6 Q% V7 @! g
  192.         if(READ_SDA)receive++;   
    3 b& l3 b. B; B, K  U
  193.         delay_us(1); / s9 W& X3 x4 s9 n
  194.     }      3 q* g5 @& `# `
  195.     if (!ack)
    ) u+ I0 F# d! [
  196.         IIC_NAck();//发送nACK6 C9 s' I; D9 v/ E" N3 c
  197.     else
    ) B5 c+ B+ J, i, _( i1 G
  198.         IIC_Ack(); //发送ACK   % {; |( r8 j' S0 Q
  199.     return receive;, V5 \6 i2 c' X7 C- v
  200. }; h# @! q- S' T
  201. /*******************************************************************************
    % S5 {# N: m4 O! p8 a2 m6 O
  202. * 函 数 名         : AT24CXX_Init: F& b& X& b1 V$ d
  203. * 函数功能     : AT24CXX初始化
      N% U# p% g7 b* p! L# D2 a, Z% L
  204. * 输    入         : 无
    8 t/ X, R$ L  I! n
  205. * 输    出         : 无) l4 E$ V' M* V; {
  206. *******************************************************************************/
    ' i/ n  o$ L0 i% s7 A+ R
  207. void AT24CXX_Init(void)
    3 V9 T3 S- q4 D6 p8 _: b
  208. {1 ]6 \  _" w( H8 N
  209.     IIC_Init();//IIC初始化* t9 h( p% C  N$ Q
  210. }3 s0 [3 Y4 @1 Q, l( B
  211. ' S$ |4 i% D, U3 U  ~) R1 g
  212. /*******************************************************************************& |" P2 g6 S* N5 s& N# V
  213. * 函 数 名         : AT24CXX_ReadOneByte
    $ {( S9 }. `3 X$ q2 I6 W0 C
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据
    4 q- n% ~( v$ z! y. q
  215. * 输    入         : ReadAddr:开始读数的地址 8 O3 n8 M6 o, ^0 t0 x: j, u% |5 C
  216. * 输    出         : 读到的数据
    ( Q$ L1 i( l, ^  W3 J
  217. *******************************************************************************/$ O# H& h" I) b# g0 `$ \/ q. B
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr)  U0 }# X  \6 y2 r3 C; d
  219. {      
    7 Q. x" v+ n/ B! d
  220.     u8 temp=0;                          % i& t7 G* Y5 p* N1 T4 F
  221.     IIC_Start();  6 S; z8 ~) L0 b& D. I9 }6 `2 K, x
  222.     if(EE_TYPE>AT24C16)2 a) n' J* E6 N8 w+ K" l( K
  223.     {' u7 m) i3 Q: K% \0 G4 M
  224.         IIC_Send_Byte(0XA0);    //发送写命令
    0 ^2 `  k' `1 a1 D8 E
  225.         IIC_Wait_Ack();* e! x4 V4 E+ E6 _9 b
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     
    4 I" ^$ m. s! K% i$ e# n
  227.     }
    / d  e0 ~* H) U1 E
  228.     else ' J6 q1 b& g$ O  Q
  229.     {9 P9 l& A# h$ e( V# \3 G9 D( P
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据0 D9 q$ w' ~. C: h2 F
  231.     }     * K; k6 f! C% H" h! F9 w! o% J
  232.     IIC_Wait_Ack(); $ M( f5 ?$ s4 u$ ]- P" O
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址! @  f5 o! [- ?
  234.     IIC_Wait_Ack();     
    $ |4 ]/ G" j! P4 C
  235.     IIC_Start();        
    3 _+ v+ A( ?; N2 b1 w. }( i
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      - }$ l4 `/ J( r. d7 A6 l
  237.     IIC_Wait_Ack();  ) N) k9 `* T4 Z) o" h7 P8 |
  238.     temp=IIC_Read_Byte(0);     
      \7 l) V3 W" }
  239.     IIC_Stop();//产生一个停止条件     
    7 O0 w# M) p" I7 c
  240.     return temp;
    9 b$ e1 `$ S! e) Z
  241. }3 G& [! o( @2 ?5 {4 f  f
  242. * E  ]: n* j- s; P  J
  243. /*******************************************************************************, _6 K7 Y. ~1 s& A! I! J
  244. * 函 数 名         : AT24CXX_WriteOneByte
    ; b- t1 b; |' {' `# k" o
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据" m8 {2 i9 s8 J1 R* u
  246. * 输    入         : WriteAddr  :写入数据的目的地址
    / v- S7 J4 r  _6 x, T- O+ l3 _
  247.                      DataToWrite:要写入的数据$ I4 F* h  v* y: N
  248. * 输    出         : 无& }  `  D/ c* `
  249. *******************************************************************************/
    4 ]) j) M7 V( d( f5 |
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    ( C# H6 o, E/ b8 j* ?: }; z3 ~
  251. {                                
    + x! |' [! s  C) l, E
  252.     IIC_Start();  
    & R$ w2 C' R6 n. J9 T; T* H' V
  253.     if(EE_TYPE>AT24C16)# w- r* r$ B2 _6 J. A% F
  254.     {
    2 n6 ~; W! e7 f: f7 y5 e
  255.         IIC_Send_Byte(0XA0);     //发送写命令
    ; T3 ]1 J/ v! ]8 m' g1 b
  256.         IIC_Wait_Ack();, ~# [9 ^/ m7 q: i% I: W
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   9 p7 \! V3 c$ \% O6 }& s8 A
  258.     }
    / M2 J1 ~% {& I7 d( g
  259.     else
    ) G! A6 h5 n: Z2 v$ w
  260.     {
    4 c  }" y& ], E+ q; r0 ^
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据$ r' y) L/ {6 k, s- O
  262.     }   ; J8 M6 ], Y0 M: C: Z" R; e) @% h
  263.     IIC_Wait_Ack();    * `& R% q* ?& [% ^! F( _
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址: d: x5 L0 N: _6 [
  265.     IIC_Wait_Ack();                    9 w' V6 @3 p, ^% }# ?( n
  266.     IIC_Send_Byte(DataToWrite);     //发送字节         
    - A5 N; l! K% x0 K8 {- H; B; }
  267.     IIC_Wait_Ack();            * \  f/ {& z. y$ o  N" |: g* R0 ]
  268.     IIC_Stop();//产生一个停止条件
    ' K2 s( f- M6 g& E2 I
  269.     delay_ms(10);  
    ) c0 e) G: F0 N4 L
  270. }
    5 n9 ?7 }4 C2 p) |
  271. 4 g" B1 Y. K' D7 E: T+ }$ f
  272. /*******************************************************************************0 l) l0 [* {, I
  273. * 函 数 名         : AT24CXX_WriteLenByte
    + l6 G# X7 Q4 q- F9 [# P
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据
    6 F1 X! H: D! H+ Z/ x
  275.                      用于写入16bit或者32bit的数据
    ; D* X3 e& W/ l* ^
  276. * 输    入         : WriteAddr  :写入数据的目的地址 & `. k) y, L' ^# o" S
  277.                      DataToWrite:要写入的数据
    1 T# c3 B* z8 @
  278.                      Len        :要写入数据的长度2,4
    : ?. N; J- |% o! f9 }' o
  279. * 输    出         : 无+ D8 j+ v( f0 l4 ?; K
  280. *******************************************************************************/6 k8 k( p/ j6 v! K
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
    * T! S$ ?4 n' R( H. S! }3 |
  282. {   
    ( H! O) G/ [3 H' ?9 R
  283.     u8 t;7 ]4 J) l) g; s
  284.     for(t=0;t<Len;t++)
    9 l2 b& K. }. U7 `
  285.     {9 O; _# D: |/ l6 k' h/ {
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);$ b, O6 K) K( q: t+ o  [
  287.     }               
    , B3 ?6 M: q1 X2 Y' S8 e
  288. }/ i' E. E& ]: U- t# ]8 q
  289. 2 C. V& \" q# }' w( ^+ s2 Z6 I' b
  290. /*******************************************************************************/ ]- l2 z' D7 ?! T$ L- b
  291. * 函 数 名         : AT24CXX_ReadLenByte9 c0 J/ y+ A* o3 b
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据
    / Z8 _/ p2 J# J$ J7 P
  293.                      用于读出16bit或者32bit的数据7 [" R6 k( N1 U; u4 G
  294. * 输    入         : ReadAddr   :开始读出的地址
    : S4 z- W( \1 y0 j4 [3 j" X
  295.                      Len        :要读出数据的长度2,4
    2 K9 M1 H3 Y# J( K8 O
  296. * 输    出         : 读取的数据! @) S2 L* d3 M% Z
  297. *******************************************************************************/) m( }5 V- e" T4 \& B; O( e
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)# X: J& L1 T) F1 y  A2 F
  299. {   # m) G4 g9 V+ U! H/ ?2 J6 y
  300.     u8 t;9 x5 \  U: b8 y  D* {' k
  301.     u32 temp=0;  z7 S/ K* x+ m3 s4 C
  302.     for(t=0;t<Len;t++)* i0 y2 ^# C, x5 Q! d+ b$ z9 D9 o
  303.     {
    . o9 d7 j3 o9 a9 m- L, \
  304.         temp<<=8;- E4 o) B* m6 n3 `
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);          4 Y% Q" N; S0 N
  306.     }4 H) \- ]" B6 g) x5 U8 w
  307.     return temp;                9 {+ a# k7 \1 ]$ o* v
  308. }7 o2 h  c2 y! \) D& L

  309. 5 A6 `( L7 C' v% f
  310. /*******************************************************************************
    6 W0 s( g+ R, f4 x! P1 `
  311. * 函 数 名         : AT24CXX_Check
    1 G; n0 M3 E4 u
  312. * 函数功能     : 检查AT24CXX是否正常$ l+ i8 L9 a$ l- E" c& X8 v
  313. * 输    入         : 无) u: }9 X# U' j, @
  314. * 输    出         : 1:检测失败,0:检测成功
    ; X6 |" U1 T" B% e: ^
  315. *******************************************************************************/8 d* ^) c) W2 D% X8 e
  316. u8 AT24CXX_Check(void); H+ u# m. t4 U. V( y7 E
  317. {: l7 d$ x1 j& l3 |' F$ i+ j! s
  318.     u8 temp;
    9 v; q5 Z# {/ M* @/ q
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      ! Z# t4 p: q& a6 L
  320.     if(temp==0x36)return 0;     
    & g* c1 Y: ]6 t& l/ H; j* W3 m
  321.     else//排除第一次初始化的情况
    1 p4 E7 }4 M1 T, Z: p, |
  322.     {, U7 f# ^$ E8 O$ h
  323.         AT24CXX_WriteOneByte(255,0X36);
    5 N) n4 }1 {* k9 `% q9 f0 D- y
  324.         temp=AT24CXX_ReadOneByte(255);   
    % s! y* c% t9 j7 H: ~) E4 X$ D
  325.         if(temp==0X36)return 0;
    6 u* S0 g' ~' O8 q7 I
  326.     }
    7 {1 |' ?2 \  G
  327.     return 1;            
    " s/ M3 v+ V1 K1 ]1 [2 b5 [
  328. }
    & }/ u3 h! e* x5 |1 n' d2 n
  329. * C. t1 ?5 i( `  }# L
  330. /*******************************************************************************
    6 q# o) C0 l8 `2 D9 i$ {  m
  331. * 函 数 名         : AT24CXX_Read: y- ]  A  e, Q2 L& r' C2 n
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据3 Z6 T, l; N  {8 l4 e$ T* o7 [9 H
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255
    5 l$ [6 x4 i/ B' ?* B
  334.                      pBuffer  :数据数组首地址* l5 n  _! a3 j; w0 O; G
  335.                      NumToRead:要读出数据的个数
    3 ?' W0 r* s2 A, z- v5 _
  336. * 输    出         : 无9 @) Y: t0 C. W) B
  337. *******************************************************************************/  f# _4 y- Y. D1 x" k
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)9 j1 r2 O/ G; O2 j% `% r
  339. {% g" I" A) F& C2 t$ T/ H% l
  340.     while(NumToRead)' @3 L$ i3 X$ v5 n8 x) [. W
  341.     {% ], m% `" ~+ g
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    . b$ g; R. F- O+ x
  343.         NumToRead--;
    % q; f1 g! [) {1 N' r) B. N! _# m
  344.     }- G" |" P" p; V4 U# X4 X
  345. }
      _. J( I7 ~: \, J0 Z& t

  346. ( w" H* I7 A. O2 E5 L$ b$ O
  347. /******************************************************************************** I8 e& o) O* \6 J& \, y8 A4 e
  348. * 函 数 名         : AT24CXX_Write
    5 o2 d2 \1 d& `) _# q6 e5 t
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据
    # ~. t. x' o, {& X  ?7 a' k
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~255$ O) A# z9 s4 W- w- V5 R2 e* R
  351.                      pBuffer  :数据数组首地址
    ' C4 E5 E1 L1 k# q, x
  352.                      NumToRead:要读出数据的个数
    . `# r' G$ d( \& [
  353. * 输    出         : 无
    9 _' p/ z8 |+ g
  354. *******************************************************************************/
    " O7 @* v3 @% |, E( e1 h
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
      W" N$ h2 m0 D/ K2 T# \
  356. {
    : U4 `$ w& `* Y5 s9 z# l& N! J5 a
  357.     while(NumToWrite--)* z) e. r6 p2 s7 V6 [
  358.     {
    4 n* W% S3 [+ x$ p) O
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);/ r. t* z0 y' C% w
  360.         WriteAddr++;/ a# s' f* h/ y: t+ }
  361.         pBuffer++;
    1 d) i. i6 O- Z2 S7 j
  362.     }
    # s) S4 y6 z/ S/ g- n0 F# Y) C
  363. }
    0 F0 o6 x8 {; `$ O% G" J
  364. .h文件如下
    9 a# W9 e7 N, C# K- a5 W6 [

  365. 3 u" \& \- r( V2 B) b; \, ?, Q) ~
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C02
    1 A! q( R, h! T# X3 Z2 n
  367. // 可修改成AT24CXX系列中的任意一个  Q8 I5 l& p5 B& \6 u' w1 M8 j
  368. #define EE_TYPE   AT24C02' f6 s; W5 ~; C, G; I

  369. ' F4 M( z9 q3 J8 `; m( H* U# `
  370. // IIC函数+ G. K. ]/ C9 z! i
  371. void IIC_Init(void);   // 初始化IIC的IO口     
    9 n6 y1 n9 \3 E  \! `$ C7 g
  372. void IIC_Start(void);   // 发送IIC开始信号9 p$ S8 g* J& D+ o0 k# S
  373. void IIC_Stop(void);   // 发送IIC停止信号6 V2 ?: n: o. ]4 U9 Y2 d
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节! G7 m' [* @# R, m
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节. n) l+ ~" `6 g0 t* b/ I
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号
    * p8 e: c( s7 P3 x2 ?# P
  377. void IIC_Ack(void);   // IIC发送ACK信号0 e% k4 o  |7 t) z" z) [
  378. void IIC_NAck(void);   // IIC不发送ACK信号
    ( m. ]: {& `1 F$ k. N9 k8 L! m+ O

  379. 4 n$ z- X/ T3 a$ t9 L
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节
    & ?, A+ ~% f; q) z9 K1 Q
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节/ [& c5 x4 \" d
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据
    ; D. y" _9 g+ E/ o3 _+ v* k# A: c
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据
    # X  T3 A* z; k" J3 L* v
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据8 Y+ x. z/ E: G* |
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据: K9 |* C, E9 d' U
  386. " [5 r7 M$ Y4 V3 e  q4 n
  387. u8 AT24CXX_Check(void);   // 检查器件
    5 Q* t  K1 C) h; S# C( y2 K0 x
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码
- X/ @: e7 W. o& _6 Y
六、应用实例
( B7 D: U6 I# V' G8 w' |. h. t, w给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下
( K2 \' }8 Y. G
  1.     AT24CXX_Init();   // AT24C02初始化
    & X, P# L' ^& G. w/ r
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常
    1 M3 @  ^' [" q  ~. }4 {
  3.     {
    7 e8 R0 y8 I/ D& T( {
  4.         printf("AT24C02检测不正常!\r\n");
      G  F+ K$ ^6 u( M) C+ e4 X
  5.         delay_ms(500);
    $ p" C9 P4 G3 R
  6.     }% ^/ u( `$ \3 [! D+ T, u
  7.     printf("AT24C02检测正常!\r\n");
复制代码

% v0 i$ S( m1 _- Y$ smain函数如下
/ H0 s1 x. G: s! [' }
  1. u8 gWData = 0xaa;   // 准备要写入的数据
    8 w3 j! n+ k% u# F  q5 o: \" A% y
  2. u8 gRData = 0xaa;   // 存储读出的数据9 r6 s6 D  @; x. ^' p* e5 e

  3. % D# d0 ~. C6 |0 P" L
  4. int main(void)' q# r0 e9 ~3 l7 g# w( G
  5. {
    5 D  Z4 d, q, I2 V# f/ k
  6.     Med_Mcu_Iint();   // 系统初始化
      ~+ u0 h' j6 N+ ^$ ]
  7.     : d3 C7 D9 @; ~3 {; O! M
  8.     AT24CXX_WriteOneByte(0,gWData);
    / {9 ], J  P, C" L+ _: }
  9.     printf("写入的数据是:%d\r\n",gWData);6 p* E! I2 M& Q& n+ @5 h. P2 d. a
  10.    
    $ [( Z5 y9 m7 a) u
  11.     gRData = AT24CXX_ReadOneByte(0);
    ' C% F: h; S/ I( p, @8 B% q
  12.     printf("读取的数据是:%d\r\n",gRData);
    4 w' E" ]7 L& v: w
  13.    
    ) ?% h" G) B( c5 r
  14.     while(1)+ r; K( G4 j9 M4 \+ d
  15.   {% Z. f2 q, [5 z9 [4 x# l, m5 i& \) p
  16.     }
    9 E5 r% v9 ^9 Z1 [9 [
  17. }
复制代码
) A- ~  h) ]- t6 [5 L
串口打印结果如下! v9 ^7 ^' J, j3 ?3 P- i5 S/ n& \

9 Q+ i4 L/ W2 S$ O( O8 _$ d# _. H

2 n* B1 F# N- v" d( z
串口打印结果

8 B) n* K- Q" }1 L8 a

6 ?; |  {5 x7 ~( F. l0 [9 ]
5 q' g" J8 F5 j% v1 @
七、拓展应用
3 X8 [, u% l# ]# D% L0 A1 UAT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。9 u' Z" [% U) X

3 ^5 A9 q: Q' M4 I1 ^) D; k
* o! c, B8 H1 W/ R9 j! s" M. f' T0 N

& O* m* i& S, C$ c, `+ ?转载自: 二土电子' {$ k4 n2 p% j, e9 ^; g
如有侵权请联系删除
' N& [4 t# `" O1 _* G& p& C% N6 B6 i9 f8 S
微信图片_20231023203400.png
收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似分享

官网相关资源

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