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

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

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介
  H  J2 T( E6 Q+ d7 f6 i2 `AT24C01/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篇。: g2 E) ?. q  d' q( V0 g* ?
5 r, P% P4 h" X% u

& U9 U& h; L. d二、AT24C02引脚

) f: m& ]" ]8 V" j- c) p9 F# K2 Z6 ?0 m" V9 c
, d8 Y  o: t( r6 M# m4 i7 C, t, a
微信图片_20231023203334.png

/ o: [1 |( h3 s% s- z
AT24C02引脚定义

9 S6 B& u5 \+ c* j# q2 q
3 z. j, ~9 c/ C5 M5 ~. K* l/ ?, r! i

' c  @# w# a. D! l三、AT24C02寻址

) A, t+ ^2 I: ~! w( ?& ?% t使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。
, h$ U' v) p; z! f; ?7 I: G) ?& T4 K" Q' k0 {
微信图片_20231023203357.png

, |; G5 S* H; q) U- ]: I
AT24C02地址信息
+ H% p& d2 Q5 I( g

! |9 ~& |2 A4 b; x  }) X
/ ]5 O5 J6 D( @0 z! ~, N9 o: @% Q8 s
器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。, w& @; d/ F8 M7 x
; |- ^# a- I" [% e9 F" n) G
四、AT24C02读/写操作
- s$ |9 v* t6 a! B5 s# R4.1 AT24C02写操作

7 O0 a* v/ e% \* H5 Z写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下
, O% W# ~: F2 Y. f4 j# e
1 |3 \4 z1 w2 H9 Y$ p) ~* U

$ d8 K6 m& W' j* a, A; @8 F$ p
微信图片_20231023203352.png
% ~( j- W# l2 O
写操作时序图
8 k$ s& n: J' v2 t1 I( c$ d! G2 V

( i! e% Q0 @) L$ y: s- {+ n
* V. F. i0 i! s: y
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。& v! Q" ~( q2 D9 @) W% e' D
& Z% D: [4 e) s- M
接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。
7 J/ H) m. _$ y$ w# z0 x- u5 y9 @* g' Z8 }& J3 J! l
, g5 G% N+ v7 y3 [
4.2 AT24C02读操作

# T; J: F! y5 H2 T1 M& `8 ~1 p  C" IAT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。7 ^. Z  t( C/ N: p4 h8 ]) T* c7 ^
• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下) F5 l0 A, N/ f& ?

) V2 S! E  c$ O( q5 [0 K

/ @$ J4 D/ t1 K
微信图片_20231023203350.png

# M, m% L; E! w1 m1 q
读当前地址时序图
) R$ W+ l7 `, v/ B6 d* ?  w9 O

; ]) R6 K, G& d8 _6 u0 n+ R# f, ]1 E" n9 x0 O
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下
6 _  T$ E! Z/ }; `9 }; L' q; R* u& `* O1 l) {4 K7 [
, z9 ^3 g4 t% ~! L2 P/ I' |2 {9 y
微信图片_20231023203347.png
, h7 i( {/ N  ^
随机读时序图

% ?( ]4 O4 Q, ^9 Z3 v9 }6 v: `( N* Y

* l( L) ]! `3 {& k) m  h! {
  V5 c4 k& F7 D7 t- F
" p. t' O0 D& T0 u" ?
• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下+ A) h; t5 m( x* F- @2 C* n# J. s7 }
  _9 M3 m) h1 x9 h- q

+ S8 g4 i3 K9 n8 y" f' w- r
微信图片_20231023203342.png

6 v+ V! F. Z1 u
顺序读时序图

$ I4 q$ f) n- C7 T, T

5 J3 i2 i" P# E0 L* G% i  G5 S) F0 g
五、AT24C02程序  F) O7 }/ I# x9 A/ k$ r
这里给出一个AT24C02的程序,仅供参考8 W* ?! k8 v; p5 r4 j' _! c. ]
  1. /*******************************************************************************. c/ ?0 y9 X( ^! j
  2. * 函 数 名         : IIC_Init
    8 U  W* F! Z  j' [* y; y7 b
  3. * 函数功能     : IIC初始化$ x& ]" ^0 a+ G) g( G/ W
  4. * 输    入         : 无
    2 ]* Y1 M1 [7 d. E% }1 Q" M/ t* {
  5. * 输    出         : 无4 ?6 V; w( W' f; j4 F
  6. *******************************************************************************/" t3 H+ P# x+ Y" u' \( q
  7. void IIC_Init(void), Y: G) }0 ?& T: \. J1 j% @
  8. {% S* ^( n1 [: m( Z6 X5 ?2 ?
  9.     GPIO_InitTypeDef  GPIO_InitStructure;) n" x/ n. E! h8 R* A
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
    ' }+ {' ]+ f; r4 O5 j
  11.     % v) [: s  [9 m; W
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;
    ) Z8 Y1 l& |6 W, z% Z) @! E* F3 T
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    ; L9 x! w  F/ p7 D5 i$ ~5 k
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;( Y2 c) r1 U& V& e- c
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);2 h: h+ T$ m% g2 A& m- L
  16.    
    4 v. I1 X" l3 W" e. L. z
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;2 H: `& h1 G, o3 Z" o
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    ! U& j( ?' h0 V6 I" W& n# e  |
  19.     " o8 @1 E7 l& s! d3 {3 @' V
  20.     IIC_SCL=1;
    4 o9 f7 E9 Z0 |+ o; [7 M. R! G& _
  21.     IIC_SDA=1;
    ' i, t: ~3 h$ _6 R) D% B- [; r1 f
  22. }6 @: s7 G- Q4 D% x9 F/ }
  23. /*******************************************************************************  y" P: j3 r' ?/ M5 s9 F$ _- ^
  24. * 函 数 名         : SDA_OUT
    ) `/ v  U9 k( y0 n3 F' {  O
  25. * 函数功能     : SDA输出配置   
    * D( J, P1 A$ F8 j
  26. * 输    入         : 无
    2 g  v& l# j" \3 ]/ Y2 I
  27. * 输    出         : 无/ D- u3 L, Q7 F( H: ]& l
  28. *******************************************************************************/+ |1 x2 l6 w9 h- }1 U
  29. void SDA_OUT(void)
    4 e+ t7 v6 x3 m+ b, Z6 d" D# b; K
  30. {$ r4 V' B$ t) a: R! j0 l# u
  31.     GPIO_InitTypeDef  GPIO_InitStructure;
    + D" f( M7 f. p# {2 J
  32.     7 r2 F2 t$ @- W: w, T
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    " ?/ u) p5 z( [! s
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;0 t. w2 l1 W! n3 J9 {- v
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;0 ^( ~' A" M+ ?: S: C0 p5 g$ Q
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    7 f8 ?; \9 w, T: z. {5 C6 q5 o" f
  37. }
    : F+ ?# ?5 g3 F. E% h6 a" Q
  38. - j$ P+ Q7 U' d3 d2 P
  39. /*******************************************************************************
    6 f3 h0 ~* ~2 w% o  b1 b
  40. * 函 数 名         : SDA_IN& a5 v4 r+ [% Y' r0 H5 P9 k  l% `
  41. * 函数功能     : SDA输入配置   
    ' Y" @5 r2 F0 X- h$ [
  42. * 输    入         : 无  P+ _8 n  \5 j  n! K
  43. * 输    出         : 无( v! ^- I' I, R3 O
  44. *******************************************************************************/1 `6 H$ _* o9 z2 N9 G
  45. void SDA_IN(void)! Q+ O$ z- w% w
  46. {( m( O$ z5 h2 m1 a
  47.     GPIO_InitTypeDef  GPIO_InitStructure;
    ; Q' U; W  t& y( ]+ U; q2 _, W
  48.    
    6 k6 T# O; W: u( Y0 E: b) w
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;  I4 |+ P3 P" T" D* e
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
    ( N1 s$ ^( f/ u" R1 s% s
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);' A4 S2 s7 c6 q
  52. }' r/ X& Q8 z7 r* ^4 y: D
  53. $ n+ H+ W5 ~: W# B
  54. /*******************************************************************************, W# X. S9 ~+ \7 y: ?
  55. * 函 数 名         : IIC_Start2 H' e& O9 m" d$ [
  56. * 函数功能     : 产生IIC起始信号   
    9 F7 {9 z6 L/ R( a1 ?7 D" q/ U
  57. * 输    入         : 无
    ) M9 t+ W; G7 {" |# v) S- F; s# v
  58. * 输    出         : 无
      ]- Y& E, [5 M8 L1 C
  59. *******************************************************************************/# ~, C2 ?$ y9 v. g6 n
  60. void IIC_Start(void)% |' r$ Q; w2 X- b3 Y1 q
  61. {7 G; V" E1 G& @
  62.     SDA_OUT();     //sda线输出& p4 b5 N: K8 |/ ~& B9 N2 T- D
  63.     IIC_SDA=1;      ) a, k& e0 q( R0 e
  64.     IIC_SCL=1;* e5 G/ Z  W; F' B4 C
  65.     delay_us(5);
    9 C" Z. Q* p" e+ F! F. U/ N
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low 1 P3 u% }( I5 M5 q4 q7 [8 d8 J+ V
  67.     delay_us(6);" x$ z  Y4 h, x  n2 Y
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据   W: u1 u, Q/ ?% q% q
  69. }
    ( y9 P3 k. p+ x
  70. " R* X" g; s0 i% S7 D! i0 [0 e
  71. /*******************************************************************************
    * u  z$ k0 N, Y6 d* b
  72. * 函 数 名         : IIC_Stop
    + K% y% @" p% W0 T7 o3 d4 R
  73. * 函数功能     : 产生IIC停止信号   
    ( j* ~8 V+ j7 n* r. H0 e1 i/ Z
  74. * 输    入         : 无
    8 W3 l6 a6 n' t4 w, m) g8 _
  75. * 输    出         : 无
    / Q+ P! b0 h/ u) _, h* N" c  R. W
  76. *******************************************************************************/
    " P( k8 Y5 p9 j0 j5 w* a
  77. void IIC_Stop(void)
    * U/ b* \  H9 Z; p) P
  78. {" a: q7 T. v7 ]# T5 l: }
  79.     SDA_OUT();//sda线输出
    # N, w% N9 A3 _& H. ~8 Q( {
  80.     IIC_SCL=0;
    # f! p  [. |7 y  _5 e' W% ^9 W( w
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
    5 k3 r9 ?& Y; N- r$ s5 J  p
  82.      IIC_SCL=1;
    ( K% Q, e2 O" y1 I
  83.     delay_us(6); + h" ^/ I5 G& E) J
  84.     IIC_SDA=1;//发送I2C总线结束信号
    0 m( a. c( L: I- E  q
  85.     delay_us(6);           
    . y; O$ {# s/ G- K! H
  86. }
    ' `" P; |& v  L/ M' E! U) Q+ j5 Z: U
  87. ! ~! j0 P( Z3 ]! D& C  }
  88. /*******************************************************************************
    ) ]7 M7 E, N* t) M% q$ ?- m
  89. * 函 数 名         : IIC_Wait_Ack9 U# q, b/ r" O' Q  M5 B
  90. * 函数功能     : 等待应答信号到来   
    : j- M) d& f2 s( w- S- i. J
  91. * 输    入         : 无. z6 V" z  A& L& \( d/ C- n: u
  92. * 输    出         : 1,接收应答失败( x  n0 s0 k# [& d) q2 M8 e
  93.                      0,接收应答成功4 e' A' K4 z9 e1 G# Z
  94. *******************************************************************************/. w# |% [* H1 ^" b- |
  95. u8 IIC_Wait_Ack(void)! e- y: E9 x- V6 N2 _  L" H
  96. {, S, J: F& F6 M! v
  97.     u8 tempTime=0;) F! o' J8 L4 B4 {. p: q
  98.     SDA_IN();      //SDA设置为输入  
    4 G* d- x0 @) _; z/ P6 b
  99.     IIC_SDA=1;; r; y2 O$ Y3 M8 P! |, R% F. [4 W
  100.     delay_us(1);   
    + ^1 }0 M  Y2 l! K+ k9 G3 V6 [" A  e1 \
  101.     IIC_SCL=1;
    ; {) k  f- B3 R" ~
  102.     delay_us(1);  4 a. j) e( g- E' i
  103.     while(READ_SDA)
    : n- t( h7 }& u0 a6 F3 m  q
  104.     {8 q. n/ V& G5 m0 X, p. p& z
  105.         tempTime++;
    % b9 F+ Q! N' F( _( V; u0 t
  106.         if(tempTime>250)
    ' r" ?0 y$ ^1 a. p
  107.         {  d4 j; V0 _! l+ D0 n: C
  108.             IIC_Stop();3 c5 G& G& ~) n7 w1 A. b* ]/ m2 c( P
  109.             return 1;
    5 `4 D  j( \: [
  110.         }
    0 @: j6 O; s# ^; t/ U* F% A4 Z
  111.     }
    / L4 Y, E) f3 h( Z
  112.     IIC_SCL=0;//时钟输出0     
    * \4 i% n' l1 ^
  113.     return 0;  
    8 p8 b; t4 f4 ~0 L9 Z( F( S
  114. } ' p9 c9 T3 \. p1 C

  115. $ ]& F8 ~  r! }' l4 ^
  116. /*******************************************************************************& D8 R* X& w- L5 Q2 w
  117. * 函 数 名         : IIC_Ack( c1 X" o2 h9 _& I
  118. * 函数功能     : 产生ACK应答  6 b# u. v$ I4 O! H4 @2 W3 Q* U- P
  119. * 输    入         : 无
    8 k$ _% y! R* g. e
  120. * 输    出         : 无
    8 Q6 {; e3 w) y" G) X- o
  121. *******************************************************************************/# {' \: r& h: b
  122. void IIC_Ack(void)
    ! g( m3 c! M6 H/ e" q
  123. {
    % M6 }8 @0 Q5 f6 ^# H
  124.     IIC_SCL=0;
    % d! K! `0 S7 F6 w4 N; w+ F3 i
  125.     SDA_OUT();
    ( b  \( Y$ f! ?! i
  126.     IIC_SDA=0;
    / K+ b# R9 j% ]' y' g, Y
  127.     delay_us(2);
    2 Y, D) u/ J" H9 I0 [. {
  128.     IIC_SCL=1;
    6 U  a4 z# e; W0 Z1 c
  129.     delay_us(5);
    ' V* _- o- |  v$ W
  130.     IIC_SCL=0;" W$ z' j2 M6 v+ `6 a0 B5 w9 h
  131. }
    & E, \/ I+ V! h) ?- o& W- ~' f

  132. % C6 r  {8 p4 y4 Q$ g) t! |. }- X9 R
  133. /*******************************************************************************4 |7 i* m# H+ S' u5 u: c) U! c
  134. * 函 数 名         : IIC_NAck" o: P6 W, I  I5 p$ [
  135. * 函数功能     : 产生NACK非应答  " E6 s8 ^% r/ F6 Y' e  J
  136. * 输    入         : 无$ Z" _$ \. H) _9 }; [
  137. * 输    出         : 无
    ) c* i- Z; [, l' {) w6 ^9 P6 I1 @
  138. *******************************************************************************/      
      i3 K% T- G, Y. n, P
  139. void IIC_NAck(void)
    " |# U% a1 |  Y! @/ m& _
  140. {# p( U. v; @" g, S. P" x8 [
  141.     IIC_SCL=0;
      y; r* }, @" `* a, c4 R1 X
  142.     SDA_OUT();! b  L, B) L7 }2 L
  143.     IIC_SDA=1;
    ! z. S- b3 j( M) ^+ \% S* Y
  144.     delay_us(2);: o. {, r) B7 c( b" p. t
  145.     IIC_SCL=1;" x! U2 z6 R" D: A9 ?8 I
  146.     delay_us(5);
    ' n" z2 [* \: s3 n- E8 K
  147.     IIC_SCL=0;
    6 v, x+ Y8 }0 t2 X
  148. }
    $ _# W  f5 d( o/ `9 j& ^
  149. 4 t' X$ x7 \! I6 ?0 n- T! ~
  150. /*******************************************************************************! S& r& l' l; R3 T4 N
  151. * 函 数 名         : IIC_Send_Byte
    - J8 H9 n! ^0 Y, @/ D3 i/ _
  152. * 函数功能     : IIC发送一个字节
    8 {5 c- m! v# R' ?' s) `
  153. * 输    入         : txd:发送一个字节/ g3 K  N- n* S8 P' B, ^  X* ^
  154. * 输    出         : 无* _3 r$ S( N3 i; m$ y+ J4 [
  155. *******************************************************************************/    ! C( l. a8 U6 ^5 d. e
  156. void IIC_Send_Byte(u8 txd)
    # a; C1 ^2 E- ~, l& D
  157. {                        8 m# e1 _7 B$ [
  158.     u8 t;   * D: F$ `( h& Z( b) K( ~9 X1 \
  159.     SDA_OUT();      $ r1 o% N6 ]3 Y( N7 i+ e
  160.     IIC_SCL=0;//拉低时钟开始数据传输; f2 u! d- t4 i( I% I
  161.     for(t=0;t<8;t++); q: W0 a8 ], u9 @
  162.     {              
    5 i" ~7 S+ l& F* t* v
  163.         if((txd&0x80)>0) //0x80  1000 00004 a' J  C; K" E8 Q. ]4 ?8 u
  164.             IIC_SDA=1;2 p$ l2 x! g* t) A6 \; z, c8 s
  165.         else
    / o- {$ D( L# b/ J, g2 Q
  166.             IIC_SDA=0;1 e4 \  v( R7 d
  167.         txd<<=1;   
    9 R( R3 c& r6 }. \: J) a# t/ d
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的  ^% v2 i# l- z/ o% {, |' X1 f
  169.         IIC_SCL=1;7 h4 n+ Q9 Q0 n2 w9 z: B( b8 v
  170.         delay_us(2); * {; M8 ~4 i0 Q1 \
  171.         IIC_SCL=0; / Z. m7 |! F( q4 U& \* J8 z9 `
  172.         delay_us(2);+ k2 V; a; b& t+ \* m
  173.     }  * f8 j0 C+ m% {6 H/ q
  174. } ( ~/ R' l4 `8 I! T6 A
  175. & v  v8 q( x& G' z. h6 j
  176. /*******************************************************************************7 \9 t5 }) A# @8 y
  177. * 函 数 名         : IIC_Read_Byte' ]0 `3 A# y0 s* M7 m
  178. * 函数功能     : IIC读一个字节
    1 c9 \* |0 U# s! {. X7 K& \, {" U
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK
    7 ?" I2 i& Z2 G% O* \8 |
  180. * 输    出         : 应答或非应答- ^( {9 I5 G, G
  181. *******************************************************************************/  
    - y- w6 e, a' E. a% j# g: w
  182. u8 IIC_Read_Byte(u8 ack)5 u+ C; M! _) d4 q. {; a4 O
  183. {7 I* ?9 L, w! A$ [$ d4 v7 l3 r. X
  184.     u8 i,receive=0;4 V. m9 G& }1 ]0 u  \: c% j
  185.     SDA_IN();//SDA设置为输入
    / d, L5 R% u; y* w: X3 z3 {
  186.     for(i=0;i<8;i++ )0 t* q! \4 U! x0 n+ n
  187.     {0 p$ B3 D$ }1 M, l* f. B  S3 ]
  188.         IIC_SCL=0; 7 Q' s( `( Q; R( ?* q% x  m
  189.         delay_us(2);2 I# r4 d: y3 E+ Q  o
  190.         IIC_SCL=1;  X6 s4 i$ P/ ~$ [# h7 i3 C
  191.         receive<<=1;
    5 F% \8 U7 T3 l) E% I
  192.         if(READ_SDA)receive++;   
    " D- y" A" m  T& l
  193.         delay_us(1); $ n" D6 }9 a8 C0 T3 }1 ~
  194.     }      ) w! m/ ~, ~8 D0 z7 j
  195.     if (!ack)* {1 j2 R& ~: z, D0 i1 v
  196.         IIC_NAck();//发送nACK
    , N% R2 `+ T1 O! [" j$ G
  197.     else
    6 n& j: ^/ H# }2 o* F, u# B2 ~
  198.         IIC_Ack(); //发送ACK   : G5 R- N: b9 k
  199.     return receive;
    , h0 `& D9 I/ C' o# I/ p, m% Q6 d1 j
  200. }: i$ u# Y. b3 @  ~) {4 b
  201. /*******************************************************************************
    9 {) L/ T9 e9 k; `
  202. * 函 数 名         : AT24CXX_Init
      L; w4 ~1 \! v: p
  203. * 函数功能     : AT24CXX初始化
    9 S/ L6 i$ b$ M1 w
  204. * 输    入         : 无5 w! G. L1 i/ Y
  205. * 输    出         : 无; F+ C- A0 v0 W0 ?+ d& z& G
  206. *******************************************************************************/
    3 p, Q; a! ]7 @/ E3 S
  207. void AT24CXX_Init(void)
    4 P1 j+ A2 p" }/ Z, I9 u
  208. {
    : o) K/ N$ L5 }5 V1 K" s
  209.     IIC_Init();//IIC初始化3 J6 \9 d4 k6 f. ?6 i
  210. }( {( ^" s0 V7 j! e1 h+ U
  211. ( z3 H) f) i% Q- f8 B: F; ]9 t
  212. /*******************************************************************************
    " m1 L/ q9 r. N- \$ t
  213. * 函 数 名         : AT24CXX_ReadOneByte
    2 }2 y7 @, O1 i  w$ t
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据2 @" D, j9 f# \; j4 @; g
  215. * 输    入         : ReadAddr:开始读数的地址 4 u6 o8 U: U, O* T- O! \
  216. * 输    出         : 读到的数据
    , Y& S$ G, h* J& [
  217. *******************************************************************************/7 u- q& U! Q) _* n0 k6 R) F
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr): ]$ J* k: g' d
  219. {      
    6 @4 G; m- _( I& L0 j9 h( P
  220.     u8 temp=0;                          ; q0 ~4 [7 v- y5 ]$ p# o% G; C
  221.     IIC_Start();  
    3 t% z( h9 z/ t7 O% M
  222.     if(EE_TYPE>AT24C16)
    3 U1 p3 P0 F' l0 @
  223.     {
    ) N& R5 o" S) D3 n" v) i' V
  224.         IIC_Send_Byte(0XA0);    //发送写命令
    ) W" i" E% `7 l
  225.         IIC_Wait_Ack();
    3 F8 [+ o9 w* r1 c  e$ t% L
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     * Y0 v; r+ r' I/ U. O$ M# c8 z
  227.     }6 ?- B* {* t1 S8 S
  228.     else
    $ D( X2 ?' Y1 [
  229.     {) ?( Y0 B9 W4 n6 j
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据( R% B1 i: Q. R
  231.     }     , B; p& p8 ]' f/ l4 ?6 H% t
  232.     IIC_Wait_Ack(); 7 ]3 v; @# y7 F% T% g; p+ s
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址9 {1 t; Z" Y; a6 V  w2 Q: e
  234.     IIC_Wait_Ack();     
    ; t+ x4 a: V8 T7 g' e
  235.     IIC_Start();        
    3 \' F6 ]4 O7 m, m, b
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      
    ' A$ c2 i& d/ n4 [! L5 j
  237.     IIC_Wait_Ack();  + B- r6 M* h# E& Y6 n$ \% N2 O' @
  238.     temp=IIC_Read_Byte(0);     9 E3 ^. E+ y0 A) E5 R* w
  239.     IIC_Stop();//产生一个停止条件     
    ! r  O  I2 t  d; i, F7 [+ T# b3 P) h
  240.     return temp;5 ?% |  n! o  u' O; i) _/ c( j
  241. }# ?( I* [2 D4 E, k/ U6 g
  242. 0 t" K8 l; ]! j( s# b7 f
  243. /*******************************************************************************
    % [: P, E4 {* R8 v; J. X
  244. * 函 数 名         : AT24CXX_WriteOneByte
    0 N; i6 d! H: C
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据+ E' r0 {) N: `+ a% I3 {4 Y
  246. * 输    入         : WriteAddr  :写入数据的目的地址
    2 z* C" v7 D& [' T
  247.                      DataToWrite:要写入的数据: I1 \, U  @) ?
  248. * 输    出         : 无2 u! w" h$ A7 O0 E1 |" Q- O
  249. *******************************************************************************/1 ^' f- A, X+ w( I
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    - u  t9 s- r' e$ b
  251. {                                # v- S* G7 Z  `# x9 L+ V
  252.     IIC_Start();  , A# X( a. t" e; C0 I4 `! G
  253.     if(EE_TYPE>AT24C16)& [" ?( o% T$ v& @) L& H
  254.     {& i# i7 R" J& i0 F& Y" K
  255.         IIC_Send_Byte(0XA0);     //发送写命令3 `' n! M. K$ ~6 v/ `
  256.         IIC_Wait_Ack();$ x8 ]/ K* P" X! p
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   
    : O: J/ U7 s, H+ r& a
  258.     }
    1 y5 ]+ G! [% M
  259.     else
    8 r0 \# `" I2 N' j2 u
  260.     {7 G/ Q9 W9 o  X1 Y: }
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据' k; T- c) I2 j# e! R+ x% }
  262.     }   : e1 ], f) z, c- j, A4 R: ^
  263.     IIC_Wait_Ack();    4 z0 x( U* X" ~# Y( H
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址( q+ f  u9 i9 B2 E4 {: ^5 S, f
  265.     IIC_Wait_Ack();                    * ?* k( G! u- _7 @6 S- \1 D
  266.     IIC_Send_Byte(DataToWrite);     //发送字节          ) s1 w# b" ^' [$ ?  c8 m# ^+ t9 j5 l
  267.     IIC_Wait_Ack();            # Q; ~% D4 d9 M9 ]% X( B
  268.     IIC_Stop();//产生一个停止条件
    & Q$ r" ]+ z' q7 w) u
  269.     delay_ms(10);  
    % }( v3 G3 G8 x& d) r
  270. }" Q/ M* s* A" Y, u$ U: L4 {

  271. . k4 R% n- q& V6 o. e3 m
  272. /*******************************************************************************
    4 ^# ]: _3 }$ ~: ~1 i. u
  273. * 函 数 名         : AT24CXX_WriteLenByte$ L% U/ B3 w, F- I2 K+ [6 p
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据5 ^, H( f3 D% P1 S$ ~: y- a0 J% u5 R
  275.                      用于写入16bit或者32bit的数据$ i% z' e6 L# j8 |3 Y$ T  G7 S+ _
  276. * 输    入         : WriteAddr  :写入数据的目的地址
    " `- G! V& X7 r/ u4 ^. z
  277.                      DataToWrite:要写入的数据
    0 z$ r0 h5 n7 P8 Z1 Y! I. E& f* B
  278.                      Len        :要写入数据的长度2,4
    2 }0 ~% Y% ?1 b5 k3 o
  279. * 输    出         : 无
    8 h3 w: c6 v: z
  280. *******************************************************************************/% o2 Z7 w2 J: {# ]# |$ U6 V
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len), S( F1 i$ P1 A  b
  282. {   + I# q! G4 _% j# x
  283.     u8 t;" B9 I" C2 W  R5 x( j: @
  284.     for(t=0;t<Len;t++)
    / g( ^: G, p" m7 X
  285.     {* t, V/ m8 y! ~$ f* z, F/ O$ S
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);- |8 q0 w2 r' {. y4 u9 E
  287.     }               
    5 [( m. N  t  Z2 I/ i
  288. }6 U# k0 o5 t8 w
  289. % h: w" j, v7 k( Q1 r% X( r
  290. /*******************************************************************************
    9 g6 ^5 i! s1 L
  291. * 函 数 名         : AT24CXX_ReadLenByte
    4 o6 J% i& q5 Q3 [
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据
    ( m+ C* J) ?9 M: [
  293.                      用于读出16bit或者32bit的数据) d4 v" f  y+ g- z$ t
  294. * 输    入         : ReadAddr   :开始读出的地址
    + m9 p# ?/ r/ L
  295.                      Len        :要读出数据的长度2,4+ @2 H3 I1 \& ^, }2 A. F  r
  296. * 输    出         : 读取的数据" v, w* x2 L6 L% ~
  297. *******************************************************************************/
    3 X- u, K( |. ~4 Z. W: k+ p
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
      D: q5 T7 |" J7 [# U2 P
  299. {   
    8 c( h: E% P( [3 b: b1 F
  300.     u8 t;
    9 X2 C. G8 p" b- M% \
  301.     u32 temp=0;
    ( ~; }/ z" O; _3 F) t. k
  302.     for(t=0;t<Len;t++)
    * G8 ^" V# Q- j! }% q: @/ o
  303.     {+ d% q. v; J& K" `0 y2 s: ^1 ?
  304.         temp<<=8;  \1 |7 ]2 l  `; y% q1 ^
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);         
    8 z# z! m4 M* b% F% {5 Z$ K
  306.     }4 `$ M8 J0 o7 E
  307.     return temp;                : m# g4 n- [$ `; @$ V
  308. }8 J' H, q1 m2 ^9 Z% w5 B+ v
  309. 4 }2 O) u# F9 d2 s( o( e
  310. /*******************************************************************************; |7 d# u( z+ v' r1 F
  311. * 函 数 名         : AT24CXX_Check
    ; O$ `; ?# U& W  B
  312. * 函数功能     : 检查AT24CXX是否正常, W. k6 D$ i" N9 ~
  313. * 输    入         : 无
    9 q7 ]  a/ ?2 U8 t- H. }; t
  314. * 输    出         : 1:检测失败,0:检测成功5 f% i# p( A! V5 X0 i
  315. *******************************************************************************/
    , [! e! I8 R' ?6 f
  316. u8 AT24CXX_Check(void)
    . q: G3 A2 |3 l. h. g
  317. {1 v4 h! E; I- l! s4 ?4 o2 L
  318.     u8 temp;
    ( W$ s5 K: T/ U
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      1 N1 K+ \: m: M& `& [
  320.     if(temp==0x36)return 0;     ( ?- ~1 U2 y  v4 d6 s
  321.     else//排除第一次初始化的情况
    + F& D0 J5 x, R
  322.     {( Q: n  p& T- k  \1 ~
  323.         AT24CXX_WriteOneByte(255,0X36);
    - K2 ]- u# ^8 `% P7 x( s- x8 W
  324.         temp=AT24CXX_ReadOneByte(255);   
    ' C* A- P+ F! e' S2 C) ^
  325.         if(temp==0X36)return 0;
    & A9 ]" m' K. D! K- b! V, V* _
  326.     }; p) k3 ]" ]: @
  327.     return 1;             0 w7 v, j) [0 z6 f
  328. }% y* k) Z' T2 \& B& b% R
  329. " i" a& b# O8 F! p3 U
  330. /*******************************************************************************1 E" ~5 {* ~/ N9 Q6 a
  331. * 函 数 名         : AT24CXX_Read) u* x9 S5 o( ~6 `
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据, s2 L3 |* e% d( B" }( k. }( x1 N
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255
      f% C0 U( Z5 I3 X, w2 e! n
  334.                      pBuffer  :数据数组首地址- r, i+ @$ Q5 G# t
  335.                      NumToRead:要读出数据的个数* H% v$ S/ R  m( S% X
  336. * 输    出         : 无
    / [5 Y4 h) `9 a: q- U; C
  337. *******************************************************************************/
    ( ~5 A& h& s! ]% v: M" h
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
    * B9 p  B6 @& c" y
  339. {
    : p8 }- U8 [$ w1 E) y# }0 _
  340.     while(NumToRead)
    , Z- g* a+ |0 F
  341.     {" l- @3 w( L7 T3 E
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    * P3 F4 N" q( Y1 n
  343.         NumToRead--;
    " w, K' i- B/ x* }% Z
  344.     }
    ' l, y, C2 g' U5 n% A% q  X& z
  345. } 6 i8 u$ Q7 x! L- i# f' B
  346. ) d6 j- m6 X6 t
  347. /*******************************************************************************' V/ ~  a% i9 z
  348. * 函 数 名         : AT24CXX_Write" X8 G4 D8 ~+ s+ [% u
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据
    / v( |8 G7 ]6 t  B6 t0 Z
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~255
    2 s9 J: P% |. X. O& u% B+ B
  351.                      pBuffer  :数据数组首地址5 A( B' {2 U. X1 ?$ Q2 f
  352.                      NumToRead:要读出数据的个数
    # z" `: Q* q( p) D6 V
  353. * 输    出         : 无/ i3 R, O, \6 B# E
  354. *******************************************************************************/4 e) M) f8 A% X
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)+ V! v2 Z: m6 L4 m6 q* @/ u
  356. {+ M4 q- f$ ]# b( s) V) E' c
  357.     while(NumToWrite--)2 i! Y9 i+ v5 J3 G8 J1 E
  358.     {& i/ o3 B% T, z. o
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);/ w% T6 L' x$ ~/ @
  360.         WriteAddr++;$ v" i6 ]+ ]6 m9 \
  361.         pBuffer++;
    : j; w& L: @# i' V
  362.     }* a8 E5 x* k8 G' H  a" ~8 N" e
  363. }
    # t: o( m1 x( e: ~' H
  364. .h文件如下, b5 R, N( n/ Q4 I# V% B

  365. ( {. C; p! ]6 E8 H) f
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C02
    6 l& i  x4 C7 I
  367. // 可修改成AT24CXX系列中的任意一个
    ! O& Y. C; @4 P$ b$ z
  368. #define EE_TYPE   AT24C02
    6 Y; d7 Z  x, f$ F
  369. # R. J" |% \* [6 a0 d" y$ l8 S: d9 e
  370. // IIC函数
    / V) @" ?2 f8 N9 ^, q) m; V% g
  371. void IIC_Init(void);   // 初始化IIC的IO口     
    0 C" t7 C! d* D/ ~$ [
  372. void IIC_Start(void);   // 发送IIC开始信号3 ^) z. t2 W# Z* E
  373. void IIC_Stop(void);   // 发送IIC停止信号8 B  B9 d- {; W
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节
    2 e+ m: B9 d4 A
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节; b$ }% F% F+ S4 b  g9 u
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号
    0 }$ m: }; _8 ~5 ]6 C
  377. void IIC_Ack(void);   // IIC发送ACK信号
    4 C; E4 s8 h, l/ r2 v! s" u) |
  378. void IIC_NAck(void);   // IIC不发送ACK信号
    % G9 y5 }9 ~. T

  379.   q% T; T( R5 J1 L" |% _/ K  P; G
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节" `5 s. |1 L2 W
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节
    8 s3 Z% Q. b* R$ U# Y+ @
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据, b& _. d) G7 X( O5 O
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据
    ' [: U. i4 U! y  k' u6 Q" Z
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据
    * R: B% w4 p$ C  Y- {
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据
    & M7 n, C6 f+ ~" o

  386. ) o' [3 M1 r2 s5 L) m: \6 s6 i
  387. u8 AT24CXX_Check(void);   // 检查器件  o- D  O7 t8 ~* q# X$ u) O! V
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码
) ^% a" U, H$ p; Y* ]0 a
六、应用实例% H( i0 e0 \/ S) N% x3 I
给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下
- q: o! Q+ L8 Q$ K  V
  1.     AT24CXX_Init();   // AT24C02初始化
    1 t$ ?6 _5 F' `( V. L1 \9 X
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常: L" k5 Q9 K& @* |
  3.     {! W! N5 K& l. L1 I
  4.         printf("AT24C02检测不正常!\r\n");
    ( v0 R; T* a4 U& w* g
  5.         delay_ms(500);/ F4 I- y0 B0 ^
  6.     }5 b( X$ \% X) D0 u4 [
  7.     printf("AT24C02检测正常!\r\n");
复制代码

# p* k, @) u6 [. N1 Bmain函数如下4 l- p$ r2 l. i; S! j
  1. u8 gWData = 0xaa;   // 准备要写入的数据
    7 v, `4 `' V! _
  2. u8 gRData = 0xaa;   // 存储读出的数据) d$ c1 K# E, ?) H
  3. ) X5 R4 H- v. L# ~# ~! u7 _' h) D1 H
  4. int main(void)
    7 _. B2 o0 ]4 _1 S/ h# G  R
  5. {# U! A7 K# @/ @" u+ x4 X$ r8 B
  6.     Med_Mcu_Iint();   // 系统初始化
    ! A4 h, ?0 q( _& u; W. ]
  7.     , [6 h1 m# F( Y
  8.     AT24CXX_WriteOneByte(0,gWData);; ^( J+ O. d; B7 q+ k! C
  9.     printf("写入的数据是:%d\r\n",gWData);- }$ r# g* w, S$ z8 _
  10.     / F: g0 c7 D2 U
  11.     gRData = AT24CXX_ReadOneByte(0);3 c( h6 ?* J: ]- Y( Y& N* }' ?+ d
  12.     printf("读取的数据是:%d\r\n",gRData);
    ; Y# _4 `1 I9 c5 I5 H: Z0 d
  13.    
    7 m  a" E7 W6 S% G( l* {
  14.     while(1)
    ' R! X2 l: ?9 |  o
  15.   {5 B7 V7 O/ |0 l* j9 D* g* o
  16.     }
    ! e, ^) K/ }3 Q! y8 ]
  17. }
复制代码

- Q" `6 ^2 j9 j4 O串口打印结果如下
' N8 O* k5 p5 e- N1 ?/ c/ L8 t8 s/ E9 U* d0 X

% z" u( v* M. O! L
串口打印结果

$ v$ n0 q9 z* G9 @! @' j( I/ i
: _1 F  {/ L* Z# g4 ^

9 R9 R, s% M: z1 Q* p
七、拓展应用- R1 W5 ?' l1 a$ p
AT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。
9 d4 ?3 C$ ?. k8 y- E" W* ?0 r5 O1 ]; k! R5 g
9 g% o) [" V5 T7 t. j. z
7 p* H, e0 p* o* L) t; d
转载自: 二土电子
) V8 y& W1 W0 Q, h如有侵权请联系删除* ^/ E- I3 s5 d

8 L; l5 a9 A# t  F% @
微信图片_20231023203400.png
收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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