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

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

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介
; Q$ _0 G8 Z: V' r4 x! }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篇。
/ l# j# q' L4 r$ `0 A9 F+ G" `9 i! ~- v9 w' Q0 Z4 z

7 c/ c: Q) R- p& l' O二、AT24C02引脚
) A! J$ C! r. F. x( j
" g* c* _: J& l1 o& Y. @7 x( U

0 H6 Q) Q* ]# I: W; i* P, _
微信图片_20231023203334.png
( ^8 R" f+ F3 R. h2 _
AT24C02引脚定义
" r8 v- T! M$ q7 A: _8 O
1 l6 c, o% ?0 ~( x; O# _
+ U; m: k' m9 Y+ F: C6 s
三、AT24C02寻址

: Z- l# S" Z# p6 @3 Y0 _- F& _使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。7 \: D" i0 [/ c% f& J0 L* K
& h, x% a& a  F- c2 i- [8 r
微信图片_20231023203357.png

% }3 S) @1 T7 V( d* }  N- o9 l/ Z
AT24C02地址信息

" p8 N: s+ j5 T5 E

2 m$ s  ~. \2 Q. l4 J

+ e; U( t; e+ o器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。
4 g, e4 E* X4 t$ a5 L4 o$ R9 t$ F+ I# Z
四、AT24C02读/写操作
$ H: w# P/ \2 U" w$ ^4.1 AT24C02写操作

; y3 e7 N  `, u' x- P2 y! z4 ^写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下+ G0 t3 c/ B) v, S3 l6 T
4 D# u6 X1 I3 R
0 d1 T4 |( K& g2 G9 }1 \
微信图片_20231023203352.png
  Z- Z  W, _8 F. O+ |- p
写操作时序图
7 f9 b- b# W8 C

+ _7 J" I/ ~* g! g1 z  f  r: D
% ?, N$ G: W% b+ s
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。$ j- \1 }4 s4 R$ f* V

3 y5 Z4 l) k) K1 y) T  K, \3 u) q接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。
, q8 a0 E- Z/ R4 a$ o- {; ~
+ I+ c4 O( L2 u0 A7 G$ N; |; e
4 h! g0 C+ }# Y- B( L
4.2 AT24C02读操作
) P$ }/ V+ ]; y- d6 y+ s& D
AT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。
5 Q" w! O; I/ k# k+ |+ ^, W6 v• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下2 `1 j. {( O' S/ n
' ~! l! [! J1 k  ^

, g. m) l+ F1 ]1 j8 {/ `6 s) [
微信图片_20231023203350.png

$ v1 q, B  m$ b' R) D7 U) d" c/ r( t
读当前地址时序图

  J8 j6 f5 H9 s7 x$ f& ~8 r+ t
) B1 F- L3 v/ b- y) h

$ a# H0 \, F+ ~- s
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下  {3 E! J$ [6 n2 M- U# G. p

4 A; a8 z$ H# Y) F5 Y

3 E9 u+ g+ I1 x$ G/ g
微信图片_20231023203347.png

0 ~2 X! U4 W' u/ T- k: l/ f. q' j
随机读时序图
7 y0 \$ d# z! L

& r; G$ ~3 P3 E' P' a! _) P
3 R2 h  U1 G' {3 i' B
* J' g- p' K, ^, S
• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下
( D2 c6 Y3 F- D$ s0 W( D$ C' X5 J! U; N6 A; w1 w$ X- K0 }
5 R& f; Y( S4 s* L
微信图片_20231023203342.png

5 x7 b* I8 ~  q2 {9 S: v
顺序读时序图
' l/ O9 o$ C1 _: s$ j! U4 M
. Z+ ]# E: ]$ B& b" i
+ k8 @5 n, u# y/ i7 n* @8 t
五、AT24C02程序$ M1 M0 j, P3 H3 S1 Z
这里给出一个AT24C02的程序,仅供参考
9 O) w2 R$ C% I+ g
  1. /*******************************************************************************
    ) |. M/ M, z7 V2 m* z( d$ k
  2. * 函 数 名         : IIC_Init
    : Z- u/ K, {8 N' E; h9 s
  3. * 函数功能     : IIC初始化/ I+ Q" Y$ q3 |" b9 C% G; A
  4. * 输    入         : 无  Q$ M3 P4 O# D6 B# s9 j
  5. * 输    出         : 无+ M3 c$ k  Y4 T$ g4 Z. x
  6. *******************************************************************************/
    . e. `4 u. J6 A* m
  7. void IIC_Init(void)
    5 Z/ h7 B, r  v: Z
  8. {
    ! T& M# Y4 j9 ?$ a  s/ P
  9.     GPIO_InitTypeDef  GPIO_InitStructure;7 c( k' ?4 R$ `6 m
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
    8 d9 e' T4 E, K8 d% d. H% g: Y6 Q
  11.     ( O6 r! N% X( P- u
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;5 Z5 `) n- a  N3 ]2 H( G3 Y
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;& ]6 z  Q9 E, J& B: s  W( m: j
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    / q. ~! e- v8 z1 P
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
    ( P4 g5 V/ `; `  F- V
  16.    
    ) I6 v. P! Y) c' I( r
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;: J' m' [4 I8 q$ o! ~4 J
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);& s, r/ Y/ Z' `. N
  19.    
    , n; D* d( ]9 O7 P  N7 [1 }
  20.     IIC_SCL=1;' |! B8 n# [. g  J/ S6 d
  21.     IIC_SDA=1; 0 R: c$ t& k, r: N# l6 X
  22. }0 J" P+ y% D* A6 E  x
  23. /*******************************************************************************
    & S9 L* r1 Q% z, ]& k, J* t
  24. * 函 数 名         : SDA_OUT4 T% I  Z3 y( U4 q1 q1 C/ V9 B0 v
  25. * 函数功能     : SDA输出配置   
    * O$ ?) _, _" x$ \* a7 n
  26. * 输    入         : 无& \3 C6 o8 `. l
  27. * 输    出         : 无
    ! F3 d* R6 X) J
  28. *******************************************************************************/
      d" v  @& t! \6 s: U0 p
  29. void SDA_OUT(void)
    # K0 q6 u5 I1 M& S8 y; \+ M! w0 n8 l  G
  30. {" Y- s! U5 N, D/ k5 U. I
  31.     GPIO_InitTypeDef  GPIO_InitStructure;6 m* C5 J' ?5 ~- o5 z  W
  32.    
    % d, D: }2 Y/ d% d" h. O2 F
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    % p% Q& _; v4 [2 ?9 n2 r
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;) {' O# V% i8 m3 r4 n8 Z6 I0 x
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;' L5 }0 R3 l5 Y
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    ; t+ q/ N$ {9 D! C3 c$ V0 {6 g
  37. }
    ( \4 B8 X+ Y+ ^  f

  38. / l; J" e- |  s% C7 G
  39. /*******************************************************************************# j7 V" ^: t; ?- S: |
  40. * 函 数 名         : SDA_IN
    : B0 N( X  K( D' l5 v
  41. * 函数功能     : SDA输入配置    5 R0 P* T- b1 K; K8 |( I$ W
  42. * 输    入         : 无: G* ]/ v5 V$ \, D
  43. * 输    出         : 无. R% ^( D/ Y2 F4 O9 e& w5 j
  44. *******************************************************************************/5 p7 w4 s. v, _1 O0 S
  45. void SDA_IN(void)
    ' u. N: M8 A5 Y+ N/ p$ a+ l
  46. {9 ^. {1 |# v4 A# n; i# o
  47.     GPIO_InitTypeDef  GPIO_InitStructure;& P3 M! Y# X' ]  k8 I! ~
  48.    
    4 z& T1 M3 r' q4 A
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;* ~: |; U, R, E
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
    * J1 S: r/ x5 `$ R+ f! }. [" D
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);- q3 P+ E5 L1 i/ v
  52. }
    , W" o7 n  r6 b6 ~7 x1 T1 P

  53. 2 `7 U8 R/ |; ~% R% Q! ~
  54. /*******************************************************************************9 ]" L& l# D$ J9 a9 P* F6 r
  55. * 函 数 名         : IIC_Start5 F/ j8 W5 J, P( V7 j
  56. * 函数功能     : 产生IIC起始信号   
    - z* F; g+ ?7 {  a3 s% X4 H% n& L- S
  57. * 输    入         : 无
    ' V" x$ N$ _8 L8 S
  58. * 输    出         : 无3 q- x, M7 k8 O, |6 A/ G. j
  59. *******************************************************************************/% r* u+ \' @" p: F7 O
  60. void IIC_Start(void)$ |" \$ o/ N9 \  |( e7 J3 g1 N
  61. {
    9 ]2 p+ D$ {0 }: W! M  h
  62.     SDA_OUT();     //sda线输出" x- \9 M! M+ e9 Q% H
  63.     IIC_SDA=1;      
    / H* _" U: n) B, Q! ]7 r
  64.     IIC_SCL=1;
    7 T7 w, R5 m3 M( Q2 ?, \
  65.     delay_us(5);* w# V: s8 T* Q
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low - ^& N6 [3 B6 d8 x2 B
  67.     delay_us(6);
    5 @5 T4 S' D9 G8 l1 G+ f. }9 n$ e8 J
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
    4 X! h- x* \" s! D
  69. } 9 ]; A1 j# ~* N8 n9 O% m
  70. - P% L) {" H" ^% [" P' K' ]
  71. /*******************************************************************************
    ! C" x9 Y$ p2 g* {
  72. * 函 数 名         : IIC_Stop  N3 N6 Y4 ]/ x$ E
  73. * 函数功能     : 产生IIC停止信号   
    ( |* {& Z$ g$ X, L9 N6 P
  74. * 输    入         : 无
    # O; D1 d$ }( }% S3 x
  75. * 输    出         : 无
    7 v/ ]. N: D) b/ {+ w- E: p; k" u
  76. *******************************************************************************/: m( ^6 Q, X3 f, [1 P6 I/ ~
  77. void IIC_Stop(void)
    & b( W4 {! N! T
  78. {
    ( J! Q% z5 V2 m) _% s! k
  79.     SDA_OUT();//sda线输出
    + @: J/ m7 R- C$ E9 u
  80.     IIC_SCL=0;
    5 L- G: A8 s. T; T
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
    & {8 t, g- m' h& S4 a# S4 t
  82.      IIC_SCL=1; , z  {- d0 W% @' x+ |% J) k0 C1 b
  83.     delay_us(6); 0 L0 X: c1 V5 F8 x
  84.     IIC_SDA=1;//发送I2C总线结束信号
    . u, C6 P" z* t; ~6 o9 q
  85.     delay_us(6);           ; R9 D/ |8 o; X6 ?3 [
  86. }
    1 K  t0 _. s8 D, D1 K3 m3 Q
  87. 4 ?. O7 m# E7 f- [; L7 |5 N
  88. /*******************************************************************************
    * }0 s6 [2 n; t
  89. * 函 数 名         : IIC_Wait_Ack
    # ]0 O0 V& S5 u- z2 q
  90. * 函数功能     : 等待应答信号到来   
    + \/ k7 n& }: V0 s' w- z
  91. * 输    入         : 无
    3 m; K9 L. l5 [; B
  92. * 输    出         : 1,接收应答失败0 @- ^0 i  {4 a) J& ^, o" z: R1 q
  93.                      0,接收应答成功% T5 C2 Y) ]( }* F- {0 s' ]4 V
  94. *******************************************************************************/
    , i; x2 ]1 ]5 a" v, O
  95. u8 IIC_Wait_Ack(void)
    1 L4 x1 H' ?7 L+ g
  96. {4 Z) j& H% M& }0 ]
  97.     u8 tempTime=0;
    , o8 L4 Z) F- C6 g# x
  98.     SDA_IN();      //SDA设置为输入  
    1 h3 Z- \- B4 h1 w8 l, O/ }
  99.     IIC_SDA=1;5 h) G* d9 ?* B& G1 M. j3 a$ U; \) m
  100.     delay_us(1);   
    4 p/ I  U0 b1 j, ]% P5 V* }
  101.     IIC_SCL=1;5 I0 h: g# G' W4 q( I1 H2 B3 m
  102.     delay_us(1);  
    # u1 K; F) f+ V
  103.     while(READ_SDA)8 e, q, k$ B, j3 V; J2 H. X
  104.     {0 w3 p$ X" ~* Y& v
  105.         tempTime++;% `1 R) C$ ^# ]6 d0 z1 v
  106.         if(tempTime>250)2 j) C% Q$ y* ]8 o! N, J* g. R
  107.         {" ?/ N  C0 E3 b1 r$ o, o
  108.             IIC_Stop();
    8 b5 J' g4 ^3 n9 ?
  109.             return 1;
    5 o) p6 U. f! C- a: ^: J
  110.         }
    7 t) f5 M: B0 K- z9 t/ Y
  111.     }
    * x& e+ L6 I& l! }- U' o* k6 t
  112.     IIC_SCL=0;//时钟输出0     
    ( g" N2 ~2 M* M; n
  113.     return 0;  , B( S0 |) ~/ e2 `$ \
  114. }
    , J# E6 B5 \! x$ |0 _
  115. 2 E& Z8 Z# \9 G
  116. /*******************************************************************************  T* ^3 P! ?4 w% ^8 a7 ?7 a1 b+ z  V
  117. * 函 数 名         : IIC_Ack
    % ^' z1 x; D" o' c, i: t
  118. * 函数功能     : 产生ACK应答  9 j7 h9 m* \3 `, ]6 _; |1 T- w
  119. * 输    入         : 无; ]% L0 U. q- s: ^3 f
  120. * 输    出         : 无" {; j5 @' R2 Z  t
  121. *******************************************************************************/
    6 E9 v5 n2 ^* v3 x+ Y7 u9 w: q
  122. void IIC_Ack(void)
      Y% E4 z. \% i/ {
  123. {
    / e- a8 F! N7 y/ J1 ]5 a
  124.     IIC_SCL=0;
    9 i% |3 s! D) G" G4 y6 u6 L
  125.     SDA_OUT();
    2 |) Y! u8 o5 R: H3 _* O6 v0 U
  126.     IIC_SDA=0;0 @/ e% R  Y1 R
  127.     delay_us(2);* p' k1 \- w! ~4 n, ^
  128.     IIC_SCL=1;, G# U& c' w0 g
  129.     delay_us(5);
    ) g% I2 b& o4 ^7 L
  130.     IIC_SCL=0;2 N# r8 [. l$ b$ o
  131. }
    0 [0 j* y+ ^- H/ t  ^2 J
  132. : R  V& }9 T7 p( W/ l! i
  133. /*******************************************************************************
    3 f. t" v; P; R- s2 E4 q0 S
  134. * 函 数 名         : IIC_NAck
    9 X- q! H" j) [9 }9 l& S5 ^* P
  135. * 函数功能     : 产生NACK非应答  
    ( @! [6 K1 u% D0 _# y0 _& h7 S
  136. * 输    入         : 无0 i* j- k3 O- M& ]* w, Y' k
  137. * 输    出         : 无
    ! R3 C. `0 V  s2 m
  138. *******************************************************************************/      
    " e0 `& t6 B2 Y5 I% V
  139. void IIC_NAck(void)+ ~9 Q; |4 D, y" h* }. }9 G
  140. {
    * Y5 Z4 K; w9 w$ `. v/ q
  141.     IIC_SCL=0;
    ; ?' W- ^) S6 I7 S( j
  142.     SDA_OUT();7 g; \3 D& i/ o1 L
  143.     IIC_SDA=1;) j3 H/ C* Q  L+ W6 Z
  144.     delay_us(2);# w+ v' m( [" C! z; `: n
  145.     IIC_SCL=1;
    ' ^. e; P% m: v$ }/ I' K8 o
  146.     delay_us(5);! h/ g" X0 j+ v1 i5 j1 B
  147.     IIC_SCL=0;  e% Q' ~/ a) k& J# s
  148. }
      N7 r& u& k' D4 A6 s! U
  149. 3 Z6 p2 Q4 a8 _* P* a" r
  150. /*******************************************************************************) T+ j. q: ]. `; x) \3 {( R3 b
  151. * 函 数 名         : IIC_Send_Byte( g$ f& X3 @! N) k4 F: U
  152. * 函数功能     : IIC发送一个字节 / }- l$ L$ [6 t
  153. * 输    入         : txd:发送一个字节/ R9 P1 u3 z: d# K& K% H* _- ^% ?
  154. * 输    出         : 无/ O8 N* p, a/ n
  155. *******************************************************************************/   
    2 u* X# D, i' U& E  n5 l/ G3 [
  156. void IIC_Send_Byte(u8 txd)& o  @8 k8 A6 c# G: ~6 a& K
  157. {                        . N. p  f6 X" m/ ?/ n5 |# _
  158.     u8 t;   
    # Z" |, B: g: k( d0 M4 j% P
  159.     SDA_OUT();      
    3 I' q: Z% X1 K9 Z. V$ O, }  `+ K
  160.     IIC_SCL=0;//拉低时钟开始数据传输% {9 H* }: W! h  Y$ @* Z
  161.     for(t=0;t<8;t++)
    # r! I( q! B0 ~, a
  162.     {              " L8 B( V9 O3 j
  163.         if((txd&0x80)>0) //0x80  1000 0000, G, i( K( a$ a  R& M
  164.             IIC_SDA=1;8 z6 b% x  [! c1 r
  165.         else
      q) p' R/ }) t# [0 ?
  166.             IIC_SDA=0;
    ' D+ n5 A* U6 c' V5 ]( i
  167.         txd<<=1;    ! H4 R4 F$ y1 Y" N8 D
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的  X- ], ?3 Q2 n% ^  B: S( ]
  169.         IIC_SCL=1;
    ! Q. j) G8 H- n  T% J$ b- A, |
  170.         delay_us(2); & @8 u. B$ w* X, o" H
  171.         IIC_SCL=0; 6 U+ j+ B9 f" K: r  U
  172.         delay_us(2);
    + o" {6 t, C6 G% p+ U0 ^
  173.     }  7 Z+ a& M( b& h# Q  v
  174. }
    * s" j7 c# X) Y& G6 _
  175. 0 h7 M( L2 c5 O/ Y3 _
  176. /*******************************************************************************
    ! `1 c* a4 Y; l6 ^% w8 q7 \4 ~( a
  177. * 函 数 名         : IIC_Read_Byte- S* P2 L( l/ b: }
  178. * 函数功能     : IIC读一个字节
    " f( Q4 f& Z( u3 s
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK 9 x- p* r2 ?, e. M  c- [
  180. * 输    出         : 应答或非应答& s3 n* ~: _- C; u
  181. *******************************************************************************/  
    0 C9 w9 R/ u% z" }" p+ \
  182. u8 IIC_Read_Byte(u8 ack)
    & A- d+ V4 n* F4 @# G) i, l6 m+ E
  183. {
    5 A/ {# z7 c4 S1 t0 Z0 F
  184.     u8 i,receive=0;
    ( C" i; Q8 \6 Z
  185.     SDA_IN();//SDA设置为输入6 d& Z4 O) A- i& G
  186.     for(i=0;i<8;i++ )9 e3 n! r$ b3 v3 \* I' h5 G
  187.     {
    ) V1 R0 W" ^2 v" k
  188.         IIC_SCL=0; 7 ?' C. Q& n0 e7 `
  189.         delay_us(2);) D, r9 n2 J5 g3 Y# e
  190.         IIC_SCL=1;7 ]) z7 R1 u, W; U
  191.         receive<<=1;  ?! s/ D1 W9 E; d1 \" W6 L2 g, ~' ^. T
  192.         if(READ_SDA)receive++;   ( a8 U! b: L2 L( w+ _" @) A0 {
  193.         delay_us(1);
    ' ^( m% l5 |& E2 H/ `0 f
  194.     }      7 J1 B1 a( J) [2 |
  195.     if (!ack)* @+ n- E+ ]/ o/ T' O+ R8 X
  196.         IIC_NAck();//发送nACK
    ; E; b' g. m! b5 I# m, V) W
  197.     else& u9 l' d! _# Q( @: r
  198.         IIC_Ack(); //发送ACK   3 p+ w0 I* z( h' M' ~2 f4 X
  199.     return receive;1 E- B: `  A9 l
  200. }
    . d8 Q7 T  R6 ?' B4 _; W
  201. /*******************************************************************************- x) S# M) l( d* ]
  202. * 函 数 名         : AT24CXX_Init. F/ e8 P( y- B) U0 O
  203. * 函数功能     : AT24CXX初始化
    2 O5 G: W7 l& I0 d* R2 b+ W# [
  204. * 输    入         : 无5 T0 `5 X$ W. U/ o2 l
  205. * 输    出         : 无6 R' L( B# B& ]* `; l4 l3 q
  206. *******************************************************************************/
    7 j6 o$ a5 S# c) U: r6 I# Z
  207. void AT24CXX_Init(void)
    ; n; q; C$ ~$ z. D
  208. {
    3 d+ X# J2 H0 @  Q7 ?; t
  209.     IIC_Init();//IIC初始化
    4 W' R1 ]% l" i) j0 P6 j
  210. }: x  m7 t9 t. B, }, m) q8 T

  211. 1 O! t& c+ ]% a3 @
  212. /*******************************************************************************! b+ U& C6 S+ y# q9 \* z
  213. * 函 数 名         : AT24CXX_ReadOneByte% Y# Z5 r2 A( n' j
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据" g; t5 A9 b2 ~5 r% Y
  215. * 输    入         : ReadAddr:开始读数的地址
      U" U6 K: a/ m3 D# W# }/ J2 }
  216. * 输    出         : 读到的数据
    ( t$ n6 n' @/ X, N4 C% E
  217. *******************************************************************************// Z2 V; I# ]$ r7 q# N0 O( b
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr)
    % E* p% ?  s1 _9 U# M# m6 T- v, V2 U
  219. {      . b6 C4 {  F8 L7 z
  220.     u8 temp=0;                          
    ! ?  S6 w) `$ k3 S! x
  221.     IIC_Start();  ( z. }% ~# Q- h7 d
  222.     if(EE_TYPE>AT24C16)
    8 s; k/ ]" n5 X
  223.     {
    * m. `0 B* R' E/ ?2 h, u
  224.         IIC_Send_Byte(0XA0);    //发送写命令
    0 s' D9 b. m& ?! D% ~; {# s2 z. ^6 e
  225.         IIC_Wait_Ack();
    5 r8 L" W6 I1 I5 }
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     5 X: ?$ S  K6 ~, a0 T" s
  227.     }
    & c% j3 C2 y( E+ A. r3 {
  228.     else
    $ k/ X- `& x' E: o! C" s
  229.     {
    ) c" C9 a8 t- U1 p
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据  Q2 L2 c* G/ L6 T' @. t
  231.     }     & w8 _' n# Q1 o8 P
  232.     IIC_Wait_Ack(); ' p& h* _$ f; k4 h7 l4 ^% J
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址
    / I: C9 Q# ~+ d
  234.     IIC_Wait_Ack();     
    # X2 g; z: f( ]! N
  235.     IIC_Start();        0 g+ @8 t: J+ ~1 S5 S
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      + n3 a9 Z1 Z( R
  237.     IIC_Wait_Ack();  7 }1 N6 B3 W. k3 L1 R
  238.     temp=IIC_Read_Byte(0);     
    " |. r/ w" J. X  i! M; \8 u
  239.     IIC_Stop();//产生一个停止条件     
    2 t( m! X' M3 c
  240.     return temp;
    . S) }7 o1 o, Q
  241. }6 j' }4 b" k5 b( Q

  242. ' k  v& B0 g7 Y% P1 E' W
  243. /*******************************************************************************
    ( |( G: ]! \  @1 i
  244. * 函 数 名         : AT24CXX_WriteOneByte# ~6 @" M! n( @1 F
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据
    8 I8 @$ _; ]9 K# D* r
  246. * 输    入         : WriteAddr  :写入数据的目的地址
    5 [# H" x+ {2 T' G) F% x
  247.                      DataToWrite:要写入的数据7 ^% x- b/ _3 Y3 ]- [: D
  248. * 输    出         : 无
    # e9 g' ?3 u4 ^: O$ y$ }
  249. *******************************************************************************/2 x, U: |4 C& u7 }
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    ' S7 ^' _' P6 S5 {
  251. {                                ; g2 B/ S% ]0 F
  252.     IIC_Start();  
    : G+ Y' V& B* R" `1 h) }! S, c
  253.     if(EE_TYPE>AT24C16)
    ) F2 I% `: `( p, T8 J5 R
  254.     {! H4 X6 l- b- k9 q# \* ^
  255.         IIC_Send_Byte(0XA0);     //发送写命令$ w2 I4 L) ?- L0 T8 x2 f
  256.         IIC_Wait_Ack();
    1 }7 k+ q" c; Z  }; }+ p* ^
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   ; ?# e* r) Y" x0 f
  258.     }* N1 y+ C  p/ O& z+ I" e8 h
  259.     else
    + Y! E0 Q' f; V, M
  260.     {& {. \1 {6 Y7 b+ H
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
    # ?0 b/ a. t. i& G$ z2 u+ q
  262.     }   ( O8 {9 o6 J" a# I/ k! @+ f: R
  263.     IIC_Wait_Ack();   
    9 ?( V  z, A$ m0 Y" t, G
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址1 F! N4 q: Z" K- G$ S
  265.     IIC_Wait_Ack();                    5 g2 A2 f6 }; H; }) i  B
  266.     IIC_Send_Byte(DataToWrite);     //发送字节          2 y9 b$ O6 a1 ~' [
  267.     IIC_Wait_Ack();            
    * v; X6 z- ~' k& P% j/ v
  268.     IIC_Stop();//产生一个停止条件 - D: ^4 K7 F' R- g
  269.     delay_ms(10);  
    2 k5 U* h" ]+ J8 R+ B
  270. }. i: g9 W2 O- g0 ?- b
  271. 6 \. U$ k, T$ c, w: V! x5 R- |  O
  272. /*******************************************************************************3 x( m/ c. m* j
  273. * 函 数 名         : AT24CXX_WriteLenByte
    # L& b- x  [( S7 S: Q. g. E  c; m& D+ s
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据% T: ~9 a: k! Q& c! }, G' }) t& l
  275.                      用于写入16bit或者32bit的数据
    0 l. i) }8 W; w* Y
  276. * 输    入         : WriteAddr  :写入数据的目的地址 2 Z' P- W; ?/ f1 o7 K& u
  277.                      DataToWrite:要写入的数据3 p( R8 s* q0 D4 C' @
  278.                      Len        :要写入数据的长度2,4
    5 r' L# n9 u, @+ Z
  279. * 输    出         : 无9 O5 }+ g/ v9 c- m8 W. N" F
  280. *******************************************************************************/
    * ~, D. x0 T+ F; X7 h- |
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
    $ m0 k* P; u3 T% X
  282. {   
    " Q; `' l7 ?+ g0 p# u
  283.     u8 t;+ X: q9 C. X# {1 F1 o( U9 D' B) ^
  284.     for(t=0;t<Len;t++)! M/ d- G% {  A* s& z- J* s
  285.     {" f( W4 o7 N& Q. r
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);" p1 v/ \* a/ ~$ K& Q$ _
  287.     }                : |( M2 e- D2 {0 ]( \$ m
  288. }
    9 g( T  g. G! a: \2 b# F4 @9 z
  289. + M7 Y8 e! s+ Q2 Z2 ~  V& e
  290. /*******************************************************************************
    + b  k0 A, T; O. j5 q. @$ R7 M) s% R
  291. * 函 数 名         : AT24CXX_ReadLenByte
    - A% B) v, }0 ^% `- V# h+ P. \
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据" x: z9 x, z! o+ L, e, N: I% g# e
  293.                      用于读出16bit或者32bit的数据
    3 B) I$ p1 J6 v3 z: f* v
  294. * 输    入         : ReadAddr   :开始读出的地址 ( M: `( i% V$ B  j, ~; u
  295.                      Len        :要读出数据的长度2,4
    3 @4 ^7 ~) C! Q
  296. * 输    出         : 读取的数据
    " g5 F; R+ b0 k1 o4 `8 ?9 C6 q
  297. *******************************************************************************// K7 l( C0 t$ Q8 m0 {
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
    0 F8 _! o& _5 X! j* n* L
  299. {   
    ; P6 `0 Y/ r, p3 l0 b" q
  300.     u8 t;( @6 J2 C& M# R7 _& d3 ?* S
  301.     u32 temp=0;, ]0 Z& x$ W6 U
  302.     for(t=0;t<Len;t++)0 D* T9 B& N: z% F+ U3 [, Z
  303.     {
    : D/ p4 T" w7 M+ m/ W5 y8 C, t
  304.         temp<<=8;( K( a8 |  E, B; J% L* q( @1 Q. }
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);          2 s& I9 C6 {; S: b  ~
  306.     }
    9 d& v+ w7 L5 U, D. u8 x; h& J
  307.     return temp;                : F, M: f1 r6 G3 V# G
  308. }
    1 q& w- f# v" v# _+ }  i3 x" R
  309. 0 h8 @; ]9 Z( @- |! h0 B
  310. /*******************************************************************************! _1 ^3 g5 V, c/ G) n: U
  311. * 函 数 名         : AT24CXX_Check' v' k3 _4 W" v! I
  312. * 函数功能     : 检查AT24CXX是否正常0 _! q; v; E5 s/ b
  313. * 输    入         : 无% b6 U5 R' n. n7 J( a
  314. * 输    出         : 1:检测失败,0:检测成功& A$ a: P6 {9 n# |- E
  315. *******************************************************************************/
    ( O8 n' O1 r/ u; k
  316. u8 AT24CXX_Check(void)
    0 x' l# x, K% r: W6 O
  317. {0 g& Z- {& _, ?
  318.     u8 temp;' Y& B8 b2 q; u: ]; G7 A; _
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      
    ' x* x# B1 T6 b9 J3 W# F& b0 Y/ q7 v
  320.     if(temp==0x36)return 0;     # C7 c. @! ^1 u' O% T
  321.     else//排除第一次初始化的情况% c/ z" @' F1 q- l0 ^  C
  322.     {
    ' U7 Z4 F. C3 x) [8 I0 x$ h  e
  323.         AT24CXX_WriteOneByte(255,0X36);* c: A9 }2 z% X7 X, T4 l2 T
  324.         temp=AT24CXX_ReadOneByte(255);   
    8 u9 Q2 b( C. S6 f
  325.         if(temp==0X36)return 0;8 q9 D" G0 [( w8 ?  l  l% x+ @
  326.     }
    ) r3 f; g( w& R7 P  q6 A) C
  327.     return 1;             1 w% a2 ]2 @, A2 @! j  t
  328. }
    - R" I2 U4 E( [0 n
  329. " n# Y( k: ^" u: y4 u) a
  330. /*******************************************************************************
    # b' r# F4 t+ f1 }; ~
  331. * 函 数 名         : AT24CXX_Read
    : ?& }. W  j9 f) G; g
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据
    - k$ Z0 \9 G9 C* y! `' f
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255# Z. }# @/ R6 {  J) m4 e* U
  334.                      pBuffer  :数据数组首地址4 M; o, J3 p- q& Y+ {7 R% N
  335.                      NumToRead:要读出数据的个数: y1 v' h/ f$ M# b. e( L' I0 D
  336. * 输    出         : 无
    ) f7 _1 o( Q" Z: j4 i
  337. *******************************************************************************/
    . V  U  Z& S* v- p! T0 P2 v0 |& ~5 y
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)# R  e$ j! A! l9 Z+ Z
  339. {' Q1 o2 E1 Y* l" J$ o
  340.     while(NumToRead)- n* l% k( ?  i8 Q7 v4 `/ u4 z8 R
  341.     {+ e) [# M! |, d+ ?# I+ W
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); - Y& Y" P( K' v4 \' M; i9 @' W9 Z- e/ ?
  343.         NumToRead--;+ J! s. g  @% m: P1 m& b
  344.     }
    + b7 O5 x& ?& n. n( P
  345. } . r; P" K9 Z4 ]1 _5 a/ `

  346. 0 n7 M: }/ b$ a( M0 ]) c& w
  347. /*******************************************************************************
    3 _7 n: u3 C) P6 Y7 g
  348. * 函 数 名         : AT24CXX_Write
    ; X9 C5 P5 T8 o9 J7 `' s+ F
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据
    5 W6 {6 R$ i3 ~  d9 a3 }1 X' f) K
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~2554 I- Y) D/ I! D1 e8 o
  351.                      pBuffer  :数据数组首地址
    & Q9 F3 w9 V& I0 E5 G% F* S( b
  352.                      NumToRead:要读出数据的个数
    ( e3 M# _, W- ~1 e) M  O8 d* R6 n
  353. * 输    出         : 无
    ! v* a0 t' t% y
  354. *******************************************************************************/
    # v/ B1 @; c, p+ c9 D( p1 Z
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
    3 V8 r% B& }$ M* T' g* b  i* \
  356. {& Z- X8 c8 o' H
  357.     while(NumToWrite--)% q" e, {& `, L- R+ e/ Q2 Q
  358.     {
    1 `  J: T( _( j/ O! ~6 a0 {" `
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    ( r' p4 f2 @6 J, f" l0 q; ]! k
  360.         WriteAddr++;
    2 [8 |* B9 a! ]' m4 g+ }( F: N
  361.         pBuffer++;
    3 P) j& G9 r- V) q' z
  362.     }
    ; h1 J0 {& E; H1 o
  363. }
    ' u( Z3 i6 z: n. s* z- ^) W4 b
  364. .h文件如下7 H6 X% ~" Y$ u0 o# e
  365. ; Y# s, ~+ A+ R+ L. y) E3 _& e
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C02
    % B% U  W  _. M" |: A
  367. // 可修改成AT24CXX系列中的任意一个( I! x* C5 ^, J0 v4 G  P* J
  368. #define EE_TYPE   AT24C02
    5 X4 k7 N; J3 k& ^7 b& \
  369. . x( A8 I* d( K' }" {
  370. // IIC函数9 J+ J4 e7 Q, W; I( n6 G
  371. void IIC_Init(void);   // 初始化IIC的IO口     
    + u, z. A0 r+ f9 Z5 a3 i5 Y% A
  372. void IIC_Start(void);   // 发送IIC开始信号
    - A$ d- Y, l+ f: z
  373. void IIC_Stop(void);   // 发送IIC停止信号% J( [! v4 x3 N. R9 ?; G8 C
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节& j' a5 c' L, ]- T2 j' r1 P
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节. h; @' g& r) `2 q4 A3 c8 K1 ?7 h9 O
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号$ M% N$ h* J/ o! m
  377. void IIC_Ack(void);   // IIC发送ACK信号, S3 R& C  H3 o- x# u& R& o
  378. void IIC_NAck(void);   // IIC不发送ACK信号
    3 c% `$ G4 f, _: D: u2 f4 I
  379. 3 G% [& Z4 l$ D: S; X; O% P% R3 q
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节# j" k) I5 v. z! H: l. [
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节  d3 ~9 L9 R$ K( J' m
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据! o  B0 l( |6 n! b3 y3 o
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据7 [3 `7 Z* E. w1 e" a% Z0 W
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据8 h8 g: k+ F; L  e; P& N# \& t
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据. Z) Q1 l4 @2 @$ u2 Y' i

  386. 6 N% h& E# K& t* W4 h, q1 D
  387. u8 AT24CXX_Check(void);   // 检查器件
    ( X) h5 k4 ~- X3 y
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码

& M0 y9 e' q( ^, L5 ~4 F+ J六、应用实例
: P  {; l8 ~! v给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下
' v* d' x9 F" _; `' L7 F- h' M
  1.     AT24CXX_Init();   // AT24C02初始化
      n3 z! D5 t  \2 R
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常
    * X( W5 d& @" p8 t
  3.     {
      c, z6 ^* p3 l. F% {7 C3 i; d
  4.         printf("AT24C02检测不正常!\r\n");
    $ V3 h2 ^( F5 S. y6 m
  5.         delay_ms(500);+ T, ^5 K7 A6 @& z9 Q
  6.     }% y, _. u& ~! x7 w0 r
  7.     printf("AT24C02检测正常!\r\n");
复制代码

7 o2 l0 Y6 L* ^6 j3 \main函数如下2 N/ V1 h/ q; I8 V
  1. u8 gWData = 0xaa;   // 准备要写入的数据) }' E. C/ v# ]+ e! H
  2. u8 gRData = 0xaa;   // 存储读出的数据! a: V, V) _' f: h1 a
  3. : `0 p% l4 ]: U8 |: s- Q- G
  4. int main(void)$ @0 x4 t; D2 E9 i( s* w; L, h% I
  5. {
    ) f2 G3 f0 i( @% O9 I
  6.     Med_Mcu_Iint();   // 系统初始化
    ' `' b' x0 o9 [) f6 k/ l* k
  7.     ) F$ D% ]3 V6 ~) ]4 g$ k4 T
  8.     AT24CXX_WriteOneByte(0,gWData);5 Y/ K7 L; k2 `1 t
  9.     printf("写入的数据是:%d\r\n",gWData);% d. i9 T3 y( u. z
  10.    
    1 c* B8 k& \# |6 a/ H
  11.     gRData = AT24CXX_ReadOneByte(0);
    1 A" A# j1 u" ?" [/ a! `! A' n' H
  12.     printf("读取的数据是:%d\r\n",gRData);
    , e3 o5 t5 x. Q0 `  h3 `
  13.    
    & i0 z- [, u3 H- X6 z2 [
  14.     while(1)
    ; N" F. F4 w& J1 y8 A7 _
  15.   {. A" u9 j* C( \6 w
  16.     }1 L7 p( ^$ Y4 X4 a8 u% J# U
  17. }
复制代码
# q8 b  U! R- A- j3 v0 N8 T
串口打印结果如下
* N1 Q2 s$ L7 R* K: U" B# b: I5 J5 l3 v) `8 B0 E/ v0 S' d
4 \! I7 ~  J) {
串口打印结果
! N' }' P5 ?% I6 _1 V+ s

7 B3 _1 D1 l% K4 E- E) V6 }# v* Q2 n
七、拓展应用# K/ R( c$ l, i+ K
AT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。
. @' C3 W$ i1 K# Z. S5 R: P2 g& Q2 @& _6 Z' T
4 w. W- g& }* m+ c- }

+ y1 V1 w9 z& \. c8 S, m" {转载自: 二土电子
! v, k7 w9 r4 G) z7 j2 m: g! x, F! R如有侵权请联系删除
6 c) Y8 H# b8 _/ n% c
" Y, r# _2 r- a
微信图片_20231023203400.png
赞 收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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