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

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

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介
& S4 c5 a7 n5 \0 M( D' lAT24C01/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篇。8 S6 y# ]7 Z6 C  v  X
9 r- C, K$ f+ _! |! H
1 _. |  H* d; h) z
二、AT24C02引脚
5 b/ c, F8 m7 \7 D, a. W

" D% a9 e, C8 c4 u2 e# Z7 |) p/ y9 a0 s5 ]
微信图片_20231023203334.png

6 ]* e$ D- ^% P0 t' z
AT24C02引脚定义
! O, X" S* H$ x1 C9 P
+ P( |7 ]2 \' F0 w+ v
$ y8 W" K1 ]' F  x/ z3 q
三、AT24C02寻址

! r; j: y$ P; [) E- K* l使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。% ~( T& y' I  G- \! l: L
) @& Z8 p: ]( d
微信图片_20231023203357.png
  q4 Q: ^% b$ ?
AT24C02地址信息

) R& K, e0 v7 ]) p% D# l4 o. `
( _+ C5 V2 r. V/ w: O; d0 }/ r  K  o
2 l( G, X, q1 b# S
器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。
$ N8 K$ B" k2 o8 X. c4 H; r& h% ]! Q) O( @
四、AT24C02读/写操作
4 V5 Q' i# u6 M! D# A% K4.1 AT24C02写操作
/ l# T4 F- A6 \
写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下
. l5 W0 b" g& U1 t
* H* P" W% {4 u% c2 b

; A! _# `6 v( U; p! }+ G
微信图片_20231023203352.png

4 j6 l0 {8 C! S) r- [6 ?: v
写操作时序图
8 y: l" F% K6 p) {9 s8 j$ A4 m

$ D9 B# L# q( |, k( X6 d5 [+ A4 d! ~  V4 f
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。( h4 b/ E4 w9 s! \2 B& B0 ^

. V: J' k0 H6 J5 N- {7 M* Q( w4 u接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。* P. `9 \1 B4 [- E4 w2 e( C
0 o& J1 }- Z  n" }

3 l5 j! j. j/ l) B: t9 E5 B! U4.2 AT24C02读操作
; Z  c1 Y. R/ A/ ~. _4 k" h# J
AT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。
0 ~; E$ o+ m) Y: ]• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下8 Q6 u4 t5 p+ r  R9 Z
! X, D3 X. e: d, q

* ], }* |; i; U) `
微信图片_20231023203350.png
# p/ N; S* A# H
读当前地址时序图
( j% T+ e! M3 N6 \
9 O8 {  ~4 c. E' T2 S

6 L, d7 N& F- E& Z; V/ i
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下4 k8 l1 d2 v; o# g
0 V+ h  l* [: a, j  F4 {; r7 E

/ @7 c2 b  I/ d* }/ k
微信图片_20231023203347.png

6 ^) |' c* g! d8 X$ l  X- ~1 K
随机读时序图
0 O: f; B5 ?$ ?5 G/ T/ i+ c$ x6 A

4 D9 ~8 X% W* \6 n. C  d2 t/ b

( h2 r5 w6 z! [! j

6 z& L% V/ M) C. p• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下
- O( L" I& F  D7 B7 x* L+ C
: |  c8 x0 N" y) p- s  O0 b6 w0 Q
! O- l, Q. u! A' N8 p& b
微信图片_20231023203342.png
3 ?  Q% ]& N4 v
顺序读时序图
1 Q) f: O8 L+ |$ ~0 f8 W/ _
! U/ U% q2 R. y8 l1 ?

! W; b0 p( u# i2 y+ p8 H( I
五、AT24C02程序
+ F: l, h5 h, ~$ g" u/ c+ Y这里给出一个AT24C02的程序,仅供参考9 @* h5 a% m5 O/ O
  1. /*******************************************************************************/ O7 n2 ?  d" p  u0 m
  2. * 函 数 名         : IIC_Init: O* A7 P' \8 r! @
  3. * 函数功能     : IIC初始化
    8 n, p- V" P  B0 _' o3 ]
  4. * 输    入         : 无
    7 ^' x  w0 B' O0 F* x2 s- D. n
  5. * 输    出         : 无! u1 W1 G. R' O; J6 X2 |" j1 v* U
  6. *******************************************************************************/
    % K1 G: f' J: \7 l: L
  7. void IIC_Init(void)% |8 L: i% L  S8 s# Q& b0 M
  8. {5 H$ h/ P1 ~8 m: h2 U- \
  9.     GPIO_InitTypeDef  GPIO_InitStructure;& k7 K9 S4 ~) E- t+ H
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
    9 T4 p2 m# E5 V1 X+ J# g
  11.    
    0 @$ I9 f5 u/ O0 `
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;0 o/ g' H; x( x: `9 V8 i) t: }& H
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;' ~. Z4 B5 `, q4 H0 e/ q
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    0 H. `) C7 Y1 _* Z! L! A
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
    4 t# }5 R3 C( H3 ]; P" ]
  16.     " @5 i) I- U6 Y: B; L
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    1 }+ P% r2 O% G: }
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    % c' d* U0 t- J0 s( z% z
  19.    
    8 i. V, D+ G; |6 e, R  @* p( w
  20.     IIC_SCL=1;! m" n3 W! y* K; W( O/ y! ^
  21.     IIC_SDA=1; , q% M3 u* j/ x& ^
  22. }
    ; k* _5 }9 k3 c8 w
  23. /*******************************************************************************' @) b8 p! u; Z9 U6 c. e7 _% j2 f. A
  24. * 函 数 名         : SDA_OUT$ \( m, P. H! r/ U+ K: p: g% f
  25. * 函数功能     : SDA输出配置    7 b2 }0 y. P$ l+ Q* T2 @$ Y6 q/ L
  26. * 输    入         : 无
    ' M% \5 t1 s: o' W5 Y% _
  27. * 输    出         : 无: P7 l  Z& x% v$ s' u0 e
  28. *******************************************************************************/
    % ~+ }, i) i$ E$ K: s5 X5 a
  29. void SDA_OUT(void)
    / t' r4 {2 N# f6 x
  30. {
    7 A" ]3 C8 l$ p/ t/ b
  31.     GPIO_InitTypeDef  GPIO_InitStructure;
    5 M* v2 Z+ q1 q$ Z3 T0 h, U
  32.    
    + y, A+ x* {6 v/ W
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;* O4 S  ^2 U% p
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;4 A5 h4 f4 A# K+ i( x4 ~
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    1 g* c8 _: U& V5 ?5 k# w& \
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    " M- {% b+ v& w/ s- d# X
  37. }
    # F* O& j# v* `# d- E, D* \/ |, D" l2 f
  38. , Y% V/ [, _7 U$ j! q
  39. /*******************************************************************************
    ( M8 {/ X- S; ?8 o/ @0 O3 K
  40. * 函 数 名         : SDA_IN
    # x4 s0 A% J8 H: u
  41. * 函数功能     : SDA输入配置    - V. |8 t6 K9 }8 I. p# e
  42. * 输    入         : 无. `' ?9 v1 }3 l) {3 [6 F" _
  43. * 输    出         : 无
    + {; P- C$ T0 a. _9 r# x# X
  44. *******************************************************************************/. c* A1 C0 {4 A+ M- Q
  45. void SDA_IN(void)0 H" H/ Z2 _* p2 i
  46. {  ^1 a# f/ J* O. c% W) |0 Y  m
  47.     GPIO_InitTypeDef  GPIO_InitStructure;
    + m+ T3 a  ^9 |2 N2 U$ ?/ u9 A9 {
  48.    
    5 \5 [% U$ q. h- j3 v4 d8 I
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    8 }1 M/ F: w! P3 ^- r
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;: [" [+ [6 v! {1 w/ ?2 o
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    ; k: X* f( F2 U7 o
  52. }
    ( O* K  y" `) E$ t2 |) N# j

  53. $ J/ |" A, m4 J, n. ]8 K2 H
  54. /*******************************************************************************, V& O# {7 c* z  `7 ^7 r. m
  55. * 函 数 名         : IIC_Start1 S" V3 ]) D3 L6 g# F  x
  56. * 函数功能     : 产生IIC起始信号   - S! O: ^  L$ G6 P1 Q
  57. * 输    入         : 无
    ! j- d% b% k" E
  58. * 输    出         : 无
    # Z# _- @4 U$ j; {, l; M
  59. *******************************************************************************/
    / S2 j! d) Y1 Y, h
  60. void IIC_Start(void)
    ! G. n/ _7 y& G) m
  61. {1 }9 G& F" e7 @
  62.     SDA_OUT();     //sda线输出
    , D( O+ P7 `: N# |! f- `6 q
  63.     IIC_SDA=1;      ( I& `& {% ]$ p, P
  64.     IIC_SCL=1;
    $ E8 H8 G& l7 H& {" H& n! R
  65.     delay_us(5);
    ! K8 [; F5 g. E% o
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low
    ' a$ r: ]- k/ O5 v2 r
  67.     delay_us(6);+ ]$ I+ K9 x$ s% U' F) Q$ e
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 ; F( x2 j3 ]4 [" M
  69. }
    3 h4 R0 j  z, K" s" t
  70. 4 d) V# j0 `  y8 l9 L6 O- k
  71. /*******************************************************************************
    0 U3 F: r5 Y, `6 l% o) U  S
  72. * 函 数 名         : IIC_Stop
    " S( Z2 c! U. S+ T( n, A4 {
  73. * 函数功能     : 产生IIC停止信号   $ V3 h9 M  G) ~3 L
  74. * 输    入         : 无, S5 U9 g8 }: B  r
  75. * 输    出         : 无& g* D  e" {  ?+ y& _
  76. *******************************************************************************/
    9 E3 e6 A3 B3 |
  77. void IIC_Stop(void)
    $ f" ^7 o, z1 |9 P
  78. {
    ( C4 a3 m' B/ N4 G
  79.     SDA_OUT();//sda线输出, p& I, C( f& ~  L9 C
  80.     IIC_SCL=0;
    - p" s- v* n1 P9 `" H
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
    $ H% Q1 P, h. M* ]  n- q( D% Z
  82.      IIC_SCL=1;
    , K" G, K) X/ }/ l" ]
  83.     delay_us(6);
    ' i9 }, \+ T+ n1 n/ M
  84.     IIC_SDA=1;//发送I2C总线结束信号+ h7 O% P4 X  ?. _% A$ u3 N
  85.     delay_us(6);           
    % @  y/ f# U% u: T
  86. }
    . w; l  F# S0 y& ]
  87. . w. n" h  X- u& [& _
  88. /*******************************************************************************# P% I" B8 T4 j" e: z1 A+ C! M
  89. * 函 数 名         : IIC_Wait_Ack2 M8 O. x0 l1 O; g' X2 L
  90. * 函数功能     : 等待应答信号到来   . a9 W3 H. `$ h! X3 P3 I
  91. * 输    入         : 无
    7 B+ o% f/ R; {) {. _7 x$ n
  92. * 输    出         : 1,接收应答失败
    ( d/ Q2 C) A3 b9 U
  93.                      0,接收应答成功
    ; e% [% j) C2 v. z7 J: r9 M% k& h
  94. *******************************************************************************// Y6 S  Z% L, Z& A+ P5 l+ c3 P
  95. u8 IIC_Wait_Ack(void)1 n) Y+ i$ d+ |. h  q  f
  96. {
    8 v( m( g0 b1 d$ T5 P
  97.     u8 tempTime=0;6 f/ ]& J" [/ ^1 P! S( ^2 \
  98.     SDA_IN();      //SDA设置为输入  8 F* s' `! Q( u
  99.     IIC_SDA=1;
    ( t/ [. ^- e5 K8 {
  100.     delay_us(1);    ) w9 v0 S1 y7 O* ?4 t2 x- C8 p
  101.     IIC_SCL=1;
    5 u  P3 }/ U' O7 b. G( h! R! ^
  102.     delay_us(1);  
    # `0 w3 m( U+ y* ~; d9 M
  103.     while(READ_SDA)" J7 [* k( c& S* a0 b" x& P" k% o3 q
  104.     {) z  }- E0 @1 m; F
  105.         tempTime++;6 d# ]% j1 ~6 W4 k( s
  106.         if(tempTime>250)
    : A6 Q6 b# d4 p0 w. k$ m
  107.         {
    . ~/ f; \0 x8 u& G; A! J
  108.             IIC_Stop();0 y1 ~. m7 l5 E  M! s# N
  109.             return 1;
    0 F3 [+ t( x' l* b$ Y; S+ ?
  110.         }
    ; i# J$ ~& @, A. n) V+ u3 U$ d
  111.     }/ a0 z4 O. i" n$ t' x
  112.     IIC_SCL=0;//时钟输出0     
    ) J  N9 K% e. J0 f
  113.     return 0;  , h1 H) R8 X3 o. L: o* ^  \
  114. }
    % d* M* D% V7 H; @
  115. 3 M+ Z) ]. ]8 Y" ?
  116. /*******************************************************************************
    % \  C# n' p0 B  V
  117. * 函 数 名         : IIC_Ack
    & _3 \, K* y: ^  g, C
  118. * 函数功能     : 产生ACK应答  / y2 R0 a4 L3 N
  119. * 输    入         : 无; f2 g  b2 n! F' U7 l
  120. * 输    出         : 无
    2 P! T) v: ^) j" b
  121. *******************************************************************************/! n& M, H4 o6 {
  122. void IIC_Ack(void)$ F8 z+ A! W. c5 ~9 z* l
  123. {
    , T4 N, h" `0 U$ O& W
  124.     IIC_SCL=0;
    ) }1 E$ t6 C4 q$ _1 u/ O
  125.     SDA_OUT();
    + n+ q& V5 D9 ~3 u
  126.     IIC_SDA=0;8 e3 O, q$ y! f$ w3 ~% z' \# V
  127.     delay_us(2);5 M1 C, K, ?+ o
  128.     IIC_SCL=1;3 r  ?$ Z" F4 `* D$ ^
  129.     delay_us(5);) L: g* r7 z1 \% f8 M
  130.     IIC_SCL=0;
    3 S; d3 g6 [! @1 i; y' d; J5 x# m
  131. }; F$ {3 t% _/ s( I: s" p" l$ h9 z

  132. 8 P3 @9 Y3 @3 A
  133. /*******************************************************************************/ {5 B0 W  ?( W. a* t. E) z
  134. * 函 数 名         : IIC_NAck: ^$ f" U+ P; E8 v* K
  135. * 函数功能     : 产生NACK非应答  
    ; w, u1 T5 Z+ w4 l+ O* k# Y; o: X
  136. * 输    入         : 无
    , R: J( \$ U* D5 f9 V( |
  137. * 输    出         : 无
    - i$ H/ s' y3 d/ x# d
  138. *******************************************************************************/      
    9 D- J& e0 r- S% |7 v
  139. void IIC_NAck(void)  U" O) z, C( J5 z  @5 W, f% N+ G" D* K
  140. {" }" f8 w+ r- ]. K2 h+ J6 N
  141.     IIC_SCL=0;
    5 q: j% @2 q- s% J# V+ h' y9 y1 I
  142.     SDA_OUT();
    8 C8 Y/ r+ ~. B0 s+ p. ~
  143.     IIC_SDA=1;
    & _( n: ^2 |0 H: F
  144.     delay_us(2);
    ( V/ @1 ]5 `1 g& _/ g
  145.     IIC_SCL=1;
    ; Q/ O* c+ ]5 @$ c
  146.     delay_us(5);
    ) C: D0 U. W# C% w
  147.     IIC_SCL=0;
    : m' e# I- C0 Z) ~: @
  148. }
    * T# }- w1 r5 H. c
  149. % m5 p+ |0 U1 n9 p2 a
  150. /*******************************************************************************# y4 c3 A) }  o" b, m9 n( P! h
  151. * 函 数 名         : IIC_Send_Byte
    ; ?! v! G8 S  r
  152. * 函数功能     : IIC发送一个字节 ' G* Q6 a; u, b: V9 W. W
  153. * 输    入         : txd:发送一个字节
    8 a" ]6 j: h) D1 t, c% W
  154. * 输    出         : 无6 d" a; F, M/ ~' B
  155. *******************************************************************************/    # j7 m, U6 n: T
  156. void IIC_Send_Byte(u8 txd)
    . B+ b$ e- g9 p* Q) g
  157. {                        
    4 v  y) [8 Y1 V$ m# S
  158.     u8 t;   1 ?$ T, o% Q3 q, t3 T
  159.     SDA_OUT();      
    3 y! P' D& R% F' f% E2 h
  160.     IIC_SCL=0;//拉低时钟开始数据传输* D* {/ Q1 q$ c
  161.     for(t=0;t<8;t++)
    / V; O4 r" w; F* ~+ d
  162.     {              
    ; q7 K& h. ~5 a# f) I( b' ~  e
  163.         if((txd&0x80)>0) //0x80  1000 0000
    5 B, N+ b" Z& o0 k: w( {
  164.             IIC_SDA=1;9 @5 h& U0 m8 D( I2 K9 [( b
  165.         else
    * ^% w% ], G+ A' O' g# P! z% J
  166.             IIC_SDA=0;
    - X. H1 p! Z2 B) P; j+ h7 K
  167.         txd<<=1;   
    ) W* D9 b1 B9 H8 z! |. q5 ^
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的
    2 t8 U8 l; z& C: w0 @2 b9 [
  169.         IIC_SCL=1;* Q* C0 N8 {( A
  170.         delay_us(2);
    6 p4 {4 w- {* D1 L; N+ N. w& A: t
  171.         IIC_SCL=0; ) g0 t( f. F# P6 h2 m( q7 z  a
  172.         delay_us(2);+ w7 K3 F1 ?6 Q" d- n9 o
  173.     }  
    # T! ^8 y# e. P8 J% G+ V6 Y+ n
  174. } 9 w% f! N# _0 f9 Z  P* T

  175. 1 ^2 y- C( j# J- t% |6 c9 Z
  176. /*******************************************************************************
    " W( U( o! d: i- O
  177. * 函 数 名         : IIC_Read_Byte; c4 d, z* k- m! D/ D8 H
  178. * 函数功能     : IIC读一个字节
    * d) [4 l3 w# _; r: ~5 l# D1 y
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK
    4 r( i  Z( t+ C8 f; p- i7 R$ p
  180. * 输    出         : 应答或非应答) A7 G( }4 r: j
  181. *******************************************************************************/  ( I. D/ l# ?* \! k* _* T& ?4 k% W
  182. u8 IIC_Read_Byte(u8 ack)
    % _# P% J1 }8 c5 B- o
  183. {' x* O) W1 j1 Y
  184.     u8 i,receive=0;
    7 h/ l' Y. A. E6 I. ^2 ]( R
  185.     SDA_IN();//SDA设置为输入8 c' j4 S8 h- A) e' S
  186.     for(i=0;i<8;i++ )/ \5 |" K  A" E8 a
  187.     {& D! X2 C$ u' f1 M9 L
  188.         IIC_SCL=0; 4 L; w# W/ N4 g
  189.         delay_us(2);' Q1 m/ k+ c- ^% K. z( D; z
  190.         IIC_SCL=1;* T/ Q. T: e' b" i, k
  191.         receive<<=1;& {9 _" z1 Y: c- T$ w. K1 N# e
  192.         if(READ_SDA)receive++;   
    8 N% L5 q% ?. O7 E: O" _# i
  193.         delay_us(1);
    6 ]& d1 S; [. v8 p) \; B2 r" ~
  194.     }      5 A7 [3 c9 ^+ C9 c4 _
  195.     if (!ack)# ^& ]) f1 p4 ], v! m
  196.         IIC_NAck();//发送nACK1 \: t/ N- O: {: ~, ~
  197.     else
    3 O+ a. Q& h5 X. }2 a
  198.         IIC_Ack(); //发送ACK   
    & [# |3 m( q( I- q4 g, o5 B. F
  199.     return receive;# P  E$ w! w3 d* [
  200. }
    / t# S0 o5 D$ v7 u
  201. /*******************************************************************************
    ( N( i/ M5 {) [. e( D
  202. * 函 数 名         : AT24CXX_Init
      P3 m2 l$ v6 t# p# Y  B- Y  F
  203. * 函数功能     : AT24CXX初始化3 `2 b" v& r) a3 j2 m' c
  204. * 输    入         : 无
    * }# a9 h" w; f7 i8 p; [
  205. * 输    出         : 无
    + ^  B- f: u: j) S/ b! a) B) R$ r9 M
  206. *******************************************************************************/
    % z' B* W7 ~0 N2 E
  207. void AT24CXX_Init(void)
    2 _, k, @$ Z4 |; Z, W1 R& i0 f
  208. {
      ~: S9 n2 E& Z. O, V( Y. j& f' S1 u
  209.     IIC_Init();//IIC初始化
    . f1 O1 ^  y7 e2 ?: g
  210. }. M2 W. Y! H2 q  W8 p
  211. ; l0 \# n5 u& k7 p# H
  212. /*******************************************************************************; J! z9 b/ s: N* f5 C
  213. * 函 数 名         : AT24CXX_ReadOneByte6 |* G5 _6 ^& a- ~9 v6 _/ \9 B
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据
    ( d9 P( y( L+ E$ d% s5 n$ g- p
  215. * 输    入         : ReadAddr:开始读数的地址 / X# q, j; W3 o' k$ Z4 h( T
  216. * 输    出         : 读到的数据
    9 v* v+ @8 E- l/ @$ j6 }: o
  217. *******************************************************************************/
    6 g- J. ~/ n  N' M
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr)
    3 T+ z' X% `& a
  219. {      % o1 w, i! ]2 H1 F
  220.     u8 temp=0;                          
    + f# W/ D2 l% z, c( y; F( a( A
  221.     IIC_Start();  4 j9 t# p* c$ v; `! T; _! k( u
  222.     if(EE_TYPE>AT24C16)
    ' X9 p6 s* [0 D7 s
  223.     {+ w& ]3 b, I$ h+ c* q% ~" L
  224.         IIC_Send_Byte(0XA0);    //发送写命令8 o/ ?# {& r, z$ u, r
  225.         IIC_Wait_Ack();# e/ I* g9 R4 D
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     4 I& T* w" s$ i6 {3 v  a
  227.     }! f! N7 r3 r, n0 S
  228.     else & m4 Y. h  ~, i2 R7 c. x
  229.     {
    0 M& J; n+ B3 w" K
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据
    7 L) [6 A  n& D0 H4 L% {, {
  231.     }     
    4 V- W" M2 _8 m. H
  232.     IIC_Wait_Ack();
    ! L( Q' T" t& m, Y7 l5 T! W
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址$ p7 l: F7 B4 C0 {/ _
  234.     IIC_Wait_Ack();     8 N' C; H/ f  Q% E1 Y
  235.     IIC_Start();        
    7 H: X' p- g" e- y( s4 V& C7 `
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      
    % r7 ]3 x- ?7 L
  237.     IIC_Wait_Ack();  . Y$ j. H% ^6 P1 K
  238.     temp=IIC_Read_Byte(0);     1 P$ p! P" u! i; c' |
  239.     IIC_Stop();//产生一个停止条件     
    1 {3 v+ ], F6 N9 a
  240.     return temp;  Z6 V; @" A' J6 J
  241. }- P% k1 d' t$ J0 j

  242. 4 E7 t3 }0 D# B4 A+ I4 l
  243. /*******************************************************************************, ^) |) x- x# n1 ~' ?* s2 E) X7 _
  244. * 函 数 名         : AT24CXX_WriteOneByte  m, N; S0 u2 O3 U  r
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据
    7 _7 I6 D8 r) Q. Z3 h9 E
  246. * 输    入         : WriteAddr  :写入数据的目的地址
    / K- G9 c) B3 i. v
  247.                      DataToWrite:要写入的数据
    : ?- @9 M, G: k) T0 R
  248. * 输    出         : 无
    , X& S# [/ |, Z! R! ]
  249. *******************************************************************************/
    9 l4 n4 g/ N; p/ X
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    7 @* @5 Z% g1 X
  251. {                                
    + G$ w/ g1 ?1 a! P* z
  252.     IIC_Start();  1 G0 i% U* X( y% ]* R4 C1 D: ?
  253.     if(EE_TYPE>AT24C16)1 N% }1 k# G& ?# t- h
  254.     {
    8 @* l4 m" u' B) s5 m! Z
  255.         IIC_Send_Byte(0XA0);     //发送写命令
    4 [$ F1 h1 {$ w+ ~6 J( |1 `3 T
  256.         IIC_Wait_Ack();/ v2 }; g) o& H; c" o! T+ R- ~1 a
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   1 g  I; X2 N4 N
  258.     }
    ; R4 @& s# f4 G. B9 u+ ]4 I
  259.     else
    % q" z' W  n6 U$ n) d
  260.     {( }! X+ j5 V  w4 x" Z9 h
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
    4 G) Q9 O" G% c: P
  262.     }   7 N. N! }2 N) S1 E% |5 ^7 Y9 e
  263.     IIC_Wait_Ack();   
    ( S. `/ I/ Q4 x1 s1 x$ Y; K
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址1 l3 K/ _7 r& R: P4 T- |. F" S
  265.     IIC_Wait_Ack();                    
    3 w) U1 n; O1 f
  266.     IIC_Send_Byte(DataToWrite);     //发送字节          " R) C: _, M  B4 s7 i
  267.     IIC_Wait_Ack();            
    . i8 `( E. p$ T
  268.     IIC_Stop();//产生一个停止条件
    4 Q2 r  J5 o$ i7 e
  269.     delay_ms(10);  ' I+ S' a& c0 ~% P* T4 W- N
  270. }" l8 [( Z7 J. ]7 c9 j# m8 A

  271. . j9 O% E' Y( ~: j* V3 C
  272. /*******************************************************************************7 _8 k, I1 _* u
  273. * 函 数 名         : AT24CXX_WriteLenByte
    " C0 \2 w4 z# A; y" E( h
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据
    % j; g5 h( e1 f
  275.                      用于写入16bit或者32bit的数据/ r; k0 v& L' p( H0 j* c
  276. * 输    入         : WriteAddr  :写入数据的目的地址
    : p. w2 G- V2 G* Q+ A
  277.                      DataToWrite:要写入的数据
    ) s& C$ |: Q9 `$ m. {
  278.                      Len        :要写入数据的长度2,4+ n& a! g6 F' I0 H- x
  279. * 输    出         : 无
    4 [8 I2 [3 j- i  t
  280. *******************************************************************************/
    ) \! f7 S; i6 Q% h! \6 ]
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
    ( K# ^: F: \% @5 O, I2 K; }
  282. {   
    % I0 A! f3 c( i9 Y
  283.     u8 t;
    1 N9 L% {2 J1 a4 S- f: K: S7 t
  284.     for(t=0;t<Len;t++)
    4 v5 m/ }7 q, Q# r6 c1 e
  285.     {7 N# _9 p* r& C8 B, T
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
    . H+ m& l- d" [  G4 V$ G
  287.     }               
      L# Q: W/ J$ R. A4 t( V) W) N
  288. }9 Y! ]" G. t/ J0 C) }

  289. ) {+ d5 i% _4 o# `. [4 u- {
  290. /*******************************************************************************
      ?% R, s7 Y& T6 `$ p! M# w. z3 L
  291. * 函 数 名         : AT24CXX_ReadLenByte0 V- ~$ Q: F, J0 X% Q0 _0 h
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据! S1 E2 f7 {; {! Z2 X6 j
  293.                      用于读出16bit或者32bit的数据
    . P. \) m6 S; X. V* _0 M% U! c
  294. * 输    入         : ReadAddr   :开始读出的地址 $ ?  j( o$ K: h% n0 [2 Q
  295.                      Len        :要读出数据的长度2,4$ @$ W7 s' ?. n3 I6 y! z
  296. * 输    出         : 读取的数据( x! \' N$ m# k7 e$ k
  297. *******************************************************************************/
    ' ~& b+ Y( l! T
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len): E8 Y5 g0 D5 G  L' V$ a$ D  D
  299. {   + u  [9 u' f& O( F. s
  300.     u8 t;$ l% ^( T" e" s. H( S$ d
  301.     u32 temp=0;1 Q8 m/ M, A: @+ g, X4 p
  302.     for(t=0;t<Len;t++)
    % Z2 x3 J- Q6 ~' ^, R- S
  303.     {
    ) {+ O9 N1 u# w. a
  304.         temp<<=8;
    6 R& q2 I/ e0 }
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);         
    , V& ~, W: {3 o0 j. d, n4 }
  306.     }! G/ S* z! p7 ?4 e! X/ G
  307.     return temp;                " F7 P6 F% `  T
  308. }. K( J* a# z" N7 j) ~; s
  309. 5 j; N$ L- P& c  W2 U
  310. /*******************************************************************************
      _" w6 L. n6 [" m2 P1 V
  311. * 函 数 名         : AT24CXX_Check
    2 I' k' |( F5 F7 p5 c: Y& Z
  312. * 函数功能     : 检查AT24CXX是否正常5 J! J# @" u6 G1 J% b
  313. * 输    入         : 无! u, r  [. q0 P% p! A2 p5 i
  314. * 输    出         : 1:检测失败,0:检测成功
    ) ~9 F% C# B+ Z- B) m" j9 _
  315. *******************************************************************************/! v6 b* G' p8 u: N% }+ q
  316. u8 AT24CXX_Check(void)
    ( d4 z& ?) }2 x5 Q) |# f4 w$ L
  317. {0 P& h( g( E6 X5 R2 h: D7 ]
  318.     u8 temp;
    2 P8 K1 l+ W# @! @! Z4 k1 s8 C* n+ ^! _
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      3 \, Q+ G7 i6 U! D* d  \+ d) P( T
  320.     if(temp==0x36)return 0;     # p5 d! R0 A% d& e$ k1 W
  321.     else//排除第一次初始化的情况/ r5 V' z" W% k) X0 {1 m, Z
  322.     {. x# X6 S. n  }
  323.         AT24CXX_WriteOneByte(255,0X36);; M/ P# V5 n8 G- G4 B# g; v
  324.         temp=AT24CXX_ReadOneByte(255);   
    % z4 L* P2 k, f, E9 b. g  r
  325.         if(temp==0X36)return 0;; {1 h8 ], U9 j: G1 p: z
  326.     }# y4 Z% v9 q9 `! V- b5 p
  327.     return 1;            
    / J; t+ a" \2 y" e0 S
  328. }
    . a' H. `" s. _8 L- Q; X* ^. D5 B
  329. - m. J; i0 @. L
  330. /******************************************************************************** n* H( L2 H; t  w0 O4 o3 k
  331. * 函 数 名         : AT24CXX_Read  G6 Y$ G: _& w
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据- q% C3 X- Q( k  J2 K9 R0 a
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255% B+ k7 F  K& k- K# R' i- I( \
  334.                      pBuffer  :数据数组首地址# o. H$ t9 y- N# y, M5 V
  335.                      NumToRead:要读出数据的个数
    # I. |$ N1 l$ M
  336. * 输    出         : 无7 ^$ a$ q2 q1 f( R8 T( o, l7 h
  337. *******************************************************************************/
      e. R. |; Q& H3 s7 l6 k1 v
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)2 f$ m( y8 g: i& [! }  ~; J
  339. {
    ! U3 \* A" h+ k
  340.     while(NumToRead)! S3 x6 b' U- \: S7 p: Y* H
  341.     {
    % H& |, G3 B. e3 l% D
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); & W' q7 [* H/ E
  343.         NumToRead--;4 V: a0 U5 I" h" K7 B
  344.     }7 _$ K/ A8 E; z6 P
  345. }
    , l  I7 q' v9 Q8 X, J# J

  346.   D7 O% N' i+ n. e2 z- G0 L7 I
  347. /*******************************************************************************
    3 m. c( E; V. Z; T6 f7 }( R
  348. * 函 数 名         : AT24CXX_Write9 P3 a6 N# g* ~% h' B
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据
    / J4 @' l4 {, S, W& I6 x) P
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~2551 y0 p( c* n# t
  351.                      pBuffer  :数据数组首地址; c8 k, C: K# z1 U
  352.                      NumToRead:要读出数据的个数- d! W# M- Z0 @
  353. * 输    出         : 无8 X4 p* `$ a$ B; _4 Q# q8 m+ d
  354. *******************************************************************************/
    % K& N  \6 G2 x( |: T
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite), y7 t2 t3 O1 }& |/ i5 ]+ v
  356. {
    " z( V( E4 ^) ^1 d( W6 m& }  l
  357.     while(NumToWrite--)) B# o! Z& U' Y% Z, F1 a
  358.     {6 W% I7 z3 u/ x6 n7 |/ ?$ A, z
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    , c# r4 {' B# C/ p5 E* j, L
  360.         WriteAddr++;
    ( D2 N' T* D) r' h& ]: W
  361.         pBuffer++;/ F6 q3 M" F+ A3 S5 K1 C
  362.     }/ H8 i/ V1 w" C2 v; V- P- I7 K
  363. }; Q2 m# Q- J/ O! s
  364. .h文件如下9 X& P; \: y* L( V5 G
  365. 0 w! x7 [3 G8 ~. n# ]  \
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C02
    : c7 Z: O( o, g" [
  367. // 可修改成AT24CXX系列中的任意一个$ I# T/ a5 Q6 K1 ?6 r& h1 s, m
  368. #define EE_TYPE   AT24C02
    5 V1 ?6 }- K2 _3 \# I$ C8 ]- ?
  369. ; D- `  A7 T/ }0 |3 g& U  X- H% M7 n  m
  370. // IIC函数1 V1 z" i  Q! D) E1 Q
  371. void IIC_Init(void);   // 初始化IIC的IO口     ( p% F! @  U7 i, Z
  372. void IIC_Start(void);   // 发送IIC开始信号2 [9 j/ r7 o& u) C* w8 d9 s) v( {+ [
  373. void IIC_Stop(void);   // 发送IIC停止信号2 O( g/ J% p+ _. L* [8 s; D  h
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节: b/ q7 f, u9 y5 M$ \/ w
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节# v5 ~# N- V& _
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号
    3 B. C% z. g0 j& ?  j* j$ G
  377. void IIC_Ack(void);   // IIC发送ACK信号
    ; a3 ^; R3 _6 s) |
  378. void IIC_NAck(void);   // IIC不发送ACK信号5 X+ O7 P7 N5 m' J! s6 h
  379. ) s' I; S/ n+ Q5 c! X0 K7 |! l; X
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节$ H1 r0 v6 d/ X; b/ B
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节: g% F; L( K  }6 s; S' b9 A
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据
    * l8 X$ T; a# t" _5 R3 K6 R
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据
    ( [+ @1 B/ Z( v4 k2 o
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据9 S& |+ H, j4 y, {: U1 Q4 O, s2 d
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据( Y9 ~, A( ~% s& n

  386. - Q$ V; }* |0 q
  387. u8 AT24CXX_Check(void);   // 检查器件
    ; Q1 L/ N0 x1 x1 y; V4 ~9 D+ S7 s
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码

" O' H4 K7 Z# `0 _6 {0 @& k六、应用实例" N& H6 `/ \  U  e3 O7 H* `
给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下
! ~. x  v* o& Y4 F2 `' _- R+ N
  1.     AT24CXX_Init();   // AT24C02初始化; \: D5 ~/ R5 A+ `7 [1 Z1 h/ S* W
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常
    , l: V+ s# l6 u: p, \
  3.     {* Z5 d( Z! o9 B5 s$ U
  4.         printf("AT24C02检测不正常!\r\n");. P$ n5 C9 v2 M# m' B
  5.         delay_ms(500);
    # G( }6 U2 f" m1 x7 M& j4 p
  6.     }
    0 E% m/ W2 C) B0 r- m& @. q
  7.     printf("AT24C02检测正常!\r\n");
复制代码

& f* T: T& O/ Tmain函数如下
9 X( k1 C' V$ Q% C# c( `" m
  1. u8 gWData = 0xaa;   // 准备要写入的数据
    5 K+ V" ~$ I, ^
  2. u8 gRData = 0xaa;   // 存储读出的数据: O  f4 _/ `+ ]3 Z* n# y& h

  3. 0 W9 ^5 N+ }( v, ^( i
  4. int main(void)
    7 s: J+ ?. o8 T+ K9 L8 t8 H# z" ~( R
  5. {# d  q8 e# v; Q6 @: ^  ]
  6.     Med_Mcu_Iint();   // 系统初始化
    ! B! v. c1 `3 O
  7.    
    ( x, K, L; }: @% f5 g+ v' D
  8.     AT24CXX_WriteOneByte(0,gWData);2 z) O; k. K  V0 g7 r
  9.     printf("写入的数据是:%d\r\n",gWData);
    5 b2 Z9 d, s2 Y$ h
  10.     % T! c% L; g' t, v9 i
  11.     gRData = AT24CXX_ReadOneByte(0);
    ' v1 b- q$ x$ `  l# J4 a7 o
  12.     printf("读取的数据是:%d\r\n",gRData);
    2 v' S/ p7 x" E
  13.     & S. v5 ]$ {" p" B& v! a+ G
  14.     while(1)
    ! |; G  ?+ q2 D1 |# Z) ^
  15.   {
    # |  a% R: F) [  J$ E1 ]
  16.     }
    4 [$ O; J$ g, U3 ^7 m% k: }
  17. }
复制代码

4 J4 q: }% \; v; @/ T串口打印结果如下5 N, M1 n: c* ~/ T

5 F1 I& a8 c# f7 u: p2 B: {

6 @! }* u0 b& X% o5 J* W/ _
串口打印结果

3 `, d+ j( Z( k! X, Q1 @
, i0 y) i. R( A( I  E" x8 j
# E/ [/ a; O  j$ b4 k+ v# Y: ]
七、拓展应用' N% p1 C  _' }) a# ~/ P
AT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。
$ Y: G% H8 e: F- F7 I& q  H
! M7 J4 ?0 ?5 _( S! t9 G; r  V
5 l' h) r7 |& V3 G1 _

" _6 a5 O6 L7 O2 q; a转载自: 二土电子4 f4 \; ?: o- J
如有侵权请联系删除
5 I# E7 Q  @7 V+ B
1 f/ X) |0 }. \% H3 N" P
微信图片_20231023203400.png
收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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