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

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

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介
1 e% ?) K- c0 m9 c9 F( jAT24C01/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篇。
7 L! r6 N& h2 a/ w4 T/ Q- L' O* [, J

- X+ v1 e; x: m7 V二、AT24C02引脚

. r2 v+ k$ Y  V" G: d
  L1 b% X. {% M5 G+ p0 `0 @3 x# l. D+ }; |5 N
微信图片_20231023203334.png

- V- [  S1 j; P( d  e6 `" E
AT24C02引脚定义

9 J" H: O  O* G* L) a

9 W& M" w  c+ w

1 b9 K) o8 [* P$ ]三、AT24C02寻址
1 E1 P5 x$ T5 k
使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。
& z/ s  _4 w4 f6 }( y* @
( P! ?3 j9 Q- Z+ z% H1 T/ U
微信图片_20231023203357.png

, L. r2 A4 O( g; P# p& G3 ~2 _- x( o
AT24C02地址信息
0 ?5 d! E# u, q: I! [
7 K! [* h0 _3 o% s  K1 b7 z
. e2 T* I5 q! z/ s9 O+ a$ T$ P
器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。
1 n* R! v! f7 H6 ^1 [0 p1 ]2 a- Q: A9 G% h4 m
四、AT24C02读/写操作2 W: [# p$ h6 Q2 a; C  K
4.1 AT24C02写操作
+ v% Y- ^; |' b
写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下
5 l$ i, i( f- \5 x* I: @% t8 ^/ \1 V  o- h: l6 t

  c! F; g! X% J$ {6 ]1 t
微信图片_20231023203352.png

: b/ r+ c4 _5 A/ U
写操作时序图
6 r2 Z; P1 Z& r% B( l5 P5 k. v% N

" P; a6 k/ k8 j5 c  {( N8 [& E! g* {# H
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。( [! r* G: ^& u. y" _1 ~! v: {
7 C+ G1 a1 T  Z9 a! j
接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。$ g" ^! g2 x+ j
. f& G8 p  C' J$ Q# ^) i# F
6 |# N% j' q8 o. I( Q$ E' a
4.2 AT24C02读操作

4 I! Q: \% ^- BAT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。
6 d8 G0 N: p% ^+ F" K5 X) [1 l• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下' T) S+ t. _7 }4 }7 t, o( u0 N- X
8 B7 H: Q' k. ^: J" q0 ?
4 D. v4 q4 R. G- t
微信图片_20231023203350.png
/ r) Q6 ~3 X; r( \+ J
读当前地址时序图
+ F: G" k) F$ m% i$ F2 l
/ ]; K1 K6 o( J/ Y, C4 ?, L
+ T+ t% E+ P0 l0 _6 ~7 u5 f! }  m
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下
  E3 L$ f5 Z: ^1 [! a% ]6 n4 |, @( l+ A8 z# J: u1 r

+ D$ ^7 i6 E% L5 r9 h4 i0 t2 t
微信图片_20231023203347.png

" I9 b* ]- s0 p0 z/ F, R2 K
随机读时序图

) s0 L$ B* B# q# r' a# o( q

, }  Z4 H7 n5 A5 m7 ?# }& a" |

7 Q3 c9 |( `1 x) F/ U" f  @0 n
: L5 c- f1 Y3 v* \
• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下
( P, ^1 ~! W' |
, J% }% q5 r  D1 c/ H

$ v, W+ g8 V9 A* w+ J
微信图片_20231023203342.png

* i- j6 D$ z: B6 V  U
顺序读时序图

( d- {9 C% M5 k8 @

/ ]' R0 F' O* E4 `/ S. g
+ M& k' Y8 b2 Q( R4 U" f/ _4 R
五、AT24C02程序
3 _; m+ D( Y$ m4 b; b, Z& P这里给出一个AT24C02的程序,仅供参考
7 f: l: n" ?/ |/ Y
  1. /*******************************************************************************. [  N4 u5 E& U. e
  2. * 函 数 名         : IIC_Init
    9 Q# H0 @' s' T0 y
  3. * 函数功能     : IIC初始化; g$ Q5 C9 F# k& i2 V8 h* i7 t
  4. * 输    入         : 无
    $ r. S' H! R& S
  5. * 输    出         : 无. A0 a4 U- C5 b* d% `
  6. *******************************************************************************/) ^( \, Y# |- O7 |1 A/ T7 f
  7. void IIC_Init(void)( x3 V" J$ f. Q( `1 w& I# x
  8. {+ O4 O+ B' K! Y- H) C
  9.     GPIO_InitTypeDef  GPIO_InitStructure;
    5 g  V( u' n# ^6 {' D& [8 ~! I+ J
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
    9 v1 o+ j% d8 I; F; y( `$ F
  11.     - k4 X: Z  u9 u6 a: M  Y' ^0 r) r
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;6 X$ s9 J) \" j. U3 y8 o  Y' B1 \
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    ' B2 `1 i8 c$ o7 t$ U) G
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    9 d2 c+ j) ~' {; s4 w
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
    ! d+ ^  N# o& r: w) A
  16.     ( a/ @0 |& T. Q" w) F
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;% ?; S5 @" W4 p: ]
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);' v5 _9 |" u3 u0 u/ m5 Q. X) X
  19.     9 k6 H, d7 T- d" t) m9 A( j4 z# T
  20.     IIC_SCL=1;- K; ^, J2 Z: {
  21.     IIC_SDA=1; 2 G! r, D% o# o, _
  22. }
    ) O0 M5 z8 Z. \7 H" D. ]
  23. /******************************************************************************** A0 K2 I1 C; `! y) F" M
  24. * 函 数 名         : SDA_OUT
    7 N* |3 h- G0 g7 e+ d. S5 ~/ v# q
  25. * 函数功能     : SDA输出配置    4 f/ V+ p2 o% z6 _% |6 ?" h5 |
  26. * 输    入         : 无
    / }' F& {7 P1 p2 |. q- x
  27. * 输    出         : 无
    . }1 g( O6 k! t  ~0 `: E( m7 H( B
  28. *******************************************************************************/& z9 R( e& O% {' h5 W& K, ]0 \9 K- O
  29. void SDA_OUT(void)
    % ^/ X- O5 m  S$ @; E
  30. {
    ; n- o" V: S" u
  31.     GPIO_InitTypeDef  GPIO_InitStructure;
    7 U1 C3 }. P' n7 T' U) o
  32.     6 W6 U' s  \3 [, F# ]8 M* W
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;7 m( N4 Z' y# m' K. z) @
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    9 s# B; p, |& l" }9 A, J0 F1 B+ q7 g! \
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;! m# p& N4 j- d. C
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);0 _; F5 E; V: F5 r$ S; C
  37. }0 i/ H" {6 x* f4 J6 T! ^: u
  38. . d2 s5 O& p9 \6 B, i
  39. /*******************************************************************************: n7 G" Q  X% A" l$ z
  40. * 函 数 名         : SDA_IN. w% D) X( l- A
  41. * 函数功能     : SDA输入配置    # C1 }. l) b7 m. x9 e
  42. * 输    入         : 无0 S- K9 W) l; T5 P& L
  43. * 输    出         : 无
      l3 n0 g3 [! t
  44. *******************************************************************************/
    3 i5 K& Y. H* H2 [* z# X# |
  45. void SDA_IN(void)
    ; N+ u/ Z* X' v
  46. {
    0 M2 ]* C/ o+ o# }
  47.     GPIO_InitTypeDef  GPIO_InitStructure;
    ( t5 s' H# w- S2 `6 d$ o
  48.     $ L  J: ~+ t6 E/ a1 S9 j% a# I
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    4 \3 o& @0 r) Z- o( d6 T8 J
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
    / i9 p3 V: O% G4 k' b9 i
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);9 U# K# [6 Q4 y: m8 y4 d
  52. }
    * R5 k9 W# l% y) p0 [- f6 m; G
  53. 1 j; p. L. _  p1 R6 U' D7 S9 [* L! k
  54. /*******************************************************************************
      O7 x! T) N6 X. Y; V  t4 |4 S! r
  55. * 函 数 名         : IIC_Start
    ( j7 Y) G* u: g- N: ^9 X4 g3 P
  56. * 函数功能     : 产生IIC起始信号   
    2 U2 ]/ d4 D4 l3 I0 V" g$ w
  57. * 输    入         : 无, D  w( [7 j: k% R1 `' j6 t  `
  58. * 输    出         : 无3 n( v, l4 F) H6 f2 a
  59. *******************************************************************************/; V4 H# h) ~+ Q$ V* p% p( ?" ]0 N
  60. void IIC_Start(void)  ~& N# Q6 {3 w3 X; S
  61. {9 o1 d' q7 w0 p  b# w5 [3 s
  62.     SDA_OUT();     //sda线输出% m2 B4 r/ h$ a" R+ t
  63.     IIC_SDA=1;      
    " [; t! D4 T6 s% V! T2 T1 x# F
  64.     IIC_SCL=1;
    * o, C, c' V: p* D% R8 L( J: _0 }
  65.     delay_us(5);& M4 f- Q$ ]5 |4 i
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low ; p1 g8 o! B8 P  C  p! C
  67.     delay_us(6);
    ! V# H9 }, C. _# Y% |
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
    ) _, Y" V' W9 U3 Z0 {& n& q
  69. }
    % f% M8 S) T! {: Q* _' I- b
  70. % x' p" ?  s/ ]; ]" {, u: W
  71. /*******************************************************************************
    ' `/ o7 t( o* }( j5 }
  72. * 函 数 名         : IIC_Stop* {$ u7 D3 W! P; j
  73. * 函数功能     : 产生IIC停止信号   + r6 h/ ~  X) e3 h/ L! Y# O  t
  74. * 输    入         : 无2 Y. S% _' Q, n' e% ?" Q
  75. * 输    出         : 无! f3 M& x8 o! s- S+ g6 s
  76. *******************************************************************************/
    3 {# m/ t8 ^+ Y- f8 G
  77. void IIC_Stop(void)2 }: C) ~" T6 n6 K- @" o7 _6 ^* x
  78. {
      `: q5 C. {7 r- Q5 P8 f
  79.     SDA_OUT();//sda线输出
    - ?( j1 w6 l2 N# p) u0 R. D
  80.     IIC_SCL=0;' M& I2 U6 V# w. F6 h6 s
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high- ?& i+ ?# l; K" J2 f
  82.      IIC_SCL=1; ( t5 p* q% T5 v( t+ A) f
  83.     delay_us(6); : e# [3 X9 X8 j
  84.     IIC_SDA=1;//发送I2C总线结束信号- ^" }( F% J- {3 ?6 Q( t. l
  85.     delay_us(6);           # k0 W  T. z8 L8 e8 x
  86. }
    : u$ p/ o' I( ~. `0 u

  87. 8 }2 T; s. C, z! V
  88. /*******************************************************************************+ [" Q- u$ H3 u& A  X" b2 |5 L% W
  89. * 函 数 名         : IIC_Wait_Ack
    4 p3 j! ^9 _  [& n7 C2 `# p
  90. * 函数功能     : 等待应答信号到来   + ~- J( ?: n) ^
  91. * 输    入         : 无9 e+ U% I( _( S% M( E5 D# b+ G0 j% \! Z
  92. * 输    出         : 1,接收应答失败
      ]0 {/ i$ I. J' _
  93.                      0,接收应答成功8 L" {) X; Q& Q! G0 J5 ^; @" e2 X
  94. *******************************************************************************/5 }# S. y4 D- j: y) S. k
  95. u8 IIC_Wait_Ack(void)
    - d4 o9 V5 {. e+ k+ P
  96. {" n" K& D. B) _) O
  97.     u8 tempTime=0;/ G. q" F; @) B' a) N; c% ?
  98.     SDA_IN();      //SDA设置为输入  $ @6 c( Y6 r( t% d
  99.     IIC_SDA=1;+ d  |  z) t% F( |% g
  100.     delay_us(1);   
    ! N, L( R( B- ^& @- }% A
  101.     IIC_SCL=1;
    5 J5 G+ e! G, J, Q$ b, O: N
  102.     delay_us(1);  
      d4 P, m% ^. p1 U
  103.     while(READ_SDA)
    " s( N: K. K9 B7 D5 c
  104.     {% {* y7 z+ R1 v% m: Z# n0 @, P, u1 W
  105.         tempTime++;
    # T5 L# Q1 B/ T
  106.         if(tempTime>250)6 g, ^6 L2 l% h7 P) e1 M
  107.         {/ K  z3 q1 X4 h6 H0 {% Q- t: n
  108.             IIC_Stop();
    / n' w" D  K/ G$ h' q# A
  109.             return 1;" |- U5 e, }% |- ]
  110.         }
    4 o# @. h  D/ X4 X+ d) A
  111.     }8 A& D5 z3 q* {: x3 a
  112.     IIC_SCL=0;//时钟输出0     7 ~/ s- K5 `/ y0 M# @
  113.     return 0;  # C% V# [# B1 a' D) o
  114. }   u& _9 o6 r2 z, }! n9 \' N
  115. & }& M/ t" \" O) G* s4 A
  116. /*******************************************************************************
    . T# A3 I; u; F8 I) V) ^
  117. * 函 数 名         : IIC_Ack
    : y' o! V& B6 _, f: }) d
  118. * 函数功能     : 产生ACK应答  0 j) B. m" @  b  V
  119. * 输    入         : 无
    + _/ i8 e( {' L! X4 c8 o; T# B& @
  120. * 输    出         : 无1 l" ?6 p" t% K+ U5 v+ p5 h
  121. *******************************************************************************/
    ) Q9 m4 k, V: Y- ^$ a
  122. void IIC_Ack(void)
    + Q3 d' W% V6 k! R1 c
  123. {
    . C7 N" B5 o9 T0 G
  124.     IIC_SCL=0;
    + M9 Z1 v% M" p
  125.     SDA_OUT();
    & b1 o  Y5 \: R( z
  126.     IIC_SDA=0;
    ( b8 N2 B7 r" z- D
  127.     delay_us(2);5 L9 @4 a. H4 e# X, g9 T
  128.     IIC_SCL=1;- T' C7 W. L& V7 n8 k: c
  129.     delay_us(5);
    6 H" s, j. g5 o
  130.     IIC_SCL=0;8 @7 p+ X: k& D1 A. Z  c' C2 D
  131. }
    8 g9 H  {1 C9 d1 c8 \) ?; O

  132. - o! \9 }: h, R6 ]0 Z! L2 l8 r
  133. /*******************************************************************************+ e: s! o; e% S. m/ Y
  134. * 函 数 名         : IIC_NAck
    + Z7 f0 g" k* g$ h5 D
  135. * 函数功能     : 产生NACK非应答  ! `5 b* ]7 V9 H' }8 Q
  136. * 输    入         : 无
    4 v3 a$ ]7 W8 A0 k6 n  i" |! c# s
  137. * 输    出         : 无8 ~) G% \: F& B# l6 U) b  b7 G! q
  138. *******************************************************************************/      
    3 V' F7 t- F% m7 ?/ e* r
  139. void IIC_NAck(void), Z- ]) @/ Q7 t& l+ {- v3 p4 m. N
  140. {  E3 m4 }- i' ^9 z6 O
  141.     IIC_SCL=0;
    2 R8 @+ E# N8 A2 `' R/ `3 j3 n. R
  142.     SDA_OUT();
    9 l7 B- H: s  l5 W- f  r
  143.     IIC_SDA=1;& i; Z/ P7 o/ Y3 w
  144.     delay_us(2);
    $ R  v9 S' o5 ?
  145.     IIC_SCL=1;$ b% l  S1 _. L/ ~% o3 I( s! T
  146.     delay_us(5);
    " H! L+ d% T7 b# f( W
  147.     IIC_SCL=0;
    - w0 Q6 E6 C/ T0 o# ^$ S
  148. }
    1 |: c+ U3 I+ D. _) m7 ^+ Y
  149. 7 c& H, P' I. f' X. y
  150. /*******************************************************************************/ w0 w" C/ {* A  c+ c$ p8 U* K
  151. * 函 数 名         : IIC_Send_Byte
    . l/ A) ~5 V5 S4 h, m$ t
  152. * 函数功能     : IIC发送一个字节 9 n- ~/ o( T. t
  153. * 输    入         : txd:发送一个字节" I  ~% B* q7 m  O( P8 z) S8 A
  154. * 输    出         : 无
    1 o/ x( A' C! @; Q+ [) f' y
  155. *******************************************************************************/    ( j, f# @: T& m4 s6 M$ F0 m2 Q4 u
  156. void IIC_Send_Byte(u8 txd)
    / |# ]0 k+ F: i
  157. {                        
    ! ]$ W8 s  r/ ]5 E8 c6 r1 W
  158.     u8 t;   7 e- t5 e, R; w  |$ C6 S. s
  159.     SDA_OUT();      4 C" u9 Z& p7 ?0 z0 O. R# C" I
  160.     IIC_SCL=0;//拉低时钟开始数据传输- ]2 ]2 k1 @2 H- g
  161.     for(t=0;t<8;t++)
    : Q2 n7 k7 O4 O: m1 v
  162.     {              5 W5 U: C" F5 }2 L( O' O; S1 X
  163.         if((txd&0x80)>0) //0x80  1000 0000, i- M( r# y0 m$ R0 [' \
  164.             IIC_SDA=1;
      h0 J4 F9 l/ W  a' X7 Y
  165.         else
    & |0 s5 i$ g# \% ?+ j  o* T: Y
  166.             IIC_SDA=0;/ Q8 s' _( P: K8 N( Q
  167.         txd<<=1;    " h/ t& B& _3 F2 {' C; s$ y4 L
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的! C# Q0 R. }& t" K& C& c/ H; q3 N
  169.         IIC_SCL=1;5 D$ R* P% C8 W( N% L# u( P
  170.         delay_us(2); 1 ^6 A4 U' z$ R, m
  171.         IIC_SCL=0;
    - @; {, ?1 {* [% U" K* y* G+ A
  172.         delay_us(2);5 c; K0 m$ x, M. G3 j7 S8 }) M
  173.     }  
    6 B4 F+ ~# r; V: l
  174. } , X1 y: O$ [* w2 F5 N

  175. 4 s& l, D  d" P0 {& a; V6 U% q
  176. /*******************************************************************************+ `1 v% ~5 V$ |8 |
  177. * 函 数 名         : IIC_Read_Byte
    # e, b7 h: ~3 o4 u, C
  178. * 函数功能     : IIC读一个字节
    6 x" K4 s1 [# ?' j
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK
    / a' B; G+ K/ Z& ^
  180. * 输    出         : 应答或非应答
    7 |4 w6 }' j! `$ q. \# v
  181. *******************************************************************************/  , I# |6 ^$ Z2 t* }8 a
  182. u8 IIC_Read_Byte(u8 ack)
    ; v- j) A0 b# G9 F2 @
  183. {/ j; \! ~' W  [0 S
  184.     u8 i,receive=0;' h; _! c9 {+ e" S; S
  185.     SDA_IN();//SDA设置为输入
    9 k2 ~  m- B( u1 F6 _# R& i
  186.     for(i=0;i<8;i++ )8 j0 h" M( n5 T. V8 u: [0 j
  187.     {; n1 d1 q9 ?+ q* P. G
  188.         IIC_SCL=0; 1 X6 o2 q3 F6 H
  189.         delay_us(2);( M1 L+ Y3 B2 f/ ~
  190.         IIC_SCL=1;
    % y; q' q# W& M9 i. V/ |0 u$ P& X
  191.         receive<<=1;
    & C6 O# Y" h0 g; K5 H) s) }8 o0 o
  192.         if(READ_SDA)receive++;   / Z" ]  @  `, n2 @
  193.         delay_us(1); 4 p* `! ]+ Z/ R/ }0 \! ^$ B
  194.     }      
    $ s4 e4 D# B& M$ a% |
  195.     if (!ack)
    3 z4 n3 q! n. T" l7 U
  196.         IIC_NAck();//发送nACK
    ) i" T. h' V& u) h* y
  197.     else$ z6 Z: `. D& B2 B8 O3 |
  198.         IIC_Ack(); //发送ACK   ( ^& L% \1 u) L
  199.     return receive;$ Z1 e, N; f# P  Z8 a, D5 y
  200. }
    4 l" ]0 u2 T% Q
  201. /*******************************************************************************: C) Y7 D4 H" L) T, u* P
  202. * 函 数 名         : AT24CXX_Init, v  w8 G$ ?0 E, d" B8 S5 O2 j
  203. * 函数功能     : AT24CXX初始化
    3 Q3 O# B( E8 r/ T7 f; t$ q
  204. * 输    入         : 无
    % l& V. Q" H# c+ b- s6 k# \
  205. * 输    出         : 无* l0 M! f/ s5 n' J
  206. *******************************************************************************/
    / _+ z# {/ q' W$ J( R2 z' q2 ~
  207. void AT24CXX_Init(void)% ~0 d6 z: E" g# C* C
  208. {
    9 _5 |' T5 Z3 P+ X  o
  209.     IIC_Init();//IIC初始化3 ?; ?# t* ?2 R
  210. }. `. c* l. o; V' Q6 N
  211. 5 D8 E5 T4 w! c: Z/ ~& H" m
  212. /*******************************************************************************0 \' C' O8 ?& E% |: b: U
  213. * 函 数 名         : AT24CXX_ReadOneByte
    , v0 D$ q% m1 \# L8 Z8 G  ]* F
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据
    1 M" Z1 u' N. ^# B
  215. * 输    入         : ReadAddr:开始读数的地址
    2 E0 ?. l# e. W
  216. * 输    出         : 读到的数据4 x! R; Y* E" L
  217. *******************************************************************************/6 }& @; O- J. G  I) `( X- a
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr)
    2 T+ V8 w. N. A' X) R& |8 @
  219. {      
    7 g7 E' z. J# E2 k0 j  a6 v3 `' \
  220.     u8 temp=0;                          8 C8 v8 @' T) W
  221.     IIC_Start();  0 J( b) F$ R- F4 P2 O! l( p7 n
  222.     if(EE_TYPE>AT24C16)/ ^1 p3 X1 T" N" ^# C
  223.     {! c* T. o0 L  Q* ^3 T
  224.         IIC_Send_Byte(0XA0);    //发送写命令
    $ J$ {' S' b! i' T4 m9 K2 h
  225.         IIC_Wait_Ack();1 B. r* L" y/ g' s* ^& _& Q# j0 K
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     
    - J+ Y+ H& X# x5 U$ E2 t
  227.     }
    ) x+ y; m9 L- U! Q9 i! f6 I
  228.     else & u$ ]3 Y; B7 J' p5 S2 r3 Y0 l
  229.     {3 A' j9 m$ R- ^" j/ D5 `  ?
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据6 q# f, b5 e6 s0 I& R
  231.     }     
    5 u. Z, S! G- T. f1 C3 R7 c0 l4 q
  232.     IIC_Wait_Ack();
    6 r) {' b8 V: E& d8 l& k
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址
    ' l) l" ~$ Z- D, Z4 @3 c! x( c* s
  234.     IIC_Wait_Ack();     # d+ S! B3 h% K0 Y# _% e9 z
  235.     IIC_Start();        ' V+ S5 C7 L4 ~7 ]
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      ! a  R/ i7 @3 l7 H2 X
  237.     IIC_Wait_Ack();  ( m4 X  r7 ?$ v, d
  238.     temp=IIC_Read_Byte(0);     ; O) |5 p. G0 f* @+ T
  239.     IIC_Stop();//产生一个停止条件     ! C. f, j. R; R( \% Y) I
  240.     return temp;' @9 a9 }& M- m; Z0 ]- N  Q' Y( R
  241. }/ E* @3 E1 A0 c" y; P

  242. - \  z9 l8 o1 d
  243. /*******************************************************************************
    ' J- P! b5 d# J5 ~
  244. * 函 数 名         : AT24CXX_WriteOneByte
    ) x/ O9 `# `! l6 ]0 x+ g
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据9 ^) O8 W% \, D* w. e, Y  r% L
  246. * 输    入         : WriteAddr  :写入数据的目的地址
    9 \8 Y, l( Y' p7 ?- o, d! A
  247.                      DataToWrite:要写入的数据) G2 K# `: C5 t4 |% I% N. T
  248. * 输    出         : 无
      w& ?. X" g; m: b/ C
  249. *******************************************************************************/+ J' s) ~& f& q# P' |0 n
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    8 M$ P; O! N8 H& K$ E3 {" ]& X
  251. {                                # [" n0 u3 l6 p! l! y' |* a  N5 M0 K
  252.     IIC_Start();  
    9 J  k. e2 s/ ?$ a( Q
  253.     if(EE_TYPE>AT24C16)
    / t8 [$ X* A, O# |( @' K, Q, T
  254.     {
    ) h, I; j& u' t5 Q8 b
  255.         IIC_Send_Byte(0XA0);     //发送写命令
    9 P1 U* q: C( T0 P3 `2 \
  256.         IIC_Wait_Ack();
    ' a/ M. y# U1 C7 B! Y
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   / z! z& M% v( e* B/ ^: _: W! M
  258.     }
    ; I0 t; L  f1 I! x( n: C
  259.     else
    & r( O7 J# m7 V7 U( u/ y
  260.     {
    6 N2 ~, M. d: e! K
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
    * Z$ c1 E8 Y! k9 h8 `, e
  262.     }   2 \; O8 W0 ]: o0 ^& h
  263.     IIC_Wait_Ack();    $ J2 w2 N% R( ^2 A
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址
    9 E0 W5 Z' G" _% z* N
  265.     IIC_Wait_Ack();                    * E0 d1 i( C! i) G
  266.     IIC_Send_Byte(DataToWrite);     //发送字节         
    8 G8 N& {, v& w. ?# a6 [
  267.     IIC_Wait_Ack();            
      T! b* c5 G- V
  268.     IIC_Stop();//产生一个停止条件
    : I  B3 i/ U) a! _( R* l6 S# p$ M, ]+ w5 E
  269.     delay_ms(10);  
    ; d. ]$ E+ x8 d+ }. T5 {
  270. }6 D4 j2 T8 b! D; l1 d4 `# U2 z8 f
  271. 1 f2 T) j( q' n, ^1 Y0 i
  272. /*******************************************************************************
    $ r7 m, [. M5 j. N3 f% w
  273. * 函 数 名         : AT24CXX_WriteLenByte
    5 J. w+ v  {2 A0 }  x+ y" ?: y
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据
    ) R" `6 l' O  J. b0 m8 H; J
  275.                      用于写入16bit或者32bit的数据
      V/ R1 l, K+ H7 a& S
  276. * 输    入         : WriteAddr  :写入数据的目的地址 0 d6 \! F9 x7 v
  277.                      DataToWrite:要写入的数据
    # e1 J0 a4 Y. ^* _2 |) o
  278.                      Len        :要写入数据的长度2,45 M7 i/ D7 I7 G: B5 @2 i; ?3 j
  279. * 输    出         : 无; Q8 p' k: {4 D' ?2 @* a; ]
  280. *******************************************************************************/
    % M2 W# {( Y9 H/ p* f
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
    5 p' d- Y- p7 l% R& ^+ A$ l% c
  282. {   
    1 ~% ?+ k6 E4 Q% E+ a/ F
  283.     u8 t;
    ( R5 G* Z5 G# d7 j1 w/ v2 H' L
  284.     for(t=0;t<Len;t++)
    % N/ A, H4 E! @+ X
  285.     {* b! S* k: [, o0 h. {4 u" }- N
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);3 H0 R, [0 f' ^
  287.     }                : S( M" u2 n. Q/ o
  288. }! M/ C0 }+ ^- Z) d( r5 N$ N9 \
  289. # {/ K( q! F0 w" M2 ]" P
  290. /*******************************************************************************
    % s6 r, w  S) a( B2 z
  291. * 函 数 名         : AT24CXX_ReadLenByte* K( O7 Y2 ^+ ?1 M' J( s! ^
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据+ U# l: o* M" p9 j. [& k
  293.                      用于读出16bit或者32bit的数据0 ]9 O; K6 i7 z4 u/ ?: L) f
  294. * 输    入         : ReadAddr   :开始读出的地址   g3 z0 a, o8 n( Y
  295.                      Len        :要读出数据的长度2,4* W* j$ Z* [, n" D3 Z0 ^4 m- S
  296. * 输    出         : 读取的数据
    ' B! g1 D" {. x
  297. *******************************************************************************/) d. |9 y: T) U2 w
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
    % b: d" r3 ]# D' q* Z4 Z7 O* I- ^0 A
  299. {   
    9 {* P0 g3 Z- x+ j/ Y- i
  300.     u8 t;
      Z" j' R: T+ L
  301.     u32 temp=0;
    ) H3 u2 U0 F0 G9 j2 W
  302.     for(t=0;t<Len;t++)
    2 G3 t/ e# k* h& Q! s/ B3 N" G8 M
  303.     {
    % R6 T$ Q8 ^/ ?( j* X) ]
  304.         temp<<=8;
    2 X. Q+ q3 A. l  j
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);         
    1 q+ o& a4 N: w% U2 g6 o4 ~
  306.     }
    0 f$ B$ r; ?  ~# \
  307.     return temp;                4 L4 J( F, S  M% a6 R
  308. }" n: E: d0 s+ l( ?

  309. " O( l6 v' y7 h7 N& F# Y
  310. /*******************************************************************************
    + ~2 U0 F2 ~* P# V7 l6 |8 K
  311. * 函 数 名         : AT24CXX_Check) L5 ~: B1 p8 W3 |4 T6 r% H* k
  312. * 函数功能     : 检查AT24CXX是否正常+ @' h& y+ L! F9 O2 Z( d( U6 _
  313. * 输    入         : 无
    ) z* D  D$ w) x/ {! Z; Q
  314. * 输    出         : 1:检测失败,0:检测成功
    4 }, }+ d2 D" o: u# s) ]! @& b
  315. *******************************************************************************/  |" `; Q$ R: i6 ?8 N1 E; f
  316. u8 AT24CXX_Check(void)4 b& U3 v9 P5 y1 `
  317. {7 z' c' m4 N/ c, q6 o* }# k
  318.     u8 temp;4 ~( {  O6 \% K0 d+ A0 e
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      * Q0 ?& j/ v* b5 i
  320.     if(temp==0x36)return 0;     
    6 u% M$ c0 K7 u' P6 S
  321.     else//排除第一次初始化的情况  `% {4 E- ~) l7 U, y
  322.     {
    5 T/ ^: o1 m+ L" V
  323.         AT24CXX_WriteOneByte(255,0X36);+ R1 W* Y+ e* K( s6 I1 j
  324.         temp=AT24CXX_ReadOneByte(255);   - Z% ~. ?8 q5 i7 k- ]( A
  325.         if(temp==0X36)return 0;( v) h8 d5 o' L" l1 i9 V% }
  326.     }; s; g' t6 b3 l9 ~( S
  327.     return 1;            
    , u9 C, [$ v  e
  328. }5 q5 F5 S: a( m' w! N0 J
  329. - B, e/ f' ?, y+ A: v% i
  330. /*******************************************************************************8 q# W% y2 g, a  W4 Y
  331. * 函 数 名         : AT24CXX_Read
    " l& ^1 o( \" `
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据$ }' E' {5 d- v' W; P# `. N
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255- z; Y. J" e8 r
  334.                      pBuffer  :数据数组首地址
    ) G5 J2 L& U" q+ U6 |
  335.                      NumToRead:要读出数据的个数% k" f6 [5 ~! A6 b
  336. * 输    出         : 无7 l8 }( x, f, C9 k$ U+ ]4 u# n# i1 b. @
  337. *******************************************************************************/: v% W1 l0 f- p
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
    ) c( P0 t+ w) d( ~
  339. {+ Q, \9 D& E0 @. g& c8 M; p0 H* L# o
  340.     while(NumToRead)
    0 A( F& c# E- W4 P. R! k2 r
  341.     {
    , v! F5 F  B2 ~3 m1 k/ p
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    # {* h  X, ~3 L9 a+ e: b1 K. a
  343.         NumToRead--;
    7 W3 z* w# P/ [* ~( W: E+ U7 F6 ?
  344.     }0 G2 p/ z+ l; F' U- ~2 |' r0 ~7 B
  345. } ! ~' Z% S" ^! C, l6 m
  346. 7 u* c8 y* g$ n% F4 U4 C7 k
  347. /*******************************************************************************$ K% c$ {% x: E$ u$ y
  348. * 函 数 名         : AT24CXX_Write8 j6 U, h1 s# E1 F) T
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据
    & J; M2 N& O+ A7 y0 Q# F
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~255% \: e( f- y9 t, f4 n  y  x
  351.                      pBuffer  :数据数组首地址5 T# Y- p9 g5 `0 Y* }  f3 i
  352.                      NumToRead:要读出数据的个数
    $ L# X3 ?  X1 U2 [! E9 o
  353. * 输    出         : 无
    - ~5 S, g2 p+ k+ z7 o7 z* @  I
  354. *******************************************************************************/: o3 \, M4 Y2 b5 @! L$ N$ j9 k
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)7 P3 p6 t1 ~5 d5 }( p
  356. {2 E: B9 ^# C0 S6 [& O
  357.     while(NumToWrite--)
    2 Q4 g# d5 S* M: s/ F9 ^; j
  358.     {& i1 w+ Q! F0 j
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    & M, H- P- M% W, @  |% L
  360.         WriteAddr++;
    4 k  `0 @4 C3 K5 d+ C
  361.         pBuffer++;1 g) q) M7 a( S, X) _6 V4 R* F7 B' _
  362.     }
    , d6 g) h3 ^! c1 l( _3 V* w
  363. }
    5 E- L$ J8 R1 o
  364. .h文件如下
    - i: `4 m1 l6 s/ R: j& x  Q
  365. ; I/ R$ ?4 u* b( w3 [
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C02+ g) D5 T4 G1 t! \+ ^
  367. // 可修改成AT24CXX系列中的任意一个& |% \/ Y6 n8 R$ U3 Q
  368. #define EE_TYPE   AT24C026 H: K/ c5 G7 O- d: {

  369. 4 L" p* f6 z( d8 F8 h1 Y
  370. // IIC函数2 i# \' ]/ n2 R% w% x( V% ?) e3 z- a
  371. void IIC_Init(void);   // 初始化IIC的IO口     4 W9 @2 z1 p, }( ?* s" z0 S
  372. void IIC_Start(void);   // 发送IIC开始信号
    7 r; u0 l$ ^6 R  E
  373. void IIC_Stop(void);   // 发送IIC停止信号
    3 E! U9 N5 v$ z" @' J: X- H
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节( [8 C. D7 j8 j% Y8 G( M1 I
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节
    7 b0 p9 W1 F, j! u! F
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号
    ; ^5 u/ \6 f4 _5 R% i
  377. void IIC_Ack(void);   // IIC发送ACK信号
      C7 m9 v! P! D! P& m0 Y4 K9 s4 G
  378. void IIC_NAck(void);   // IIC不发送ACK信号! N: x7 M  J4 N8 j  n
  379. + [+ m7 T" o+ u; S$ R7 d6 W
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节& F$ ^7 j! K+ \8 ^* }: D# V$ f
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节
    - L# |$ p2 n# G
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据; l4 S8 }" Z2 p
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据# ]' @8 x  L+ m% F* v
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据$ t+ N6 ^  M  y
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据( J( e0 S; u& D  T
  386. / r. t$ K3 i$ O) W. n, T7 E
  387. u8 AT24CXX_Check(void);   // 检查器件
    1 G0 A$ Y5 ]" [4 k  Y5 z" T
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码

+ T6 E- E9 f5 U# M4 u# p+ ~六、应用实例$ a2 }- @0 X  P+ P$ R
给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下
( K) z% R" P. z2 a
  1.     AT24CXX_Init();   // AT24C02初始化
    % \) {: V9 x' p
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常/ T9 K7 Q: h3 F, p, A( }$ Z, \
  3.     {
    ( L; h* H; @4 z5 A6 a7 I' x' w
  4.         printf("AT24C02检测不正常!\r\n");
    % }6 {- a' n  z: e0 V1 R
  5.         delay_ms(500);
    - @' L9 \" }% _5 A3 A
  6.     }
    5 s, l8 N9 h+ ]9 ]  u
  7.     printf("AT24C02检测正常!\r\n");
复制代码

, |$ x# t1 _( P9 L. O; smain函数如下( @8 O4 k$ \! P) M5 O9 F; F
  1. u8 gWData = 0xaa;   // 准备要写入的数据! K: p- I. j/ B( y6 k
  2. u8 gRData = 0xaa;   // 存储读出的数据" }: y9 ?9 {7 M; `) q4 c
  3. $ {# d% D; `; h0 w2 L* N# t- D
  4. int main(void)" C7 t  \# H. C8 U( P
  5. {
    * Y% {/ i5 d* X! h2 s/ \' B7 d7 e9 e, b% E
  6.     Med_Mcu_Iint();   // 系统初始化6 J0 i$ F, @# i  e" @4 `
  7.     4 S+ _, C" P/ k% J  a% a# f8 A2 u0 y
  8.     AT24CXX_WriteOneByte(0,gWData);$ k) @% c# f9 w+ ]5 _4 h0 m5 E
  9.     printf("写入的数据是:%d\r\n",gWData);5 z) w1 V0 z! ~- n' _' W" }
  10.    
    0 M) a. h8 M8 [$ }5 ]6 u7 |! {
  11.     gRData = AT24CXX_ReadOneByte(0);8 g* f" P! p+ Z2 I9 T
  12.     printf("读取的数据是:%d\r\n",gRData);
    7 q* y& e2 t; {/ S  m# z% X  Y
  13.     ; p, g- m  z, W+ W4 a
  14.     while(1)
    4 {3 ~- w+ J+ r, A1 H& t
  15.   {& _9 `* H& t: q
  16.     }7 Y8 Z) B' @; g$ a4 [
  17. }
复制代码

/ D" }; L+ b8 T0 m3 a串口打印结果如下& J- x3 [8 h6 B+ J, k4 _
+ D# U0 W: P' Z) h

2 v& D" d# D/ N. z; ?# _4 V
串口打印结果
+ f5 l  y+ S, P# A! o4 c

* r7 @' ]; F- C- O! H" k+ r9 ^0 w. w$ I8 ]
七、拓展应用
1 y) t: s% h2 k& B5 X$ RAT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。' j* F! F) L! e/ h; q! \

/ E! {7 R9 s1 B+ W( x1 \4 r1 w  q! u6 B8 W: T0 t- [5 v3 f! q

/ x' W; D; B' K1 |# x转载自: 二土电子) e2 ?) C; |: D7 O5 w
如有侵权请联系删除
2 a. |# f4 Z6 ]) m+ a
( Y5 `3 H; O5 D5 S8 F9 S# O- C
微信图片_20231023203400.png
赞 收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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