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

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

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介
+ B" q) B- A7 X( FAT24C01/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篇。. D" Q% T( q$ Z) \3 T2 D

# t/ G. S' J: h! K

' \* M! S1 r5 b& V二、AT24C02引脚

/ U- ]! d$ E2 e5 h7 T# U8 I* O* M) c$ q* n5 d% n2 u2 A% N
2 m1 o; M. _( S& R3 J7 M
微信图片_20231023203334.png
4 m7 m$ J9 Z+ y: w
AT24C02引脚定义

  p" h. G3 x2 w& X% u

/ r8 j# P$ n) `$ e+ _
. @3 r, ?& Z2 O8 }
三、AT24C02寻址
7 H3 c2 X# d: C6 ?& f9 I; O) L
使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。& p0 u( e+ h' C4 Y7 |
; E. }0 E5 V5 n  P
微信图片_20231023203357.png

' {5 J/ I, z, K+ G" ]! J3 C7 V! s
AT24C02地址信息
4 l% {0 G! a/ |2 y& x- Q8 {  l6 I
2 R! b; V  y6 n+ {% J( D1 D
, g- n6 s2 t8 y* V3 l/ B( G7 B0 \
器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。/ T: X7 o9 n# W( H

) W& v3 a5 {5 ^0 Y2 ~9 C6 Y0 ?四、AT24C02读/写操作
3 F' p& U& I0 ?) e- Q8 S" ?% {' V! s4.1 AT24C02写操作
. o$ n8 R8 O: G1 S, G0 _& |
写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下$ i6 [) g; t. P

6 y( H7 W/ P& m, [. C5 K' e1 P
) Y5 O+ Z7 e8 k' G8 N$ ~
微信图片_20231023203352.png

# a+ c0 Y. Z! j" x$ q
写操作时序图
% ]; Y% ]! A" B: t$ V& E
/ m1 D* ]( F) Q' X
* z; b; m: x1 U; u% `8 S, S, b: e' D
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。
8 m+ N. F" I/ ^6 b! L: o7 U
1 Q5 D/ ]" {3 Y0 `
接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。0 T" \4 ^" \" T" l% w  ~" B; x- A% n
  @& L6 n' p) T: E6 `
, S; R' i1 ]) h) v
4.2 AT24C02读操作
: K. X9 g6 Y. ^, C7 E7 J
AT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。
" I! x* e1 t$ j+ J9 R1 e6 U• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下
$ Q& W; b5 b7 {& A: ?, K1 o: K" |) L' Y) j$ I6 \4 B% u! _5 d

% O* U$ @8 r2 {
微信图片_20231023203350.png
  l% A/ B. E* B- {+ e; l
读当前地址时序图

3 a& u5 @: d0 B$ U/ n2 y2 Q

( f5 H' n1 W3 b2 G8 ~$ i4 S! L/ o
2 ^; ]2 s# ^# ^5 T$ b
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下' o: h" `/ Z3 x& }4 L" L

* u- z- b. G/ t/ V! t, V& F* ?; W

3 l9 |$ `7 ^; t% j" s! l) f6 F
微信图片_20231023203347.png
) ^0 [+ p0 U4 _5 q% D7 j: [
随机读时序图

- }5 W# @! G; i7 C: K, l
* T. G4 R' _0 ?0 c( r
/ Z9 q5 w7 L& Z6 Y7 o% {. G4 b2 m$ F

; h7 d& _8 V$ j1 J2 K4 g• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下1 A# K& i6 I# f+ F5 R! B) e: W

* O# y$ o. ^% u3 ?+ w% W

  b7 Y2 e( g- [* _1 q+ O
微信图片_20231023203342.png
6 g7 u0 _3 B9 m  r; i
顺序读时序图
! n5 C# j& Z( a9 M4 ~" k
0 J) `9 |9 }+ p

/ r7 s0 V+ Z; n; q9 i& v
五、AT24C02程序
( b3 I$ G2 V- w1 E& k这里给出一个AT24C02的程序,仅供参考8 W3 c5 N4 ?0 [/ M4 T. \9 o
  1. /*******************************************************************************
    ' X. @( ^$ d5 }% A! r" {* n3 j
  2. * 函 数 名         : IIC_Init
    7 `9 k& _# }2 O+ m
  3. * 函数功能     : IIC初始化
    % C5 M4 l  Z; e( j2 T+ U
  4. * 输    入         : 无1 Z: g  J3 C1 X+ b# `
  5. * 输    出         : 无0 x& ]% w7 H$ n$ i" U& i$ g
  6. *******************************************************************************/1 P# D" v& Y" I7 P& G8 D
  7. void IIC_Init(void)5 a" |2 l2 Z1 k2 j0 }, F, \
  8. {
    ' o; G$ A9 a  A& t2 X
  9.     GPIO_InitTypeDef  GPIO_InitStructure;
    / x* ?# H' e3 e# \: V  @  W) g
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
    ! u/ W- v6 ~$ k+ s/ a2 b: {3 M2 K; d
  11.     ; d' e6 u+ K( }* k+ i# @$ E& q$ Y
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;$ H# Q; ]3 X. V2 D( M$ M
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;' C) e* M  ~6 W* [4 W) ^8 i$ }; [$ @
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    : j" V% y! u/ c8 k
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);) \* [0 U+ U3 R5 D0 E
  16.    
    9 X; B8 a1 c& a/ x
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;! D. S  T- w" K. Q0 T& a  R; ^
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    ! O7 L; u( u* M& }& Q/ p
  19.     & h2 h6 M+ X0 F6 x# H
  20.     IIC_SCL=1;7 e( U; s5 z8 }0 z: s4 w- P
  21.     IIC_SDA=1;
    0 T6 l$ V3 i5 X- g  c! }( d
  22. }: Q& y+ \* _- t
  23. /*******************************************************************************
    # x$ v, @7 X4 Q9 f6 E4 b1 @
  24. * 函 数 名         : SDA_OUT
    , V0 ?; Z7 L& I4 f6 W* n
  25. * 函数功能     : SDA输出配置   
    . v3 r" s/ }% p& o% D9 b
  26. * 输    入         : 无
    7 I+ X, ^  \/ m2 A6 g' @% ]
  27. * 输    出         : 无
    / u/ M' G- R/ w
  28. *******************************************************************************/! |) `9 c/ [: x! ^' S: I# ]  }
  29. void SDA_OUT(void)
    $ K* D" T' e' u4 i4 i# r9 R
  30. {
    9 a) q: \$ G( F! f
  31.     GPIO_InitTypeDef  GPIO_InitStructure;7 W5 C) e9 ^3 |) [: j
  32.    
    : o* ]: ]" |- H) K/ M
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;# Z9 S/ J* Y8 b/ }- H& c3 o
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;0 t9 d$ D. G0 V1 d1 u
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
      I& f; i0 {( t7 L
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    8 I0 e3 m8 S% v: C3 K
  37. }: F5 c3 r8 a- I) x* s! T6 h7 }) z

  38. . A$ }# ]3 ~- k) r; R
  39. /*******************************************************************************, v( ?: I- W# l- n1 t) m, @9 S$ }7 l
  40. * 函 数 名         : SDA_IN# X% N* m& F& \7 U6 g9 Z
  41. * 函数功能     : SDA输入配置   
    6 D6 h0 b) M5 k! n% Z
  42. * 输    入         : 无) e8 ~( L1 ^- i/ O$ D- V- o
  43. * 输    出         : 无
    3 x3 @' d% E9 r: V1 t7 o; [
  44. *******************************************************************************/
    6 }9 f( e+ W# @/ {7 K6 `4 d
  45. void SDA_IN(void)
    5 }7 N* B* k) k; i% u
  46. {* H0 t1 h5 `, z& I0 G% H$ L
  47.     GPIO_InitTypeDef  GPIO_InitStructure;
    $ b& U. n1 |6 D3 o# ^$ c9 ~
  48.     3 C  b1 g* d0 C6 S: D; Q
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;5 h' C0 g( j7 s) ]. R& v( |$ N- W
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;4 B: L( p2 T  g2 s+ D
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
    " `( Y" r; @% M9 ~# J% p8 }
  52. }
    " ?8 r3 z! [5 I7 H

  53. 9 |  a! z6 a5 w8 s
  54. /*******************************************************************************  H6 @  v$ C( b7 O' G
  55. * 函 数 名         : IIC_Start
    & k& g. e, }. A& ?/ s7 b+ E" e
  56. * 函数功能     : 产生IIC起始信号   
    5 P0 Z+ p( l: o3 d8 [, |
  57. * 输    入         : 无
    8 n2 |) j1 p+ T3 k$ E& L4 c
  58. * 输    出         : 无! I! c; E: l) X
  59. *******************************************************************************/2 f5 R0 R% Y# ?/ c2 {2 S, r7 `' p
  60. void IIC_Start(void)
    1 ?1 J8 p1 A- W- v
  61. {
    ; T0 m2 K+ @7 H  h
  62.     SDA_OUT();     //sda线输出
    9 m) I( N8 z, i3 W
  63.     IIC_SDA=1;      
    1 E& I* e5 p" L  m
  64.     IIC_SCL=1;
    2 Y0 U  V% J5 S# i; v% ]% ^2 h
  65.     delay_us(5);
    # K3 t5 L5 Z1 E$ {+ h, \
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low
    - g7 r( ~5 a" a$ D/ d% |3 z5 G
  67.     delay_us(6);
    / ]8 Y7 r% C: f1 i
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
    ' Z/ d# S) `% `
  69. } # C- P9 N; t2 E2 V* e' E) y
  70. , J% ^1 P( T, g- e, W
  71. /******************************************************************************** b" e7 N% k% d, \5 i' {% H# q! ~' t4 t
  72. * 函 数 名         : IIC_Stop3 S+ K) G- K" |' D( r' P
  73. * 函数功能     : 产生IIC停止信号   ' z! y- }# t0 X4 I- R
  74. * 输    入         : 无
    ) l0 n6 o8 @, i: ]& W
  75. * 输    出         : 无5 k( \5 ~" O( q8 w
  76. *******************************************************************************/; A" p% i5 u2 \: K9 R" k
  77. void IIC_Stop(void)
    0 _+ [6 |3 Z! I/ K; C+ N1 M
  78. {
    ! K' D% O% K  F8 r( s
  79.     SDA_OUT();//sda线输出) @: h) G: X2 d# b
  80.     IIC_SCL=0;1 Q# s$ c' X8 ~  C6 N
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high' }7 A! h2 K' g; ~9 O7 O0 ?  @
  82.      IIC_SCL=1;
    5 B. K: x4 }5 }% ~
  83.     delay_us(6); * o1 S$ `/ F" g5 t1 ?
  84.     IIC_SDA=1;//发送I2C总线结束信号2 K3 i( r. E  q- T& F8 e0 N
  85.     delay_us(6);           
    ) T4 O6 v! G% e: `7 Z
  86. }
    ' G. l0 b& {. [6 k: L4 D

  87. 7 n' f( K( `% o( V
  88. /*******************************************************************************
    0 A" i  Q1 r: f' B5 g
  89. * 函 数 名         : IIC_Wait_Ack2 k/ p' W& J9 @8 R
  90. * 函数功能     : 等待应答信号到来   
    ; D, G0 f7 i. x4 I
  91. * 输    入         : 无  D" x! B+ Q3 W, f
  92. * 输    出         : 1,接收应答失败
      c3 n8 Q* I3 S5 I. E
  93.                      0,接收应答成功
    7 p2 }. T, a% ^! y' E3 Q
  94. *******************************************************************************/
    9 b6 V+ ^& Y  f0 p" T8 W
  95. u8 IIC_Wait_Ack(void)
    2 [7 U5 X5 X) F" ?% E# e
  96. {8 o5 {1 Q6 }$ O7 x  u. \! m( x9 f
  97.     u8 tempTime=0;( Y9 K$ i2 S" m5 H4 l2 e
  98.     SDA_IN();      //SDA设置为输入  
    2 Q3 u$ c  `, s
  99.     IIC_SDA=1;7 a+ W: b/ H8 j
  100.     delay_us(1);      X! r4 P: R: y9 p) U: Y
  101.     IIC_SCL=1;
    6 `) g4 _( x2 S; O' K! i! R9 `
  102.     delay_us(1);  
    & Q9 Q: p4 G! ]$ f3 @7 v& y& Y' G
  103.     while(READ_SDA)" N) r8 L0 l# x9 n5 K
  104.     {) v% R; z" W, T# k) j( l
  105.         tempTime++;8 a0 Y- B8 j3 v& y. _
  106.         if(tempTime>250), s; \0 ^2 R3 \; _
  107.         {
    , B' N; M" z9 i: ~  ?! K& W
  108.             IIC_Stop();
    ! I/ m7 `# _5 J# j* V9 M/ v
  109.             return 1;6 F( h- `  ?0 k  B
  110.         }
    ' B. P# o$ o: i' J; t2 l7 D6 C
  111.     }
    $ A$ f! X# A1 b
  112.     IIC_SCL=0;//时钟输出0     
    ' {, @; I* o! r6 w8 l# q2 g
  113.     return 0;  . }) n" N* F: k* C, ?; A
  114. }
    ; v# ]3 Q: B9 o  q$ [
  115. 3 N; P' g4 i' }; N" q
  116. /*******************************************************************************% c4 r) O- E, l! O9 i8 P, D/ A
  117. * 函 数 名         : IIC_Ack( ~3 h  o! h- H2 n& }
  118. * 函数功能     : 产生ACK应答  
    " e% s0 B! X0 i7 L9 S
  119. * 输    入         : 无
    * J& [6 {; |8 |- v3 K. P
  120. * 输    出         : 无
    0 J+ f0 n* d% D2 W3 I( L
  121. *******************************************************************************/% \6 H* I# N) L
  122. void IIC_Ack(void)) h& x- Z% L1 y9 i- _- h8 ~
  123. {
    8 Z! R# N9 y! Z, P1 W) n3 O% G
  124.     IIC_SCL=0;
    ( [" T+ g. }( S
  125.     SDA_OUT();/ x$ n* }% Z4 O' b
  126.     IIC_SDA=0;6 F' ~0 x9 U0 @; W7 z9 P+ F0 g
  127.     delay_us(2);
    5 j0 h; ~; Z& `; W; K+ F
  128.     IIC_SCL=1;
    9 x0 o* g/ w1 H7 f% m
  129.     delay_us(5);( B+ V. J) R' |# @) H
  130.     IIC_SCL=0;
    / C- L( p" e  a2 S
  131. }
    ; F+ g0 C3 q9 K- Y

  132. 3 ]1 j) \, s8 H2 U: d" U
  133. /*******************************************************************************
    ! k+ g9 r8 I: ^3 M3 A
  134. * 函 数 名         : IIC_NAck
    3 y( F, B9 Y9 s1 O$ p  M
  135. * 函数功能     : 产生NACK非应答  
      Y! K& o. h) u- [+ z
  136. * 输    入         : 无! K; O* b, L4 e+ t
  137. * 输    出         : 无
    ' {; g- i4 n7 K1 H; W* n
  138. *******************************************************************************/      : b& m" i6 D* m8 V. N( Q
  139. void IIC_NAck(void)
    ) D8 a* x5 S0 u3 }9 `% @  [# y; O
  140. {
    3 h1 _) T  D- I. P
  141.     IIC_SCL=0;
    * A- }8 ~% I1 U) Y& K
  142.     SDA_OUT();
    2 M: U) X0 [7 d3 E1 o7 X
  143.     IIC_SDA=1;
    3 y7 ~0 ^0 I, b# U
  144.     delay_us(2);8 l/ ~% B* T9 B  D8 T9 ?
  145.     IIC_SCL=1;
    0 l3 k- {9 y) s: F$ q7 t
  146.     delay_us(5);. P+ z& {6 j$ g  o& e  k# i& D
  147.     IIC_SCL=0;+ _, G/ b/ k! @4 J9 o9 M( k: Y
  148. } 7 _, h8 w& m6 p

  149. * r* q0 z; g. M: C4 j5 I* c
  150. /*******************************************************************************
    # s5 y; w% R2 f0 J9 F
  151. * 函 数 名         : IIC_Send_Byte
    . O$ x% ^, F% i, A4 p
  152. * 函数功能     : IIC发送一个字节
    5 b, {; t! J# v, N% r9 n
  153. * 输    入         : txd:发送一个字节
    6 t! Z" c" O1 l- v
  154. * 输    出         : 无! r3 r0 {9 y8 U2 N8 h
  155. *******************************************************************************/    4 i. f/ l. T% b, q
  156. void IIC_Send_Byte(u8 txd)
      F: Y0 U  Y  s+ ]: g# ^
  157. {                        
    5 V/ D4 o% C/ A# ]: W2 I$ f5 G9 W
  158.     u8 t;   
    : B9 X  [: O2 |* f
  159.     SDA_OUT();      $ F9 g) j) F. V8 W7 B* ?! _/ N
  160.     IIC_SCL=0;//拉低时钟开始数据传输0 }3 C0 ^" E- B
  161.     for(t=0;t<8;t++)
    . V" e! L9 m- m+ `! c* n6 `
  162.     {              ; e2 |) ?( J0 q: a! b
  163.         if((txd&0x80)>0) //0x80  1000 0000; H9 I( V7 W7 v( C3 A/ ^
  164.             IIC_SDA=1;
    % R7 |* ^1 {% m  ?4 a# O
  165.         else
    ! r: g" s7 H7 b
  166.             IIC_SDA=0;$ r4 _& u& r9 w5 |+ f
  167.         txd<<=1;    ' M) `) o  d2 O1 v6 F  q" I
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的# `/ ^3 |4 N/ y1 A( A! w: G
  169.         IIC_SCL=1;
    ! Y; u* N' H" k8 N7 @- @4 p
  170.         delay_us(2); 4 g4 T7 R- @  ?8 ~! f" |4 @* m) x8 _4 \
  171.         IIC_SCL=0;
    ! c  d+ n( r. S) p
  172.         delay_us(2);
    , r) T( k. D4 j1 D/ C
  173.     }  8 ^& B& z' {% i. k
  174. } $ l* N( N" F& T. ?' E0 g9 w; E( G
  175. 0 \9 v9 \- o) f) {, v- M
  176. /*******************************************************************************
    , p1 z! G, Q4 B% ]+ m
  177. * 函 数 名         : IIC_Read_Byte
    ; i7 J3 A7 _9 q- P
  178. * 函数功能     : IIC读一个字节 6 r3 k5 s% u, J$ ?/ e
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK " u6 Y  p4 ?5 @, O$ E2 w7 k2 K
  180. * 输    出         : 应答或非应答6 f7 Y& n$ F; Y: \6 t1 L0 }
  181. *******************************************************************************/  
    ( ^5 g2 K6 ~. a  C# ^
  182. u8 IIC_Read_Byte(u8 ack)2 O# r+ O; t4 m
  183. {& c4 s+ y- i; F8 q" D
  184.     u8 i,receive=0;9 s9 R2 X5 h6 ?& e, ?* ~% I3 R" A& L
  185.     SDA_IN();//SDA设置为输入  n' t$ ?. c  O! j+ k; q. @
  186.     for(i=0;i<8;i++ )
    : B0 l( x5 U2 Z- y" S
  187.     {
    8 X( e; c. m9 w% Z5 @
  188.         IIC_SCL=0;
    " P/ T( `" i* m, r9 C% r$ L
  189.         delay_us(2);
    + C  D& M* W2 X: J
  190.         IIC_SCL=1;8 q2 p9 B. U: P0 A2 l- h
  191.         receive<<=1;2 S/ S* k4 ~# |4 e2 a3 v+ A  u4 N
  192.         if(READ_SDA)receive++;   6 M0 b# u8 e9 _+ Z- G9 x
  193.         delay_us(1); ; ^4 H5 r- ]) S2 o4 {- k; q# x8 O
  194.     }      ) W: k& Z  r+ G8 d1 B# y
  195.     if (!ack)2 E5 K2 O6 l" Z: d( g5 o
  196.         IIC_NAck();//发送nACK
      b; @' w# j/ Y8 {! g* F" K; m
  197.     else! @( b1 ]" @- N& r4 ~
  198.         IIC_Ack(); //发送ACK   7 |! T; e9 j. @& W
  199.     return receive;* u: c7 V) R6 S5 W; O  R
  200. }
    $ `) K1 O  a1 d
  201. /*******************************************************************************
    1 U8 k- k7 ^0 Z" d5 M
  202. * 函 数 名         : AT24CXX_Init  \$ G* ~8 l8 }$ b2 f1 l% A) u
  203. * 函数功能     : AT24CXX初始化
      I& R: \' B. P; a
  204. * 输    入         : 无  R. }/ J& J3 K5 e
  205. * 输    出         : 无
    + Y6 X# y# Q( U, S) e  D
  206. *******************************************************************************/
    * V' e! j+ @$ d( l
  207. void AT24CXX_Init(void)
    ; |3 i: @% F7 i6 N
  208. {
    $ ]. A) M1 l" a& n( J
  209.     IIC_Init();//IIC初始化
    8 f# m5 ~+ m+ M. B* Z, ^) T, r4 e
  210. }% X0 j3 h1 x/ G" H8 Y

  211. ( H9 i8 C" K& n8 \7 e' Z( k6 A
  212. /*******************************************************************************$ v6 w5 u6 A7 B6 G
  213. * 函 数 名         : AT24CXX_ReadOneByte3 A& {9 T6 F/ w0 f" `5 B+ G
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据
    + {; m7 H" C% |& e4 K3 F
  215. * 输    入         : ReadAddr:开始读数的地址 - z6 v% y  l- o5 v% c& E
  216. * 输    出         : 读到的数据
    ' j% ?, f3 ?/ R) m5 D
  217. *******************************************************************************/0 F2 r% s; e: J+ O
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr)
    ! E% \' n5 n" U5 K$ z
  219. {      
    4 [$ B" E6 L) \
  220.     u8 temp=0;                          % E9 B4 x  j0 X( z! V
  221.     IIC_Start();  ! O) y" b6 M) U8 g/ L
  222.     if(EE_TYPE>AT24C16)
    ( b0 {. h0 q. o; u9 O
  223.     {$ b$ i. N5 h5 a. B. C1 b" K
  224.         IIC_Send_Byte(0XA0);    //发送写命令
    3 t4 {4 F' x, b; A
  225.         IIC_Wait_Ack();0 d, H/ _, x2 f) S1 X
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     
    0 M1 [" M, |: ~* q2 ?' g
  227.     }" |7 @" B* z% x- `
  228.     else 9 Y% s- T/ A9 B
  229.     {1 ^# @$ S$ H& b# h: d
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据
    6 J4 h# I$ \1 M" \* I' R' @
  231.     }     
    1 D6 x0 T0 B* m- t1 c
  232.     IIC_Wait_Ack(); 9 d  x2 }. V) l. C  f; w8 Y
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址
    ( m( \! ^, V( E1 R
  234.     IIC_Wait_Ack();     # u& M6 d& \! q) i5 j& j
  235.     IIC_Start();        
    ! r2 _; o8 q0 ^: t& {/ P) q
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      8 i4 O8 D0 U8 O0 O
  237.     IIC_Wait_Ack();  
    " F$ Q( O* R* d0 X2 n1 F1 P; Z
  238.     temp=IIC_Read_Byte(0);     # w, T% L; i& V$ H
  239.     IIC_Stop();//产生一个停止条件     
    9 o# w3 \. G- E. N
  240.     return temp;0 c: o5 R( @5 e/ N
  241. }
    * l# R( m! M; @$ i, r2 W

  242. . @" A# Q- W+ ~" B
  243. /******************************************************************************** u. @$ {. U# S: Q5 A  f6 N1 B* K
  244. * 函 数 名         : AT24CXX_WriteOneByte: R: L& l& E' F# Q  q
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据4 L. l( H; S* D9 Z- `& A9 T
  246. * 输    入         : WriteAddr  :写入数据的目的地址 ) K8 f+ ]* Z& |* |
  247.                      DataToWrite:要写入的数据
    8 q: p; t# G" L' G  ]! g) q
  248. * 输    出         : 无
    $ o7 u4 y% \8 t0 i5 m0 j) @* j
  249. *******************************************************************************/( A2 I- n( n6 F
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite): R) y% J2 X) ^( ]
  251. {                                " b7 \3 d" E5 n" O
  252.     IIC_Start();  $ F5 j. ^! E2 A' j* A
  253.     if(EE_TYPE>AT24C16)
    $ l4 A/ v1 b* C( {
  254.     {
    # y) V; b7 P7 P: `& v
  255.         IIC_Send_Byte(0XA0);     //发送写命令
    7 f) s$ P: d6 U7 O  I
  256.         IIC_Wait_Ack();( v0 I: n. E  \
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   
    * j$ O4 e4 J0 G3 P5 C7 l
  258.     }
      Q( [0 O. R2 H5 b/ R
  259.     else
    # t1 l' [5 N+ A5 E7 R
  260.     {
    ' F4 E8 F' p% w% Z' @8 H
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
    ( M' }) U4 h# h% V( `4 [! I0 V8 h- _
  262.     }   
    8 _7 k% Q+ s, ?/ r% ~; m( n
  263.     IIC_Wait_Ack();    + u) S9 M6 C  g$ Y' ]
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址
    % G; t6 C' A% p$ f1 M8 @9 k) ?
  265.     IIC_Wait_Ack();                    ! E8 [! \/ L8 Y8 N) D
  266.     IIC_Send_Byte(DataToWrite);     //发送字节         
    7 e+ Y$ {0 r& a8 {
  267.     IIC_Wait_Ack();            
    : p/ ~. E0 F" T: i: v) K, L
  268.     IIC_Stop();//产生一个停止条件
    - G/ v1 I7 Q" W' K
  269.     delay_ms(10);  " ^; h8 w- L+ q. @" \7 n3 R
  270. }& r& k9 @- D( }9 r
  271. % P- N: X+ L: A- ~1 `
  272. /*******************************************************************************! q* N" q8 R: [) }; w; Y4 `$ f
  273. * 函 数 名         : AT24CXX_WriteLenByte3 P6 b' P5 z0 N( u' Y. v
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据9 |4 _6 L0 O$ P: N4 X! j' B( H
  275.                      用于写入16bit或者32bit的数据
    6 H$ @( N5 u4 N, Q
  276. * 输    入         : WriteAddr  :写入数据的目的地址
    1 ^) }/ |% v* x+ p# s8 E8 e
  277.                      DataToWrite:要写入的数据2 V8 L/ c4 g5 K& R& Q9 m# J
  278.                      Len        :要写入数据的长度2,4
    , L1 H: Y( n; [" z  w
  279. * 输    出         : 无3 t* D# B* |! C) O9 l
  280. *******************************************************************************/# d2 W+ b& c/ p( ~& {/ v5 k
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
      D7 o, x6 ^9 v- ]
  282. {   
      z0 }' W( V# l( O) v
  283.     u8 t;
    : c$ w; E9 [- x3 S- V1 x4 |* z9 G  a
  284.     for(t=0;t<Len;t++). a! S* U: ~+ f
  285.     {
    ( h. d3 x; }# m0 X$ c5 t
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);, Z% E6 H: j6 M6 K4 U  b: z' a
  287.     }                ( j8 E" @& T1 W/ p
  288. }
    8 h# m! M3 _! v, D  r* ]

  289. ( a' ?7 P- K5 T% @( t3 X. n5 \- ~
  290. /*******************************************************************************
    ( Q& h7 ]% R5 I( N
  291. * 函 数 名         : AT24CXX_ReadLenByte/ H' K9 G& R. v/ w. U, _) {5 f
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据; [) T) e3 {8 m2 ~( n2 \
  293.                      用于读出16bit或者32bit的数据
    ) y4 I5 f' c0 w- m  n8 N
  294. * 输    入         : ReadAddr   :开始读出的地址
    * j) \6 M& [3 ~% _' D3 n8 w6 @
  295.                      Len        :要读出数据的长度2,47 ?7 s, ]& a2 T
  296. * 输    出         : 读取的数据
    9 I! \1 H9 K8 ^
  297. *******************************************************************************/
    7 n$ I3 R' e$ a2 M
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
    , G& h) _5 T/ R0 n: R2 L0 u; _
  299. {   
    - b6 P/ G" O% F- y
  300.     u8 t;7 \8 \3 q% ^9 z4 w6 J, v% _
  301.     u32 temp=0;. a# l% w( c+ h" K$ h5 R* a
  302.     for(t=0;t<Len;t++)1 Q, u: l9 p( \3 j. D& ]/ @
  303.     {( s: `0 u" u# ]( t8 _
  304.         temp<<=8;# V" ]2 _! o5 z% E9 q8 }; ^* C
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);         
    5 Y/ F0 n  U; B. L8 g
  306.     }2 L) n( }. \8 q, e+ s; T
  307.     return temp;                / i' G- z' f9 V( z
  308. }* Z- E' p* _9 S! B! A' X" x

  309. & K# S7 m! U7 z1 P" ]
  310. /*******************************************************************************' i) x/ N% C$ E& N) @
  311. * 函 数 名         : AT24CXX_Check
    ) c+ o: O1 ~$ {
  312. * 函数功能     : 检查AT24CXX是否正常' c& p7 E" |% ?3 n: `
  313. * 输    入         : 无: }% D' Y9 m+ H* ?' s
  314. * 输    出         : 1:检测失败,0:检测成功
    $ U  y6 T7 [: w$ a$ A( j7 m
  315. *******************************************************************************/
    % Z1 ?- p' x  B. T1 E
  316. u8 AT24CXX_Check(void)! N# m1 c% k0 p9 a' s& H
  317. {% q! E7 I& @: f7 c9 d, U+ I
  318.     u8 temp;
    . J" r2 f" C/ q3 O" h
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      
    # F% S" r) e* I/ N
  320.     if(temp==0x36)return 0;     ) K1 N! [( }) b$ H5 `
  321.     else//排除第一次初始化的情况& |) D, ]3 h2 @+ u* b3 Q1 O% f
  322.     {$ ]  B  o* \: ]) |
  323.         AT24CXX_WriteOneByte(255,0X36);/ Q6 `8 ~6 p* C
  324.         temp=AT24CXX_ReadOneByte(255);   ; V4 i$ e  J- b- f  Z( O
  325.         if(temp==0X36)return 0;
    , V+ H9 [& A" G4 Y' F, p
  326.     }
    + N9 z% n: a/ [; _7 a2 g( t
  327.     return 1;             2 w( u/ L% M! a' x
  328. }
    & ?3 b# V7 u- u8 g6 S4 J

  329. 2 f7 n7 p' Y9 z+ I! ?
  330. /*******************************************************************************0 @8 K5 u: m5 }1 |# y7 {
  331. * 函 数 名         : AT24CXX_Read
    + R4 ]: H, D  X' n* [) {
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据; j: y7 M" f. S
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255
    ) q& n$ R8 L. x' Q, a; X- x$ Y& W& t
  334.                      pBuffer  :数据数组首地址5 |- Q/ N5 ]: t2 U) |
  335.                      NumToRead:要读出数据的个数
    4 I# s" k  m; H5 t* H
  336. * 输    出         : 无
    + ], J4 X0 A8 Y
  337. *******************************************************************************/
    ) u$ N0 A' K, M; f
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)1 J9 T/ h/ b& k1 F
  339. {/ T3 n1 N6 z( o( M7 S  q) K
  340.     while(NumToRead)8 d0 c, E+ C( o. B- ^6 q/ |
  341.     {
    + L. e- L" Z8 `, G8 g1 E$ P! x
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    % [0 J  T+ B4 Z+ A
  343.         NumToRead--;3 C& x% e0 C4 |6 G3 h8 f4 m
  344.     }
    ; Q) v! Q3 v( d
  345. }
    $ n+ Q+ g" Q7 X7 {
  346. ! V! j' Q) R5 t7 j0 `+ S  Y) C
  347. /******************************************************************************** q! L3 R) I* E# d( c0 V
  348. * 函 数 名         : AT24CXX_Write
    * ~! L8 [% c3 ^# U! y- z
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据. F6 N) V. ^1 U
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~255
    1 o! L! R- a5 k$ O$ T% ?
  351.                      pBuffer  :数据数组首地址1 ^5 C% j, z4 |$ a; Y9 Q% J+ y
  352.                      NumToRead:要读出数据的个数
    ( y$ _! h8 Z( g4 E5 [' M
  353. * 输    出         : 无
    : O" f, ]. a1 k4 J: c
  354. *******************************************************************************/
    , X  q) W6 z5 q, _6 N- {, c7 u
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite); N' c& _& |% F. B3 Q) t& g' y
  356. {% y+ o9 h# U+ k
  357.     while(NumToWrite--)! {7 e2 `+ |8 C/ @, P
  358.     {
    # W/ c3 f, Q' R* j; S
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    + I5 x/ Q' ^* }) t
  360.         WriteAddr++;
    8 }; o7 q& F- P
  361.         pBuffer++;+ c8 A. _: }: X5 s% J
  362.     }
    6 c, f7 }  b9 s. ]0 G; f: ]
  363. }. z+ G2 v4 F. ?& _" Y) p
  364. .h文件如下5 _/ o5 r5 Z# {
  365. 0 U) W! Z; E: Y/ ?
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C02
    * [# Q9 P* e2 Y0 _+ [0 o; ^
  367. // 可修改成AT24CXX系列中的任意一个
    " }! u  d4 z' i) T
  368. #define EE_TYPE   AT24C027 a6 i) `9 z( T) ?

  369. - d; W2 D( _) w. r2 k" b. s0 Q
  370. // IIC函数
    1 F- V$ d4 P: t. {8 L
  371. void IIC_Init(void);   // 初始化IIC的IO口       E6 E- O6 n& \# \) a
  372. void IIC_Start(void);   // 发送IIC开始信号
    5 U. O2 N& R; \# ]' v2 P7 `
  373. void IIC_Stop(void);   // 发送IIC停止信号
    3 e+ j9 Z1 v, l7 [% K( V
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节& Z6 v: K+ z$ j8 f  O1 x
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节1 e) w5 z! }8 ~+ D0 N$ K0 D9 h
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号
    : L1 w5 B) r" c7 l8 ~; L8 _
  377. void IIC_Ack(void);   // IIC发送ACK信号
    1 }8 A5 I: {8 S4 J+ r' O- ]! A
  378. void IIC_NAck(void);   // IIC不发送ACK信号. c4 b6 s4 `- ^+ B7 `

  379. " a. ]1 o0 b  N+ K, f, ~* P. b& c
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节" o- Y- P! E+ `+ [+ I) l8 S
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节9 x9 i2 y9 D' e4 w/ Q1 C7 c
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据
    * f8 ?3 r. J  Z) I
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据) r0 Q0 [# }7 z  r2 W8 @
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据
    4 U6 M5 I3 n2 F5 D
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据, u9 q' o! C4 V0 N- \

  386. 8 B$ \" d2 i; m" i% R" Y0 O7 q
  387. u8 AT24CXX_Check(void);   // 检查器件9 {- Q. @3 Q' K/ x3 B+ F
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码
# c& [3 d% @7 V
六、应用实例' h  G3 D4 y% {! p
给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下
+ c+ c" U6 m- `5 O/ O. S- v
  1.     AT24CXX_Init();   // AT24C02初始化
    % D% r# V, z7 W- L% |! |. e
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常
      G3 [- O( u* w, M" r* j7 r
  3.     {. b) E" [$ L- G% q2 {0 J+ m
  4.         printf("AT24C02检测不正常!\r\n");
    , D* o0 v$ r- g- k8 N; w* r2 F0 @2 z
  5.         delay_ms(500);
    7 g$ m7 B- O5 [$ n2 Y9 c% n  T7 {* D: z
  6.     }- C2 e7 f$ v( b8 J5 T
  7.     printf("AT24C02检测正常!\r\n");
复制代码

6 a! J/ m' F2 m5 Hmain函数如下
% @4 v* z- q9 y! t
  1. u8 gWData = 0xaa;   // 准备要写入的数据- z% a8 h7 ^4 o* {7 K5 `# e
  2. u8 gRData = 0xaa;   // 存储读出的数据6 s! r6 l5 M: O
  3. 8 P! e4 j0 W. i) s
  4. int main(void)
    , J: I! r3 C: w( w+ |
  5. {
    ) P2 S  o' |7 t, Y
  6.     Med_Mcu_Iint();   // 系统初始化+ M5 H! w/ @; H, _5 j) ]  t# l
  7.    
    ! K* H6 J1 w" c: i1 |* b' s; z. @! ?
  8.     AT24CXX_WriteOneByte(0,gWData);7 S- f2 x9 h( Z. N( H
  9.     printf("写入的数据是:%d\r\n",gWData);
    $ |# O* o+ O1 r/ B+ c; b
  10.     & `7 z" E4 l) b  a
  11.     gRData = AT24CXX_ReadOneByte(0);- c7 b6 ?2 z! ^5 Y$ U2 Z
  12.     printf("读取的数据是:%d\r\n",gRData);
    3 Q0 {& A7 H- P+ {6 ?% q
  13.    
    * U8 M7 A9 n# |
  14.     while(1). V4 r( t7 D" [
  15.   {* @" ^+ p4 s6 w/ O6 S
  16.     }
    0 d: A2 I0 |6 A) |1 r
  17. }
复制代码
  q, _: M# J% L! Y# @# b+ a$ H! f
串口打印结果如下: d( a1 H- H5 Q9 m4 i

" s+ F, \2 f% }$ p; ?# J% v* I  y5 H$ d
+ H' C# A7 A) @& C" n; V
串口打印结果
# B% [' [# r: |& `% Z: W- D
, y9 {$ Y3 \2 Z0 j" W3 M
% i9 p" C$ S; l; C: g; u2 O; g9 C
七、拓展应用4 |4 u2 ~* K: I. ]- S% ~- M
AT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。! T' I4 c- V' W

. J, _  x0 [( L! R: D% G% z2 ]+ b4 t# E; z6 Z% ^
" @; u: e! Q# ]8 M
转载自: 二土电子3 ?+ E! X! |  G+ o$ }$ C
如有侵权请联系删除
( R" z  y. g0 O5 O8 H1 Z6 x
9 Y/ w9 ?5 U: V) s
微信图片_20231023203400.png
赞 收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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