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

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

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介2 P5 q( i% R* \8 q- x+ i
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篇。1 Z) D/ C3 P! S( V5 \

) N+ {+ ^5 O& k

9 d; M3 v3 B  B. F/ f二、AT24C02引脚
, k! {3 Y& o# U- _5 i

0 S: u1 y7 x- O# h7 a. @  P: ?: L3 ~
微信图片_20231023203334.png
, K5 u4 O2 `/ a
AT24C02引脚定义
& [- p. K' ^" g3 Z7 U' ^6 ]
# q) f- [" [$ K' G

1 ]& V! I$ S$ A, G; d. y" f, w三、AT24C02寻址

- E  N9 O- _5 ?+ `; Q( I使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。2 p) \( B' H% v& o4 u5 y4 e! W% R
! Q/ o: J6 u8 n  r* V
微信图片_20231023203357.png

* [1 Q) l( y5 E" X$ x7 k
AT24C02地址信息

) D5 u9 G$ z. K

0 c7 O* f( E; I8 Y5 ~  x) D' {' D

4 l+ E6 v- W1 x9 I2 n$ _器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。$ k0 D% i  ^2 m0 ]4 [3 ]

6 @& W: a6 C" `' g0 `8 c四、AT24C02读/写操作
, X" e! u8 o: ~0 [4.1 AT24C02写操作
: L; j$ D2 C! a" [" w" k
写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下& k. M) |& \7 N$ @- q( u, q

- W7 {5 k7 `  q6 p; w
7 D. f5 \9 ]. D9 |& {) i: {
微信图片_20231023203352.png
. ]" e: F" Z6 K6 w# W
写操作时序图

, R) _& |6 t* K9 L+ r

' R! y/ p- h" B# X8 S- E, P" p, M. F1 F, N. ]! _% H) F: F( f9 O9 s
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。9 d3 |* G7 o" c( J' ?' d# z+ `

/ h9 l0 X, y& [- w接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。! \1 l' n, S" d/ j

4 W) T0 d8 a: G
" {6 H6 J% V/ J1 q$ x- o
4.2 AT24C02读操作

# T1 x1 J8 g0 \AT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。
' R& w+ L( Q& |9 H' Y% a- B% q• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下% y4 w9 ?# v* B/ _* X( }
/ G5 r% O/ W( U. ^
5 S9 I2 _! M& Q) X! m6 L6 O2 j8 [
微信图片_20231023203350.png

) m" t; \5 }) O. I; X! ?8 M
读当前地址时序图
0 F% t0 {( G! M2 U( t

3 x7 ?+ W! n: `) ~% G" E3 q$ x+ _$ q1 Q- ~
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下
2 r, n1 V4 a' _" v/ g9 I5 ]
5 Q+ ?3 J. `9 p, u( k
0 B7 \8 n8 m9 z. `4 W, i
微信图片_20231023203347.png

* _; N. T' B2 @6 g' l: P
随机读时序图

; i/ w2 f% O0 d( X+ l. X

% V/ J6 [9 [- z& W/ |3 R
' Q0 c0 s4 w8 [( j- Z3 T' R' a

& ]/ `3 K3 A, d8 x• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下# z/ f. P/ x+ P! y5 \- H5 }
& s, H0 P) _& E' x' Q

1 B( f' b: X/ R4 P
微信图片_20231023203342.png

8 s4 x' l' r9 R
顺序读时序图
1 U6 Y* g% \" {1 U/ v

' C6 B" E4 g" e4 \! f. K
  B' Y4 O3 |+ j1 M% z+ Q
五、AT24C02程序
0 T, p+ \" @; u. K3 V这里给出一个AT24C02的程序,仅供参考
0 x: J* k" o/ j; I
  1. /*******************************************************************************1 i- l8 T! _+ C
  2. * 函 数 名         : IIC_Init
    / o( ?5 ~; _( z% [& W* ^4 T" J# l1 y% Z
  3. * 函数功能     : IIC初始化
    . O4 U" Q- U# b6 t( @. G- W
  4. * 输    入         : 无
    ; ?% C" S* c% R. {$ i, {* \
  5. * 输    出         : 无
    % B1 x' U4 r+ K7 Q4 T$ t' ?+ B* X
  6. *******************************************************************************/1 s: {+ M* G3 J$ y
  7. void IIC_Init(void)
    ; F  U! v. z/ O
  8. {
    # B5 @  n6 y: {4 w+ P
  9.     GPIO_InitTypeDef  GPIO_InitStructure;: Y  j; y, O# K. X' v  i1 \' [
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);0 y+ ]: v4 ^- c! U5 ?
  11.    
    + N! ]' n; z3 x( N
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;" Q* Y1 B7 C: `! _
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;3 I: J7 C, n# N! F$ @
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;; X* _2 U( d! E5 ?2 L8 U
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
    & a4 K) }: [0 T$ J9 w
  16.       U- P0 Z/ a( ]% D  O0 C6 m
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    : t7 [  F8 Q) H- t* w+ X
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    - n& E& L4 [4 H7 F7 m' K7 k
  19.     4 I5 W# X8 a/ Q4 G. @
  20.     IIC_SCL=1;
    ( l9 x, W# Q+ J4 Z) s5 N
  21.     IIC_SDA=1;
    % a9 D# m, ]  w1 V
  22. }
    3 N3 a$ a: b; U: Z' ^: o, b  t
  23. /*******************************************************************************4 ~. O) ]) Z2 t1 _# p' p5 [
  24. * 函 数 名         : SDA_OUT
    + T( n2 [- I# h( L  T4 R/ h
  25. * 函数功能     : SDA输出配置   
    % @7 j7 f; J7 t% V+ u
  26. * 输    入         : 无8 b  C4 `# P7 c0 I% m( ~
  27. * 输    出         : 无
    / p; r( T7 R% z- ^7 \2 R) y8 }
  28. *******************************************************************************/
    & W0 ]. f2 ~7 [0 U$ |& j" l3 G% y% X
  29. void SDA_OUT(void)
    ; K  [! e6 k: P0 v
  30. {" v9 L" C* y: L) W" l
  31.     GPIO_InitTypeDef  GPIO_InitStructure;
    0 k. H: T+ ]$ ]4 E! x/ c
  32.    
    8 j; u: [: R" g5 p% z
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    9 q- `0 U* m- q3 |" R
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;0 R# O) @9 d0 K! K/ q: \+ C5 m# f
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;0 y' P3 }- h. L6 T& \
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    7 ], N4 m, `# d( P
  37. }
    7 j* `0 [" z& j2 r

  38. - s9 o1 }' T' l* c; n) i- N
  39. /*******************************************************************************
    7 Y2 o- g/ Q% D- l' ]( t
  40. * 函 数 名         : SDA_IN
    + M4 X! {; S3 W) J  e; b
  41. * 函数功能     : SDA输入配置   
    9 [3 _2 ~6 L% X% G7 o9 h* ^
  42. * 输    入         : 无
    ( w% C, ~( P' b% N: _1 N7 K
  43. * 输    出         : 无" _* [( H) \, Y' S0 I3 w% b
  44. *******************************************************************************/
    ( O' a: B  [  w# h5 B. ?
  45. void SDA_IN(void)+ e6 F; ?; k2 ]3 f% D2 Z2 S4 ^
  46. {  \1 q  U* @3 k. j4 C" e& P
  47.     GPIO_InitTypeDef  GPIO_InitStructure;& {2 T7 X0 \5 G/ n6 ^$ Q
  48.    
    ( \3 U+ R  U) a! w. P/ f/ b
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;6 r, {. o+ C7 y7 ^
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
    2 ]: L+ J* ^- K  w* s2 n: P
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);% B% s% \; H) o* q$ ~9 m* b! I3 l
  52. }
    $ O1 o, T( x8 X9 l0 r- f( @
  53. 4 _# v5 H# A; f. P
  54. /*******************************************************************************
    , J$ {; B) Y) I4 ^' W; h1 ^
  55. * 函 数 名         : IIC_Start" S1 S# e3 h, d  J
  56. * 函数功能     : 产生IIC起始信号   
    . o1 y' i5 A$ t6 F! S' Z
  57. * 输    入         : 无
    0 I6 c/ Y* ?7 X* k# m: \* A
  58. * 输    出         : 无
    ! E6 i$ t" o' f' d
  59. *******************************************************************************/
    - ^% V* B$ M5 L% ~4 L2 ?/ f
  60. void IIC_Start(void)
    3 p- D% l# M! [: L0 ^: U% e
  61. {
    0 x& `( L" Y3 D7 A1 [' Q  t( f
  62.     SDA_OUT();     //sda线输出2 v4 d2 Z# t/ x1 T
  63.     IIC_SDA=1;      / E9 l" v+ B8 Z5 ^6 ]
  64.     IIC_SCL=1;0 k/ A% s: _  q8 B6 x' y
  65.     delay_us(5);
    3 |  r, @& p! b9 m
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low ) C4 V8 S4 H3 z* \
  67.     delay_us(6);! }) I2 \% A. T2 i
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
    $ u) @9 ^1 l' Q9 C
  69. } & S: T, E. o8 E; I4 H2 g5 a2 S) f1 S

  70. ! T' p1 I+ {- b
  71. /*******************************************************************************
    ) |2 ?! b9 t; l5 j
  72. * 函 数 名         : IIC_Stop
    7 z3 B& Y4 U6 h6 V5 k  z5 C+ r7 T
  73. * 函数功能     : 产生IIC停止信号   
    , d. p5 A; K6 i
  74. * 输    入         : 无. R7 A# r+ O: |3 S( Z  Q  @
  75. * 输    出         : 无6 R& a* h# `0 q; d
  76. *******************************************************************************/
    ! `) K  t3 C4 K: x$ d) V
  77. void IIC_Stop(void)
    $ x7 Q0 i: R" k
  78. {# F% T0 U5 B% K. E* R, }/ `
  79.     SDA_OUT();//sda线输出* h! q4 l, C) b) n0 V4 m
  80.     IIC_SCL=0;! F3 ^- ~! A1 x  }
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high) S# ^! a! K; A5 C7 X+ g7 Q
  82.      IIC_SCL=1;
    $ j5 h- E* a% @. R7 I$ l
  83.     delay_us(6); / r* |$ c: R( A
  84.     IIC_SDA=1;//发送I2C总线结束信号1 S" Y) |/ u! i$ p  f: o2 G
  85.     delay_us(6);           
    0 c# U) Z$ P/ M
  86. }
    ( P3 F" H+ D4 W1 t( P$ X. K
  87. / n# o* }7 G- t& Z- K, `
  88. /*******************************************************************************
    4 i+ D: N8 ]2 ?: C
  89. * 函 数 名         : IIC_Wait_Ack
    / p  g- G' r7 U
  90. * 函数功能     : 等待应答信号到来   2 r3 O* C1 F* X
  91. * 输    入         : 无9 X& Y; p1 \% Y& h6 J
  92. * 输    出         : 1,接收应答失败
    7 K, C8 A3 z- e  @- e8 P& N. z7 N6 z
  93.                      0,接收应答成功
    ' ?* C. \5 N7 D2 l
  94. *******************************************************************************/1 s6 M( W8 z% E2 t& H. `( _) B
  95. u8 IIC_Wait_Ack(void)# W+ r$ q+ R' @
  96. {
    ) H6 ^6 O3 M' f% X! q' X
  97.     u8 tempTime=0;
    % U1 U: |. N  j4 A( L7 E
  98.     SDA_IN();      //SDA设置为输入  , p' P$ `$ T+ d# X3 m7 f
  99.     IIC_SDA=1;
    6 B; K3 h: ^/ z9 |9 G
  100.     delay_us(1);   
    # p2 u' b" Z( u2 d8 }: Y
  101.     IIC_SCL=1;
    ; S, `# S7 F- B; H4 Y
  102.     delay_us(1);  
    7 t% _2 c$ r1 J
  103.     while(READ_SDA)* q' S& j) Z6 w) Y7 m
  104.     {% S! r% K( b- s& v
  105.         tempTime++;& R6 ]( L. P- [; O- T
  106.         if(tempTime>250)# m) h5 `) P' `5 L2 y
  107.         {
    4 ?+ _9 `* F% ^0 w" ?+ |, i
  108.             IIC_Stop();) L' H0 K8 g& o* m2 i2 I; H& v
  109.             return 1;( ]) u! H! y: ?
  110.         }% U3 p3 I, m; \, X, Q
  111.     }6 D: m3 g% x! v& x( |, [2 f, K
  112.     IIC_SCL=0;//时钟输出0     9 w2 h8 d" f; |0 B+ _3 o
  113.     return 0;  . M- t. C2 v. S( L# o
  114. } 3 X+ E+ P0 Y7 s3 P4 f& T

  115. - {2 X; ?& R! \9 x0 Q" ^
  116. /*******************************************************************************
    8 O& V7 q. R! |0 q$ J: M* {
  117. * 函 数 名         : IIC_Ack5 |$ O8 n7 K/ f8 @5 l, Y
  118. * 函数功能     : 产生ACK应答  
    / Z( n# g* ]. _& V
  119. * 输    入         : 无
    9 e3 _" K% P6 Q$ o, E2 f
  120. * 输    出         : 无( q$ N7 @; T/ c& ~3 o% ]
  121. *******************************************************************************/. l; Y. f8 {& y+ Z- j/ u  V; V
  122. void IIC_Ack(void)" f1 @) M6 c8 `
  123. {' ?7 `- _6 {; |
  124.     IIC_SCL=0;
    5 J3 e( Q  R: T2 ]: l. u
  125.     SDA_OUT();% }5 p* Y' v. U6 |0 J0 Y1 Q
  126.     IIC_SDA=0;' f/ l0 `0 K  w- K- k0 ?* Q
  127.     delay_us(2);
    + D/ u% {2 \8 R) \9 m+ w
  128.     IIC_SCL=1;+ k8 h& ]- K6 z) M9 F( f6 `) I
  129.     delay_us(5);' ]8 {( M. \4 _
  130.     IIC_SCL=0;
    ' O4 U5 I& A( }1 V
  131. }6 G4 k' t1 i  w  _+ h3 I1 t

  132. % O. @! I1 M2 c, s0 Z) U2 M/ Z
  133. /*******************************************************************************% v7 c& k5 M5 z6 s
  134. * 函 数 名         : IIC_NAck
    " Y  o7 B/ z" V
  135. * 函数功能     : 产生NACK非应答  
    & U+ o2 S" E; Z5 }1 s9 A
  136. * 输    入         : 无
    ! b+ X) _1 V2 b, x- X6 ?. `, w) b
  137. * 输    出         : 无
    9 q. w  y* C9 j% i, q  V/ }; ]
  138. *******************************************************************************/      
    2 r$ L# i, o1 f* i$ a$ ]
  139. void IIC_NAck(void)7 o' p$ V" U/ `# ]8 C
  140. {; b! R6 r* _! t- w' ?/ d) g  c
  141.     IIC_SCL=0;4 T% J8 I$ u6 h5 A9 K: a$ D
  142.     SDA_OUT();& I% k1 {+ e& O& d+ h
  143.     IIC_SDA=1;: G! H- V, z6 D" F) n
  144.     delay_us(2);0 c6 ]' Z/ P% A' [- R, w
  145.     IIC_SCL=1;6 x  T5 p. \" Y
  146.     delay_us(5);
    / Y: Y( {- v- f8 X' c. M# a
  147.     IIC_SCL=0;
    $ V* \2 C5 v2 z
  148. }
    , ^- O4 ]. T# L
  149. . Y$ ?2 E0 C4 C: x: `2 ?% p
  150. /*******************************************************************************
    7 O, J, \; U% ~; [, u' j
  151. * 函 数 名         : IIC_Send_Byte
    # I3 C' C$ m0 i: n3 v, T
  152. * 函数功能     : IIC发送一个字节
    ' {3 O2 w/ A1 U+ F
  153. * 输    入         : txd:发送一个字节
    # c6 ^8 ?4 @5 y( R- R! k, f2 A' ]
  154. * 输    出         : 无: |* L+ q) n% U6 q
  155. *******************************************************************************/   
    6 c2 P4 G9 f2 a5 e; |9 d% `3 ?9 ?
  156. void IIC_Send_Byte(u8 txd)
    ' N# j' T* m5 U: K/ j  s6 o
  157. {                        6 g* B, s9 M4 N+ N
  158.     u8 t;   
    . e0 ]% _; @8 {# O0 E
  159.     SDA_OUT();      ' r: i8 o+ u$ W2 V
  160.     IIC_SCL=0;//拉低时钟开始数据传输
    9 n7 [* S) ^$ t) ~0 t# |
  161.     for(t=0;t<8;t++)
    - B1 N2 R6 x5 w- h6 n+ Y
  162.     {              
    + ]$ U' V/ x+ q% }6 \+ y1 Y0 a
  163.         if((txd&0x80)>0) //0x80  1000 0000
    % h" @1 y! [" J" z% o  Q
  164.             IIC_SDA=1;- W% C' j* `6 ]8 o4 U
  165.         else
    % ^2 d7 W5 f5 Z) D* f8 B
  166.             IIC_SDA=0;
    1 U2 e- Q$ y/ W) `  W: T
  167.         txd<<=1;    ; L2 A2 E# O; U5 u$ C1 a
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的
    / O9 H" _2 B; N" ?) R
  169.         IIC_SCL=1;
    , D9 j& y, J) @5 A
  170.         delay_us(2);
    ! x( l  ?, T, R) V
  171.         IIC_SCL=0;
    / r) Q1 H" c; |8 R9 ~: D' J
  172.         delay_us(2);, i; o& I8 V+ D* d+ M7 a; T. q( x
  173.     }  7 q6 u7 Q* c1 I5 U. C2 g
  174. }
    2 `/ S, \* W% v

  175. 1 M& J& j/ {! b( @( J) g7 W
  176. /*******************************************************************************1 G8 x0 D# H+ Y# ?& Q
  177. * 函 数 名         : IIC_Read_Byte
    & P3 L% i/ V) c/ {
  178. * 函数功能     : IIC读一个字节
    2 V7 P( }7 t$ G& ]
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK
    8 N4 Z( u) x$ r  e2 \& S1 A0 M
  180. * 输    出         : 应答或非应答
    9 I. x- l0 I' o2 ^/ f$ ?
  181. *******************************************************************************/  
    2 d  D, O# [% \: D" E* B+ T2 U
  182. u8 IIC_Read_Byte(u8 ack)
    5 m5 C+ I: U5 J3 o( |2 J9 W
  183. {; G- n- ^  z! M; x: Y2 z
  184.     u8 i,receive=0;
    ; ?5 W% e4 S8 v) Q- \
  185.     SDA_IN();//SDA设置为输入
    6 g7 z) @9 G! t: _
  186.     for(i=0;i<8;i++ )
    " F, G+ y3 g* G7 j/ k! t
  187.     {6 R) i" Y  \8 q5 a# k4 k
  188.         IIC_SCL=0;
    ' E# ^5 I9 S1 |0 n/ W% J7 O
  189.         delay_us(2);
    ; `3 L% @6 G4 v  y9 G3 W
  190.         IIC_SCL=1;
    2 W& h' M, S, U
  191.         receive<<=1;
    1 q6 T9 n: [0 K; w, v
  192.         if(READ_SDA)receive++;   9 W  ?  R. R. e9 A# `
  193.         delay_us(1); 8 j. J' b# V6 W7 j# D
  194.     }      
    & X. z' P/ V* L# W& [" l, G
  195.     if (!ack)
    3 N, M: ?% |, _
  196.         IIC_NAck();//发送nACK
    " J4 _/ [: @, o6 t0 |  \
  197.     else
    . [6 M! \- ~. w* W! M
  198.         IIC_Ack(); //发送ACK   1 ]5 l0 I5 a2 O* s/ [7 }: R
  199.     return receive;; S* d  v; b. s. T
  200. }# p6 G0 ?( ^- g' V3 ^
  201. /*******************************************************************************
    ' H* `9 k' c9 [& N* u1 B( @- k% b  k
  202. * 函 数 名         : AT24CXX_Init
    / l, ~  J) @, H$ v
  203. * 函数功能     : AT24CXX初始化2 e) ~+ b7 B: Z" t! P
  204. * 输    入         : 无& x/ |& |9 `7 P( M
  205. * 输    出         : 无
    2 v0 w% s1 q3 j
  206. *******************************************************************************/
    ' n) q) f; e  e7 A& p
  207. void AT24CXX_Init(void)
    ) Y* h: p6 p* ~) |* y1 ^
  208. {
    9 L. M7 W# D  u3 v" ^
  209.     IIC_Init();//IIC初始化3 p- a& s+ G+ P8 u1 j
  210. }' F! E% l6 V" \2 m& s1 f! K

  211. 9 M0 `. J3 o; `( ?# I, @  I& P
  212. /*******************************************************************************- }- S! J9 G' K, b7 V
  213. * 函 数 名         : AT24CXX_ReadOneByte1 T* h7 ?1 b8 d/ J# @4 _/ v
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据
    # Q7 s- h+ M8 ^9 o" N, l% _7 b
  215. * 输    入         : ReadAddr:开始读数的地址 7 ?- F, l0 B' Q; }
  216. * 输    出         : 读到的数据7 Z9 w+ I& B! J
  217. *******************************************************************************/
    ; u, d) @  B* _/ c2 T, v: F# W
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr)& S. Q* s9 J! P2 z4 S% ^
  219. {      / X, w8 g1 ~/ r8 A% G
  220.     u8 temp=0;                          
    " E! R1 G/ m4 s' k" L
  221.     IIC_Start();  : g; O) f3 S2 S8 R  H
  222.     if(EE_TYPE>AT24C16). C1 K% j: u( A+ ]( ?
  223.     {; k, f% B6 h. X$ h# T
  224.         IIC_Send_Byte(0XA0);    //发送写命令. {- [; M; E# S2 _5 E9 h' `* D
  225.         IIC_Wait_Ack();# k) P6 D3 Z5 f
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     1 l7 u4 X; H# X7 J' s  |
  227.     }7 |" G6 n5 \2 r2 R: V: j* W/ A  A, _
  228.     else
    % `! L$ Y1 a5 V) I4 u% Y4 M
  229.     {
    ; U. x1 I) {0 [3 U$ Y0 m
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据; [! z" `' q/ q6 r
  231.     }     8 w& f8 B% e9 x
  232.     IIC_Wait_Ack(); - \+ C: Y8 k# \+ R
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址
    8 E( s0 U- X) O8 z
  234.     IIC_Wait_Ack();     
    ( i$ K% T# K9 q, H$ s1 z3 ?
  235.     IIC_Start();        
    ; J9 r+ ?* T# _& r7 O- G
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      
    / m. e; c2 H- y" `# @3 q/ p7 ~6 [
  237.     IIC_Wait_Ack();  
    ' K( j# B3 ?7 `5 Z! F
  238.     temp=IIC_Read_Byte(0);     
    5 K1 I! m* Q4 R2 L1 Y4 A- K0 C
  239.     IIC_Stop();//产生一个停止条件     7 T% A  @/ c0 j
  240.     return temp;
    8 f$ H, W0 d- Q' q$ z# y
  241. }
    ) w' N6 v2 w# H9 C! v  z* t

  242. # C; `" e$ I) C& ^
  243. /*******************************************************************************
    & A! Z4 E4 M' i
  244. * 函 数 名         : AT24CXX_WriteOneByte
    / z' L5 b7 Z2 c( C# G% y2 O
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据3 C: ^: {! ]  H/ k& {
  246. * 输    入         : WriteAddr  :写入数据的目的地址 2 [; i- E/ H6 w# s  P
  247.                      DataToWrite:要写入的数据$ L1 B$ L! ?5 {. i$ Q& M+ l
  248. * 输    出         : 无: a6 }. K3 K& d4 L
  249. *******************************************************************************/, d- o# b# P5 n, B1 c/ y
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    / }& \& n8 e$ [3 o  l4 t$ U
  251. {                                & A$ u; u* q6 K% ?) l" f: R% Y
  252.     IIC_Start();  
    2 e, q( z7 E. w% A7 V. Z- D9 @7 @  r
  253.     if(EE_TYPE>AT24C16)( x: V; \- x% _0 y
  254.     {$ B! E& ^% f5 B: p; d
  255.         IIC_Send_Byte(0XA0);     //发送写命令  g' J; F) m" R: g$ n) [
  256.         IIC_Wait_Ack();. {* b# L5 H9 G2 v
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   $ |* u* f6 \1 i  |# E8 l3 c* m
  258.     }" i; P, h) `$ H; j& X( u4 A
  259.     else
    1 P: V' ~* c# S; ]4 q) v; M; f
  260.     {# s# b5 N/ J, p4 U2 A4 h6 j* c
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
    , I& p6 o" p4 }$ H
  262.     }   1 D+ f; \. }% O! Y: z- X; h" d
  263.     IIC_Wait_Ack();    ; ~. G3 L+ b3 L; I5 Q0 W
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址
    & g1 Z5 R  i* w
  265.     IIC_Wait_Ack();                    ) `  h. W  @% ^$ y- G1 x/ p' q- Z
  266.     IIC_Send_Byte(DataToWrite);     //发送字节          5 G0 K% h, i. U+ ]1 w/ k9 k1 R' A
  267.     IIC_Wait_Ack();            9 Y' z9 [9 n5 p7 l( R
  268.     IIC_Stop();//产生一个停止条件
    0 F& k1 W3 \; v+ o9 M8 X. z+ t
  269.     delay_ms(10);  6 S4 L0 p2 ^1 J3 h2 O# O4 w
  270. }
    ! T! K# T7 c0 j! x" y7 f; v

  271. 8 E( P; L* B1 _+ u" `. U
  272. /*******************************************************************************
    ) t! t$ ~8 y& K5 v
  273. * 函 数 名         : AT24CXX_WriteLenByte: V- C$ l8 Y# u* o
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据
    8 h7 W7 `  g; \1 g
  275.                      用于写入16bit或者32bit的数据. }( a: c* N0 h! K$ P5 d+ H: K7 j9 E
  276. * 输    入         : WriteAddr  :写入数据的目的地址
    8 a! W# @- H2 l- n7 x. u( ?2 e/ Y
  277.                      DataToWrite:要写入的数据+ h5 o, r# B3 U
  278.                      Len        :要写入数据的长度2,4
    8 K+ T) r4 N+ @+ u5 X9 L
  279. * 输    出         : 无8 C2 e1 E- w5 E) V- X
  280. *******************************************************************************/
    , E! t. y7 _1 ?& }) G3 b
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)$ H) g" F6 W8 I( O( L
  282. {   
    1 t! g4 u! c: h* `7 Q! L
  283.     u8 t;
    ( L; Y2 K' i) C) ?
  284.     for(t=0;t<Len;t++), j' O* e8 _0 D. C
  285.     {
    , I8 {- R; O! }: q% v/ g
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);; M, _: M3 L  }& F: D
  287.     }                . M3 X1 v' t$ ?$ g" g
  288. }5 z; @2 j" ]# p* O, Y8 K/ k9 l

  289. * `. x1 X$ Q4 R( U7 W7 `' Q
  290. /*******************************************************************************3 c( P3 X' r: H8 \6 r" J, ~
  291. * 函 数 名         : AT24CXX_ReadLenByte1 o  [# H) R; \& _
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据
      C3 f) n8 B- a
  293.                      用于读出16bit或者32bit的数据3 F+ f% f7 i5 O! R0 x
  294. * 输    入         : ReadAddr   :开始读出的地址 + l+ V7 ?7 r% [% O
  295.                      Len        :要读出数据的长度2,4
    ' N. I% c: h! C$ J, J8 M  \' V
  296. * 输    出         : 读取的数据
    ) ^2 {0 E  i1 }  Q+ A% |  n3 ?
  297. *******************************************************************************/
    5 G+ }0 j5 \& G/ l
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
    % N( I+ G6 d5 ]  k, R6 K
  299. {   
    , u+ d% ~) c5 f) @
  300.     u8 t;0 B0 t: e! R( r9 ]2 h8 G& a, t6 R: x  k
  301.     u32 temp=0;7 B  f5 C$ A( T: G6 K
  302.     for(t=0;t<Len;t++)
    ; T' n, s  w5 B8 H6 r9 B$ Z4 E
  303.     {* T/ ?- Q, K+ e4 M
  304.         temp<<=8;
    6 B- R/ B. p% r* \& R' d! n
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);         
    , x3 M" g3 L/ ~* b
  306.     }: u# O7 T' B! ]- }
  307.     return temp;               
    1 ?8 [. ~: `" C5 ~9 z  g! _
  308. }" h5 r7 j. O/ R- E5 }' Y( q
  309. ' o& A/ [$ j' w# M7 [7 P
  310. /*******************************************************************************- ?. C& ]; w  c, e
  311. * 函 数 名         : AT24CXX_Check. n9 J6 [( E, F" u' t) C
  312. * 函数功能     : 检查AT24CXX是否正常- M$ H# B* P# N+ l% N
  313. * 输    入         : 无
    1 r# _: N) x, T# t
  314. * 输    出         : 1:检测失败,0:检测成功
    6 p: g8 B+ g* |2 o
  315. *******************************************************************************/
    " n1 r( \) a, {
  316. u8 AT24CXX_Check(void)  E% O5 p/ H% o4 g9 W
  317. {. T" ^! Y/ h0 w2 \" @! B9 C
  318.     u8 temp;
    . N) [, q+ _) F6 A6 X; x
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      % o; K. U! |, G0 A' D: V
  320.     if(temp==0x36)return 0;     
    ' p! y9 n! Y( j! g: i
  321.     else//排除第一次初始化的情况/ R' Q: R& k& |6 a- n7 H
  322.     {
    - y5 u; w) Z4 G& a7 V
  323.         AT24CXX_WriteOneByte(255,0X36);8 U8 E3 b" r6 Y
  324.         temp=AT24CXX_ReadOneByte(255);   
    $ L- M% e4 ~( @
  325.         if(temp==0X36)return 0;% o# e2 g) e7 G  T  l% g8 d
  326.     }
    & K- Q$ D* ?8 C2 z* j0 _/ j
  327.     return 1;             ! [# K4 g# t' ]6 s! p
  328. }& f$ R# Y9 ~+ V9 b4 L: |, x7 H

  329. " `- T! ^. R# P5 D
  330. /*******************************************************************************( k* L/ h' w+ \) R# V1 t9 d
  331. * 函 数 名         : AT24CXX_Read
    4 l+ r+ `6 W) w) c; O, F
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据3 ~/ u/ _' o6 |% V+ `  ~
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255
    * l( n5 r+ {* _' t# k
  334.                      pBuffer  :数据数组首地址* j' B" M3 A; x
  335.                      NumToRead:要读出数据的个数
    3 G* q) r+ o& _3 C& e
  336. * 输    出         : 无
    1 r6 ]5 U8 E6 l2 b
  337. *******************************************************************************// s$ I/ Z9 I( Z) f" ^& I/ m
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead): Z( n7 K) x7 w* J
  339. {
    : o. s" d- T* E' g, A8 b) e8 J
  340.     while(NumToRead)7 p9 M" u" `* @( l1 w. J2 t
  341.     {
    . L9 k% ?; ^% `- S& S* S1 ^. d
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); & E' |7 G0 p( J1 y
  343.         NumToRead--;
    + t& f: `, X) ?- _
  344.     }& X" V: H9 s/ u0 A" |* O5 T
  345. } 1 w9 P) @( Y5 j+ Z

  346. 2 y6 _$ y, `( Y0 Q
  347. /*******************************************************************************2 J# C% b* G8 ]$ f  I7 \
  348. * 函 数 名         : AT24CXX_Write
    9 q$ d. [( N7 Y! O1 M; l
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据# S# A3 t! T3 p" @
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~255
    , p9 ]: s( p1 Y! C9 z$ X  J
  351.                      pBuffer  :数据数组首地址+ P: g  v3 f4 G& `) g
  352.                      NumToRead:要读出数据的个数
    3 S" O" a$ ?1 `% E) j7 ~1 y8 e; {
  353. * 输    出         : 无
    3 v  y# Y. t# J: z/ ?& g
  354. *******************************************************************************/9 X$ C; d& T9 }" \" u! g6 y2 d
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
    ! V% Z5 x- c  Q! z1 A2 {
  356. {
    * s, ]7 z, u# _) l/ `
  357.     while(NumToWrite--)
    3 L( h# A0 V6 r& E7 j1 W
  358.     {0 e4 ^! N( q& @3 F" t# G' p. \, h
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);' A3 S. u5 o, {3 }' {
  360.         WriteAddr++;# @+ a# H2 t: b/ D
  361.         pBuffer++;- f/ {/ r* d& P8 y) I
  362.     }
    " _0 m- _/ M' c
  363. }) x) J2 L. e- V! S% u% M3 Y
  364. .h文件如下) A' g  u  T# {; J/ S: T6 j2 Z

  365. ! a# o6 z- A) N* i0 q# H6 e
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C02. V( w0 ~6 f% ~  Q/ G7 b
  367. // 可修改成AT24CXX系列中的任意一个' Y& T; V- U1 V) s" t  B
  368. #define EE_TYPE   AT24C029 k+ M$ q: J7 ~
  369. + q! d7 w) A- ]" P
  370. // IIC函数
    ( I! A6 j* G1 r& z
  371. void IIC_Init(void);   // 初始化IIC的IO口     1 T% Q( a2 M6 r, ^* h5 _% [
  372. void IIC_Start(void);   // 发送IIC开始信号
    $ x1 A. a5 B" b. C( T, W% F) u  R
  373. void IIC_Stop(void);   // 发送IIC停止信号
    , ^8 l5 m3 B) |5 K
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节
    & w  d7 K7 X0 h$ ^, [& F
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节
    8 ^, }/ H; x0 `! S
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号
    : D& q- U1 m3 g: @( z% [: i6 F' Q
  377. void IIC_Ack(void);   // IIC发送ACK信号
    4 ?! M! q# P' I0 Y+ R2 Z& C* {
  378. void IIC_NAck(void);   // IIC不发送ACK信号9 w. G/ g; K* t+ ^% Z' Q0 `
  379. # d9 ^1 Q  |, u) w9 r( C
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节$ z. F+ y  }. T3 m1 |! ?8 Y( a) k
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节
    ( N* S9 B3 e2 k% {
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据$ [! w9 h: L! P, \
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据% m, `5 O2 f' U2 Y$ y
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据
    , N/ w$ _# |. h/ U4 @
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据* L9 c& B: f' {* F" M  m8 `
  386. 4 a: a5 y* b4 C; _
  387. u8 AT24CXX_Check(void);   // 检查器件
    $ I. o+ A6 k6 R" o
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码
$ ^" G- f' q- c: ]- J7 a" x
六、应用实例
1 @8 U+ p' ~) m/ f给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下
+ ]' u1 B7 D4 |2 S' g8 b
  1.     AT24CXX_Init();   // AT24C02初始化( K6 U: g. q4 u# X% t. }6 ]1 s, ]
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常% C. c. r  i' g% I  S. s, |! B
  3.     {
    & B& d0 f: H) h$ r5 U' V3 c8 k
  4.         printf("AT24C02检测不正常!\r\n");. {% E. g5 b5 P' x8 D% r5 ?9 i" ]
  5.         delay_ms(500);
    9 m2 H9 D! a9 W6 D* g3 s
  6.     }
    1 {* h8 F. k7 A3 L0 p/ C( }) }
  7.     printf("AT24C02检测正常!\r\n");
复制代码

+ u8 z9 w1 d! g8 g8 E  K( {" rmain函数如下: N' O8 Z- a7 @! @, l4 E" m  J  }' z
  1. u8 gWData = 0xaa;   // 准备要写入的数据* ~6 c1 U: y6 |! p% {' ^
  2. u8 gRData = 0xaa;   // 存储读出的数据$ Y, p3 j- L! y4 c( @0 G/ F# w
  3. # ?8 ^' c$ \! _- K  P9 Y6 \! `
  4. int main(void)
    # v' ~8 D6 l, \& A; I
  5. {
    $ Q2 G! X; V9 |. y) w5 T
  6.     Med_Mcu_Iint();   // 系统初始化3 c" k% n' r. f5 w" a+ W
  7.     8 ~/ Y4 p& y; f4 }% I( E
  8.     AT24CXX_WriteOneByte(0,gWData);$ C" W( C. ^1 X3 z: `5 x: A5 E
  9.     printf("写入的数据是:%d\r\n",gWData);) }" S! a) b6 o! E
  10.     " M8 q, M4 \2 d. r8 f0 v8 a
  11.     gRData = AT24CXX_ReadOneByte(0);5 R/ P; M2 j- n1 j0 {
  12.     printf("读取的数据是:%d\r\n",gRData);
    - |5 ]0 c) {* V; `+ D8 X# _
  13.    
      L2 ?6 v" n: |- z( ^
  14.     while(1)1 X: P- c$ u6 p, ~8 C, F
  15.   {
    - Y: T3 |1 M/ s5 B) Y8 y
  16.     }: h/ I- }/ w' u& h, [9 C9 T
  17. }
复制代码

. c% f, x8 u* y2 \+ _3 o4 @: \串口打印结果如下
' j$ J; Z, w* R' o# L8 x; a+ H% }$ l$ P

: L+ L' i6 x! O) M. V4 N
串口打印结果
( @( e3 e2 I+ q' D' l$ p
8 @; b7 Z) Z  @/ J

0 X, Y- l; S; J: A8 ^
七、拓展应用
$ [( q1 k9 o/ K, P' vAT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。) C' i/ ]5 F+ |& R. S

! F: n4 M7 Q1 t  E8 M( r( V/ e% `6 X6 H( Q7 L9 e
! K0 ]6 E  g. q( s" p8 j1 G% H
转载自: 二土电子4 q" K# k6 S8 O) Q$ h% s/ f
如有侵权请联系删除
/ e4 h7 \/ _' H
! ]* S- L) y- p6 F% v& }& y2 X* T
微信图片_20231023203400.png
收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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