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

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

[复制链接]
攻城狮Melo 发布时间:2023-10-23 20:34
一、AT24C02简介
. y0 ~/ b) e' j. yAT24C01/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篇。  ~# I* y; U7 ?3 H/ a  b* W
, d5 c5 d4 f" J  V, A- r- F

2 t7 J0 z/ J1 {7 Q* |3 d二、AT24C02引脚
* S, s4 a  q' z5 z6 q8 b. ~* \

. G4 E0 b- S+ i' t0 W' F6 G$ Y' E" g7 X7 K
微信图片_20231023203334.png
3 z+ C; H6 e7 ]! w* c
AT24C02引脚定义
% C3 s; j+ y- _' y* x( j! D
' H  L/ b- m+ a8 j1 Y; y

( q! ^7 {) K8 L三、AT24C02寻址

' w. B) I4 y- O) [2 Q$ g使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。1 F1 R- S9 ^! Z! E

' D% R2 l! h. w: o1 x7 T
微信图片_20231023203357.png
1 ^! ~: c% H5 Q. P
AT24C02地址信息

/ h! q5 O1 K' V) W

1 r5 |; |7 N9 v) a
% n4 I1 T/ X. H; v) i
器件地址信息由"1"、"0"序列组成,前4位对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2、A1和A0为器件地址位,必须与硬件输入引脚保持一致。
$ ^$ L  G# c  I( t" _0 H( C/ r" o! Q! c) M( R
四、AT24C02读/写操作
6 P7 I; @$ z% u3 w- t4.1 AT24C02写操作

! h+ ]: J# I2 h1 \3 f写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下
7 k$ P  m) @# H7 w) f! m
2 |  p$ Q) }, E( q% o
5 `) f9 N$ C1 R
微信图片_20231023203352.png
3 N- k% e! \/ @" t* S
写操作时序图
. y( {( j) A, b

7 T& v0 Z$ M" v. I5 ^+ i
: G8 J; M* T, W& L4 m% S/ R) b
24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。& f3 G: |9 f- k7 c$ {9 J

0 a- @5 T! |% w, _3 g! o8 ?接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。
3 }% s9 W+ b* _+ d( z- X: E1 _+ `% @9 c& e# W3 |# C4 h" P: G& b

) c! w+ i+ J. N3 ~: F# i4.2 AT24C02读操作
: |2 C" D/ E) W6 ~. L: `3 |
AT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。
; G, \: j4 v) J1 C$ s2 }' g• 当前地址读 内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下2 ]) u9 q' R! K6 m: a8 k- p

: S8 E3 b* U. t2 J2 U' V( b0 h
4 n/ q8 V; o- f
微信图片_20231023203350.png

# u" B7 I7 e, u5 w8 ^
读当前地址时序图

! l. n6 D0 v; C6 t% `+ Z0 G
. d% ^8 O, t; C# y3 H4 K
( P, n1 ~8 T( q0 V
• 随机读 随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下3 w! o- a3 j7 X9 w4 k  l

* W0 X) [$ w8 c7 P% }; X, R% ~
3 m6 S* |$ {+ g& x+ U5 ^0 E( V0 P
微信图片_20231023203347.png

0 R5 f& x# e( o5 t$ J: g* c
随机读时序图
, G; r; l) E7 g
- e* J8 i3 r1 E$ W" |! l
1 E! n/ d! }0 x
' k2 R2 B3 Z  f
• 顺序读 顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下
, `( l* ?# t0 L! ?: N5 |. F& N; S: c0 K/ m4 U. I

( S. b8 I' b8 i9 T* Y
微信图片_20231023203342.png
1 Q& d0 D6 c$ X+ I1 \- h, J5 s
顺序读时序图

+ _7 u9 V' z/ [& A0 w2 g# Y: w
% u6 B; G( k* ^7 L* y' \

/ B1 ^/ i$ y  y" c. D3 H2 ^3 c
五、AT24C02程序6 _" _0 u+ H" Q- @  O  V
这里给出一个AT24C02的程序,仅供参考2 o* ^, w2 J) O8 b
  1. /*******************************************************************************6 p7 t) `% O. S7 O* R% [* @
  2. * 函 数 名         : IIC_Init9 g3 u, e/ u) y4 X, j
  3. * 函数功能     : IIC初始化. }- j) \) m" S( b& z
  4. * 输    入         : 无
    # y. N+ @( `2 H4 E( T& N1 b
  5. * 输    出         : 无
    ! A/ ^- V, a- v+ M
  6. *******************************************************************************/: i2 g- H4 o, v* {5 O; Q
  7. void IIC_Init(void): o! R0 F8 F6 ^. I. k7 G( V8 h
  8. {# ^* y; {* J( _( \7 W
  9.     GPIO_InitTypeDef  GPIO_InitStructure;
    3 }( k( d( K( M6 K
  10.     RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
    + L/ Z5 M; m8 T, ?
  11.     , _$ H* g7 ^9 ^: l4 Z
  12.     GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;4 Z6 g' a6 F- H9 h: }" A
  13.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;; p$ @; ~" g% v$ Z( s* @. C8 N
  14.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;1 I. h& \/ q, B# ~
  15.     GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
    9 q& }5 [; v; r/ ?9 u
  16.     2 N% A+ d3 M) d* p/ a
  17.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;! [! W/ e5 V3 l) L6 Y9 B
  18.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);; P- |# t* ?$ c
  19.     4 b! G5 N5 P4 a2 q3 Y9 d' A, Q
  20.     IIC_SCL=1;
    ) E  A1 E+ }7 D) Y, O
  21.     IIC_SDA=1; 0 T. c* Z$ ?$ D9 T( O) t6 j
  22. }
    4 g, V6 t1 N" L$ ~6 p
  23. /*******************************************************************************, f3 d$ H0 ?: }! G/ ?$ N" o
  24. * 函 数 名         : SDA_OUT9 A& d8 ]/ g; G5 n- b) p0 P8 B
  25. * 函数功能     : SDA输出配置    ( F8 T, R) L4 w6 v: o
  26. * 输    入         : 无
      G- w; H! f0 j+ m
  27. * 输    出         : 无
    + ?2 U! o" x( i  ]. G1 |2 |
  28. *******************************************************************************/
      r) M3 f. K( {( E. I5 y5 ?: S' f
  29. void SDA_OUT(void)* s8 g6 F( n4 l; U) L3 o7 g% N
  30. {, ^0 z2 s+ W% e/ x& Y
  31.     GPIO_InitTypeDef  GPIO_InitStructure;. C- E% G3 {' M# R
  32.     : l* f4 v6 L4 o$ b; e& G
  33.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
    , T( Q1 \; g6 I2 P& z4 _  }# P" W" ?
  34.     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;/ p$ I& |3 M8 J! D2 y, |2 [* B
  35.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    " x' Z. N: E5 O+ O% o' o/ o! s
  36.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);3 V/ Z+ o6 C! L
  37. }
    , ^9 x7 X: |' B# {* o3 g. h  g

  38. # y: E$ w1 P  a* y
  39. /*******************************************************************************1 ?' R+ T" Y6 m3 j$ G
  40. * 函 数 名         : SDA_IN7 V! y  d$ ^( U8 [# v7 l; J7 S& J
  41. * 函数功能     : SDA输入配置   
    6 x/ d" o9 V! P
  42. * 输    入         : 无
    9 z& A) J- v6 x
  43. * 输    出         : 无
    . k5 ^( h5 H# w- r, V+ z
  44. *******************************************************************************/: |+ J, R" U$ z* q5 K2 ?5 o
  45. void SDA_IN(void)+ a$ P) }6 p# o9 H5 @
  46. {
    : d9 |# e; R/ [
  47.     GPIO_InitTypeDef  GPIO_InitStructure;
    8 a/ Q2 r' n+ b) p/ D( x
  48.    
    6 m8 ^7 B6 o, f  y8 i0 D
  49.     GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;* c- K7 S5 [  b- Z/ U/ e
  50.     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;3 u7 }, _+ w9 V' a+ c2 Q
  51.     GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);+ v  n6 ^! V: x$ U$ c
  52. }( B. |9 K4 X8 o, |) X7 V
  53. ( p  L2 n8 J* L8 B
  54. /*******************************************************************************2 J+ m8 |7 Y& F; a
  55. * 函 数 名         : IIC_Start
    ' \+ H2 h- Z$ P6 ^- k, U
  56. * 函数功能     : 产生IIC起始信号   
    8 H3 K: E! l/ z) N+ t
  57. * 输    入         : 无- W( a  n( z' j: ]% ]: L) `
  58. * 输    出         : 无8 f  O. G  |2 J
  59. *******************************************************************************/
    : _* c8 X1 m( X0 W
  60. void IIC_Start(void)
    : D2 B, n2 S; m6 U
  61. {, ?; Z* V% ~3 f  o8 R3 P" D& p
  62.     SDA_OUT();     //sda线输出* R( j7 O( Q9 Z1 x" y! J, s
  63.     IIC_SDA=1;      ! B: P2 `! c& p* @7 C. {7 p# S
  64.     IIC_SCL=1;: K' X: e" i3 \& w( b
  65.     delay_us(5);
    / T; r  \$ A9 ?! |3 x9 m
  66.      IIC_SDA=0;//START:when CLK is high,DATA change form high to low , O4 }  f  b  N& h( F% h
  67.     delay_us(6);
    ' {2 `8 G4 V0 F( c8 [; S
  68.     IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
    ( ]! O/ s" o" k7 `8 [
  69. }
    " U: w2 O9 {! q7 A

  70. , i6 t1 |$ I$ t$ O# T( `0 m. M- Z
  71. /*******************************************************************************. ^% p4 b- ?6 Z
  72. * 函 数 名         : IIC_Stop
    : P1 Z' r/ Y: U3 d) m3 v$ ~4 i
  73. * 函数功能     : 产生IIC停止信号   
    5 V8 I& \  m& U
  74. * 输    入         : 无8 C1 J9 ^  m5 o  }
  75. * 输    出         : 无
    " \/ a% X) h/ e! K
  76. *******************************************************************************/' T. H# n0 g' M8 [* _
  77. void IIC_Stop(void)6 I, I6 f1 R; M8 b
  78. {
    3 h! O2 [( ^" m
  79.     SDA_OUT();//sda线输出
      c6 ?: A1 p% T' i7 \1 s, i3 s- t
  80.     IIC_SCL=0;( ]: j- D) [7 T& L% z2 i* @$ X! ?
  81.     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high8 c5 f+ d0 O6 A* s5 H
  82.      IIC_SCL=1; ( M9 T0 o0 r0 U- p+ b
  83.     delay_us(6); ' v9 J" r4 d/ |) g- w7 \
  84.     IIC_SDA=1;//发送I2C总线结束信号. v3 J) A% j, C
  85.     delay_us(6);           9 Z7 r- P2 W! ^
  86. }
    ) @6 F' f# E8 W- l

  87. , \2 U4 C5 S" Z% \
  88. /*******************************************************************************
    $ H( k' ]- k! T9 X
  89. * 函 数 名         : IIC_Wait_Ack! M0 X2 O- J! s2 v0 y7 p* w' A
  90. * 函数功能     : 等待应答信号到来   
    + Z; q( q4 P) r
  91. * 输    入         : 无
    1 J2 c5 l8 |7 E" a8 c6 D; `
  92. * 输    出         : 1,接收应答失败) T! O( A2 W& I$ C/ Q
  93.                      0,接收应答成功, d( g; T* o+ y
  94. *******************************************************************************/2 n1 m- a2 e. E) F2 d; ^+ b
  95. u8 IIC_Wait_Ack(void)
    , a. `" K% L) S! z) g! o. v
  96. {# t- j1 d! ]. |9 v) c5 x4 K2 `' f
  97.     u8 tempTime=0;/ u! q. B0 H- y* M; t
  98.     SDA_IN();      //SDA设置为输入  
    2 A( ]! O5 Z; R/ b3 u; j! L0 z
  99.     IIC_SDA=1;9 {! \; f+ s0 ?; l
  100.     delay_us(1);    ' o: H4 t: m8 e. c! p
  101.     IIC_SCL=1;
    ; ?, r  K: y: v+ X3 U* l+ B7 ]
  102.     delay_us(1);  
    : P8 D& D2 o  ^0 a  u3 W
  103.     while(READ_SDA)
      g* ?: Y3 O( w1 K* Q3 l8 O
  104.     {! `! `0 b# U1 `- f
  105.         tempTime++;  |7 J. o+ {! ]+ A
  106.         if(tempTime>250)
    2 w6 {9 I$ E+ g; Y, P" B
  107.         {
    " m; l+ p- \. D( ]( P+ m
  108.             IIC_Stop();
    3 T- _0 H- p9 S. Q1 p
  109.             return 1;
    ' r: Z; o, d8 t3 t6 }6 E
  110.         }& b/ |/ p+ i7 [" e4 n3 d+ K
  111.     }
    2 S! S- l: D1 s; O0 C
  112.     IIC_SCL=0;//时钟输出0     
    " T7 r0 M- H) e
  113.     return 0;  
    + h, X1 j2 F5 H+ U0 V
  114. }
    ' H: E/ e( r0 F9 j- b

  115. + ^5 P" E; L7 g$ n/ G
  116. /*******************************************************************************5 i# o. R- R* l9 j6 B8 d, z: k! ]8 X
  117. * 函 数 名         : IIC_Ack
    9 m# E8 i4 g/ x+ p
  118. * 函数功能     : 产生ACK应答  * Q0 B5 q2 \7 s; [# ?) b/ ~& y! }0 v
  119. * 输    入         : 无: I; Y6 w) T- [4 w& d9 |
  120. * 输    出         : 无4 X& y# n5 m% m/ r. m+ J/ U( Y
  121. *******************************************************************************/& r! F1 U& ^4 J( a) s3 V7 A& {
  122. void IIC_Ack(void)
    : `, T. }% J. {) |; `& a! U  a
  123. {
    3 O8 c! f8 _# r4 x# |- {
  124.     IIC_SCL=0;4 ?- I4 ~  B; k$ u- s* y
  125.     SDA_OUT();
    3 ~, M+ h  A& M1 }$ b; F
  126.     IIC_SDA=0;' J" `+ `6 C4 q7 ]) c: N
  127.     delay_us(2);
    * ?) a5 r8 J, o
  128.     IIC_SCL=1;
    6 c9 o: [8 H- A+ n0 ^5 E: `8 L
  129.     delay_us(5);  p( ?7 T  e4 J/ }) H& T( [! p
  130.     IIC_SCL=0;9 O' i3 ?" F- {
  131. }5 C- ]+ k. x! i! x/ T  R
  132. 4 Z$ }! X6 `' m% h6 W& W" w. O
  133. /*******************************************************************************
    2 Z8 S: k: c8 T/ N9 V9 z
  134. * 函 数 名         : IIC_NAck0 k+ Q- p, s6 q6 m9 ~
  135. * 函数功能     : 产生NACK非应答  
    ! _8 I2 m5 g! A, Y0 C( v
  136. * 输    入         : 无( h3 ]3 Y: c2 F! O/ E, W
  137. * 输    出         : 无  o6 |* Z7 |1 _
  138. *******************************************************************************/      
    ! Q& R' [: G* [# E, C. x4 N
  139. void IIC_NAck(void)
    ) l9 g2 O0 g, L
  140. {) }; D7 u7 d& G3 L' r5 \
  141.     IIC_SCL=0;
    + @( x" M+ D, F8 Y- {& _1 v! j
  142.     SDA_OUT();0 o. H! A! g* ^4 H: ]
  143.     IIC_SDA=1;
    - R& G" F7 s3 _# i7 b
  144.     delay_us(2);
    , d9 R) g% p% E, D" @1 o  g
  145.     IIC_SCL=1;
    " o' ]* p7 Z6 P. [! }$ r& A
  146.     delay_us(5);
    " z% ]) D2 W. E$ ~  t
  147.     IIC_SCL=0;- q# w% o# K1 l' K6 N" o/ F- p
  148. } - e7 m3 e$ J' C" W, {- w

  149. ' d; X2 P* {# N9 z
  150. /*******************************************************************************
    & J: U) h6 `1 T" J& \; C% u
  151. * 函 数 名         : IIC_Send_Byte
    # F- }! O+ |! B% ], y
  152. * 函数功能     : IIC发送一个字节 8 |* z- h$ `0 y
  153. * 输    入         : txd:发送一个字节
    ' f# K* I. T  J" d$ b
  154. * 输    出         : 无
    ( C* U! f% H1 {, Y" y
  155. *******************************************************************************/      o; u/ [8 ^# X6 p$ j7 q$ e  t
  156. void IIC_Send_Byte(u8 txd): [% N! b. l9 b+ J) ]
  157. {                        ! ?9 b7 L( G& @* Q( m
  158.     u8 t;   7 h+ g: ^# k1 @) i2 D7 c
  159.     SDA_OUT();      ! ]; ]) f4 a% p) O0 F
  160.     IIC_SCL=0;//拉低时钟开始数据传输
    " f4 ^! s8 `  ~; L4 X3 ]# D
  161.     for(t=0;t<8;t++)+ }! n+ s; G$ ], H6 u& N
  162.     {              
    8 a$ q) D" s# W
  163.         if((txd&0x80)>0) //0x80  1000 00007 K0 [2 E+ j2 i' k
  164.             IIC_SDA=1;1 @  t, x, E/ q2 W" j
  165.         else8 ^- g  ]! p* i% D# s) J! P
  166.             IIC_SDA=0;" [9 u6 l$ Q. y& F4 |
  167.         txd<<=1;    ( E- J: b2 j& c8 S# F, W7 U+ ?
  168.         delay_us(2);   //对TEA5767这三个延时都是必须的: o; ~$ T* z! q9 }- H/ ?/ c0 N. ]  ^
  169.         IIC_SCL=1;3 A3 O" \/ \; d0 j! c5 l# W  I& y4 u
  170.         delay_us(2); 8 f4 q. Q7 J: P# W+ }* `
  171.         IIC_SCL=0; ) g( c6 [$ ?. H4 [0 z4 `% E7 w
  172.         delay_us(2);
    6 S& f) S0 q: ?8 {, T
  173.     }  
    / P; `6 G6 k6 i7 j, b1 ~
  174. }
    , m; _: E9 J  T

  175. + n  a# R$ {3 I( K- ]
  176. /*******************************************************************************. K* ?2 l6 S5 M+ e6 ~
  177. * 函 数 名         : IIC_Read_Byte
    5 C, W# M1 |$ E% \6 A
  178. * 函数功能     : IIC读一个字节
    . U% G( @& }4 V# d7 S- _  X) m
  179. * 输    入         : ack=1时,发送ACK,ack=0,发送nACK 9 x4 w; [% I. Q
  180. * 输    出         : 应答或非应答
    & y# r  E, T% w' n& e+ L4 `2 v: N
  181. *******************************************************************************/  
    + n+ t) D9 w: w
  182. u8 IIC_Read_Byte(u8 ack)
    ) J& a& S1 m% R' j" a0 c
  183. {
    , x- u, j0 J, ?% `+ U$ a
  184.     u8 i,receive=0;
    2 R2 k: ?1 ]: x& V6 J8 D6 m/ E9 R
  185.     SDA_IN();//SDA设置为输入( {5 ^/ K0 O; L
  186.     for(i=0;i<8;i++ ); L4 _3 x% Q+ [: S
  187.     {+ L1 ~# p, B/ s/ z# n& S
  188.         IIC_SCL=0;
    ! Q) W. `" B% u9 ^8 _
  189.         delay_us(2);
    7 W- O) V# R4 r6 t
  190.         IIC_SCL=1;
    . [3 a1 ]3 A; C; n5 K2 `3 R( J) v5 K
  191.         receive<<=1;
    4 U7 ]) x5 W' `& [8 S
  192.         if(READ_SDA)receive++;   ! [. r3 G7 g2 X" y
  193.         delay_us(1);
    ; Q8 C1 y. }, \
  194.     }      9 @$ U8 l# G# Z" k
  195.     if (!ack)
    4 Q9 k  v4 Q8 f6 C& u. p
  196.         IIC_NAck();//发送nACK
    - a- x3 e( ?& y% A& y$ ?7 _
  197.     else
    7 ?. k3 R3 L* e- u- w0 \
  198.         IIC_Ack(); //发送ACK   ; k* u$ u5 H3 _2 l
  199.     return receive;; p: ~0 `6 j: \/ |' q3 Q
  200. }
    " M/ @5 Z7 L3 U6 i+ t: ]. {, v, h
  201. /*******************************************************************************
    / e+ h( }( z( n1 \, L/ i+ V
  202. * 函 数 名         : AT24CXX_Init
      t. N+ t* S3 N
  203. * 函数功能     : AT24CXX初始化" j* ~3 z! Y6 D% o: ?
  204. * 输    入         : 无2 J; k- @0 [8 w% c* I. e! ~, |$ h! J
  205. * 输    出         : 无
    ) z4 C4 w4 ^' ]  o# }
  206. *******************************************************************************/
    . E0 v) G5 W  N6 L, y; ?5 m$ U, v
  207. void AT24CXX_Init(void)' L6 m& [) e0 i4 s8 d& U7 ]
  208. {
    5 u8 s7 S1 S5 Z7 W
  209.     IIC_Init();//IIC初始化
    " B$ c/ O4 p# S; N7 J$ W1 Q
  210. }
    + ]7 D) H1 p! X. o( M8 X
  211. 4 }! j4 B! ~3 p5 R6 ?
  212. /*******************************************************************************2 `: i! l6 C/ V: v0 p  V1 a9 O
  213. * 函 数 名         : AT24CXX_ReadOneByte
      ~) Y, t! p3 k+ p6 F
  214. * 函数功能     : 在AT24CXX指定地址读出一个数据3 @7 F9 }: N# [5 O, O
  215. * 输    入         : ReadAddr:开始读数的地址 & t: M" g4 ~9 P
  216. * 输    出         : 读到的数据% O; O) _. [% G1 }
  217. *******************************************************************************/
    5 R: J( C/ Q& s1 {7 ^; q! k$ A
  218. u8 AT24CXX_ReadOneByte(u16 ReadAddr)
    * P) f7 E/ k, `( _0 \+ t( ~/ u' a
  219. {      
    , b5 [6 E3 k, K0 z- J& E7 t
  220.     u8 temp=0;                          
    5 R* p1 l2 W2 p' o
  221.     IIC_Start();  2 Y7 \& ^0 Z9 Y1 I4 q
  222.     if(EE_TYPE>AT24C16)* g7 I- G6 k% U1 l3 x# e9 [
  223.     {- R( d; \5 t4 D% P( o# ?5 i
  224.         IIC_Send_Byte(0XA0);    //发送写命令+ R( ^( `4 b  W7 c' T! }  x
  225.         IIC_Wait_Ack();
    # @# D7 [& a4 ]: V" B
  226.         IIC_Send_Byte(ReadAddr>>8);//发送高地址     ; _2 }" U$ `4 u8 _2 z; p
  227.     }" N% T, V, m+ g- i% F, P# V
  228.     else
    " D' j; S" l0 B0 z* }6 k/ R( D: a% c
  229.     {1 A  p% P, S% m& Q. }4 c; L' f
  230.         IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据6 U2 h1 a3 U" B+ j, S- U4 z8 m
  231.     }     3 s# u. n4 m! Y- q- m
  232.     IIC_Wait_Ack();
    # V! ~$ C2 U3 C5 n: h8 W5 h! o9 S
  233.     IIC_Send_Byte(ReadAddr%256);   //发送低地址
    ) }% t, O+ @8 E- K! e* W# F
  234.     IIC_Wait_Ack();     
    / T9 N4 H( t2 j$ V$ s$ `2 _
  235.     IIC_Start();        
    : |7 D3 C8 H8 v9 {& r7 r
  236.     IIC_Send_Byte(0XA1);           //进入接收模式      
    - V  i- {6 }# c' O
  237.     IIC_Wait_Ack();  6 P4 b) ?8 b- F4 x# }2 {9 P
  238.     temp=IIC_Read_Byte(0);     
    + i7 G  H2 r! h* f4 d; h, h4 a
  239.     IIC_Stop();//产生一个停止条件     5 ~. b3 z+ \0 |5 [# Z4 T! S
  240.     return temp;+ g& x; u0 z  g, L0 W* R
  241. }4 Q: O& C  O( D0 g
  242. / L2 ?1 u! N0 Q" |9 ^
  243. /*******************************************************************************, s9 B" A0 ]* z
  244. * 函 数 名         : AT24CXX_WriteOneByte
    & J2 q9 A' R) t& @$ l
  245. * 函数功能     : 在AT24CXX指定地址写入一个数据
    . [0 U: Q# X$ G1 w5 X4 W+ D2 J
  246. * 输    入         : WriteAddr  :写入数据的目的地址
    * e- Z! ~# a( V4 E- x' h- T
  247.                      DataToWrite:要写入的数据
    1 |2 U  ], f4 ?; v1 t
  248. * 输    出         : 无# V! y4 G  y( t+ q# J& r
  249. *******************************************************************************/7 t& J0 B5 O2 ^9 K7 u- `
  250. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)9 J1 k+ [, N0 z) s! @& u( }
  251. {                                1 k* s! g  }; p9 \
  252.     IIC_Start();  6 _8 ~9 x9 o0 G6 N9 w) F5 a
  253.     if(EE_TYPE>AT24C16)
    * h8 |8 g8 p: U. z! u: r, ^
  254.     {- J4 K/ f5 b/ k
  255.         IIC_Send_Byte(0XA0);     //发送写命令. M* K" H, I' O; i# \+ M3 f: W
  256.         IIC_Wait_Ack();7 k) I! ?1 v/ m  }; Y3 [  k
  257.         IIC_Send_Byte(WriteAddr>>8);//发送高地址   : K( p* S. M/ u$ V, i' S4 H
  258.     }( P% w5 D' C3 T
  259.     else 6 T8 F$ a3 X3 Q5 ~2 G$ }3 B# E
  260.     {: }! G& n, w, {" [3 K
  261.         IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
    2 \8 `5 ?' o6 f9 i2 \
  262.     }   
    * c1 x  k( q/ q# r  u, s
  263.     IIC_Wait_Ack();   
    ( t0 u# Y0 L( \8 b! G" C4 b
  264.     IIC_Send_Byte(WriteAddr%256);   //发送低地址1 ~& d: t* A0 |- `. x9 b6 W" B' N: u
  265.     IIC_Wait_Ack();                    
    " I5 s  t8 A4 G" e" Y
  266.     IIC_Send_Byte(DataToWrite);     //发送字节         
    ! k( I# u6 M% E; l9 P$ M1 D1 ]
  267.     IIC_Wait_Ack();            
    # v& m% ?1 e% _- [6 I: G9 O
  268.     IIC_Stop();//产生一个停止条件 9 T* Y6 e- |8 Z+ \2 y. Y/ E1 H: g
  269.     delay_ms(10);  
      z% r: D! d! Y
  270. }6 l/ k# W: g9 L3 _7 U7 ~4 J/ Z

  271. # o3 m4 }" p0 C9 a# `
  272. /*******************************************************************************
    3 M  l- k& M9 w2 b0 Q- Q) n1 r
  273. * 函 数 名         : AT24CXX_WriteLenByte
    ( U3 F# a% ?. Q+ W4 X& }
  274. * 函数功能     : 在AT24CXX里面的指定地址开始写入长度为Len的数据0 S! L* W$ R7 K1 |) U3 r0 f4 `
  275.                      用于写入16bit或者32bit的数据
    . B! A5 M3 ~( o: y: u( `9 t
  276. * 输    入         : WriteAddr  :写入数据的目的地址
    + I  I, O' V5 C: X) }
  277.                      DataToWrite:要写入的数据
    & }7 _# L: Z  R
  278.                      Len        :要写入数据的长度2,4# V3 h; A" g+ y
  279. * 输    出         : 无
    * e- a' K8 Y8 T7 s, E
  280. *******************************************************************************/
    : l* F& d- W; h- `
  281. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
    , A& u" D9 N. o  q  r/ @' T
  282. {   
    $ B& N5 V% n* D( b' M* E
  283.     u8 t;" h& Y+ t9 y( M& P5 y  a9 D9 m* _& N
  284.     for(t=0;t<Len;t++)- B" _: N! _4 ]3 G. u0 T: m( f: d% m
  285.     {
    / u5 t, \4 `1 d) ~8 h
  286.         AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);: ~& S3 e6 r) ]; T: i! N% ?
  287.     }               
    - d% C. T) x8 o1 k3 i, Q, T3 ?
  288. }( Q6 y+ x. u9 C# j3 A3 Y" Y
  289. " o' ^( X5 [+ m; j2 Y2 v
  290. /*******************************************************************************1 x! q% s: l0 S, v- Q' Z: o" ]
  291. * 函 数 名         : AT24CXX_ReadLenByte, g  l5 \$ A; f3 ~5 [+ ?! f
  292. * 函数功能     : 在AT24CXX里面的指定地址开始读出长度为Len的数据
    ' }0 C& X+ _0 E
  293.                      用于读出16bit或者32bit的数据# {4 _* Q  X, V8 S( M
  294. * 输    入         : ReadAddr   :开始读出的地址 9 F& M0 y! v; ~; h: N
  295.                      Len        :要读出数据的长度2,4/ _  e7 j; u# I& d
  296. * 输    出         : 读取的数据% G; {3 V. ^& v# x
  297. *******************************************************************************/
    7 z" A6 X7 ~# d) m
  298. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)' U' B& Z% B& }( ]  E, v: }
  299. {   5 z- B6 T5 w3 B2 \
  300.     u8 t;( M" @" @$ T/ @6 f9 h6 C3 k  ^
  301.     u32 temp=0;0 ]8 f; |" v  X( Z7 p
  302.     for(t=0;t<Len;t++)! p8 }6 g& D1 L
  303.     {
    ; j& B6 G2 \# [: T* h, o5 @" l
  304.         temp<<=8;
    , Q7 P1 G5 g% e+ w5 {
  305.         temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);          + k  ]5 ?* E$ s7 P
  306.     }- E3 M( Y, C. `5 O2 f) f
  307.     return temp;               
    + j8 l9 }, m, t/ q2 S
  308. }
    5 U& {$ j3 e( j, q% f
  309. , F- Q* D6 @% \) Z
  310. /*******************************************************************************
    + u: J- C8 f$ ]2 Y' s: @1 U
  311. * 函 数 名         : AT24CXX_Check8 z; |( ]' H* {5 V; i
  312. * 函数功能     : 检查AT24CXX是否正常
    ; T6 a2 ~0 L% W7 o0 _
  313. * 输    入         : 无
    0 x& j9 N" Q  u$ b5 _8 }
  314. * 输    出         : 1:检测失败,0:检测成功. P! r0 i7 `6 a7 A5 _5 }( u! Z% }
  315. *******************************************************************************/
    4 e2 |, D/ E0 u. L9 v% \+ \  {
  316. u8 AT24CXX_Check(void)
    4 a7 O6 u. a% s* v+ Y
  317. {
    5 L+ \! O" Q8 s. M' P+ [$ s
  318.     u8 temp;
    4 t* U  y! ]# q
  319.     temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      - o" b/ E/ w1 V% l7 R
  320.     if(temp==0x36)return 0;     % a# o% ]. Y0 j6 e, I4 i+ w
  321.     else//排除第一次初始化的情况
    . c+ ^6 N, I4 S
  322.     {, C/ u, m6 ~# c$ {7 I
  323.         AT24CXX_WriteOneByte(255,0X36);6 M: @0 C9 }6 s
  324.         temp=AT24CXX_ReadOneByte(255);   , K1 W9 B) p+ O- T# x0 G
  325.         if(temp==0X36)return 0;
    ! K5 R) j3 j: e( q0 F& F# o2 j
  326.     }$ f: Q8 p( W" \$ I' D
  327.     return 1;             , z6 q: N8 G. P. P- M; _) Q  b
  328. }  {3 T  j% ^; J8 b3 {

  329. 1 n) r3 [& Z( w! r2 h/ q, q
  330. /*******************************************************************************
    " Z. A9 }3 U4 H; X) z" k
  331. * 函 数 名         : AT24CXX_Read
    ( T7 B6 m3 X" j/ x3 F" @, S
  332. * 函数功能     : 在AT24CXX里面的指定地址开始读出指定个数的数据
    1 T* X- a% j' H# a4 P$ z2 P
  333. * 输    入         : ReadAddr :开始读出的地址 对24c02为0~255
    % F$ B6 b; s. Z; r# o4 @8 ?
  334.                      pBuffer  :数据数组首地址
    ) i' U( [+ v4 ^0 y) O, V7 N
  335.                      NumToRead:要读出数据的个数0 ^3 X4 N/ j( {9 X  z6 `4 N
  336. * 输    出         : 无
    9 q' W- R1 h8 ?5 ?9 F8 j+ u9 W1 O
  337. *******************************************************************************/
    2 E' p: a) F* \! h$ q; w
  338. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
    7 D' I: o( X! z
  339. {" D/ T. w9 X" L" p4 ^5 C% o
  340.     while(NumToRead)
    3 F2 _4 A( u* r# I1 n3 ~
  341.     {
    4 J5 {1 O6 v  Z9 n/ O; Z
  342.         *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    9 d. U2 ^9 N2 E, c/ P, Q
  343.         NumToRead--;4 {' t6 b* N6 b0 i' a
  344.     }6 O; \- }. W3 H& g9 R8 J; r
  345. } & I% s  q/ q2 r/ T
  346. - Z/ q0 P. E# Z+ B
  347. /*******************************************************************************0 G9 x( c5 i, B# \- v/ L& F+ O
  348. * 函 数 名         : AT24CXX_Write
    $ x# ?. W" ]! m# q
  349. * 函数功能     : 在AT24CXX里面的指定地址开始写入指定个数的数据5 l# d/ C8 @$ P( R
  350. * 输    入         : WriteAddr :开始写入的地址 对24c02为0~255, h8 X! O9 i/ |( A4 u* P
  351.                      pBuffer  :数据数组首地址" n7 t# b4 |7 V- k( ~
  352.                      NumToRead:要读出数据的个数
    0 B# C7 s- t8 s; v4 z2 ]
  353. * 输    出         : 无$ O- \& O/ ^/ {; ~, ?' Z) @' r4 X, j
  354. *******************************************************************************/
    . _8 h; `9 k7 T3 T! W7 d
  355. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)' j% c- h8 K1 L/ p
  356. {7 C. p* d  q5 a+ c+ p
  357.     while(NumToWrite--)
    ( q4 O: n% u) a( R
  358.     {
    # ^( D$ l. B2 L' J4 `; O* n' R
  359.         AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    5 X) Q' g8 H0 @( c2 g
  360.         WriteAddr++;
    3 H& F0 _7 e4 U
  361.         pBuffer++;+ o. ?. Y3 D+ Z+ \" x6 m
  362.     }" F* b' ^$ s5 L
  363. }
    # q: \$ Y. a% ~1 o+ ~
  364. .h文件如下) t% y4 I, J) H* G' `

  365. ! U2 S3 `$ E5 Y. i
  366. // 核心板使用的是24c02,所以定义EE_TYPE为AT24C029 B3 C5 S: H2 j6 u
  367. // 可修改成AT24CXX系列中的任意一个6 ?3 g4 ^8 m4 v0 }3 |9 j: A
  368. #define EE_TYPE   AT24C02* V: U" F( I9 [1 X! @/ h

  369. * B- T$ Y8 `8 {  L9 ~9 Q/ j2 g- h
  370. // IIC函数" U& f. e8 x3 e7 \5 ~- _
  371. void IIC_Init(void);   // 初始化IIC的IO口     
    # B' r" j$ Q; h' ?' W
  372. void IIC_Start(void);   // 发送IIC开始信号
    % n2 t9 ?, K. z) t3 x) B
  373. void IIC_Stop(void);   // 发送IIC停止信号: v2 W; y# N& A- c
  374. void IIC_Send_Byte(u8 txd);   // IIC发送一个字节
    7 e4 F1 i) }7 o/ K0 [4 Q
  375. u8 IIC_Read_Byte(u8 ack);   // IIC读取一个字节0 a- ~& j  E( B7 y7 O
  376. u8 IIC_Wait_Ack(void);   // IIC等待ACK信号
    5 |4 Q0 p+ ~3 n7 ~: n
  377. void IIC_Ack(void);   // IIC发送ACK信号
    % d! Z- X7 j/ Q0 Q- F1 j0 I
  378. void IIC_NAck(void);   // IIC不发送ACK信号" W$ u& ^% Z1 R
  379. : L2 ?8 P8 Y) @. M( t3 Z1 j
  380. u8 AT24CXX_ReadOneByte(u16 ReadAddr);   //指定地址读取一个字节
    8 Y- {. O3 e, e+ g. v2 L
  381. void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);   // 指定地址写入一个字节
    / }- ~" v5 Z2 J# I! B- E
  382. void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);   // 指定地址开始写入指定长度的数据
    8 L+ x/ g. |/ @0 A$ i5 S
  383. u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);   // 指定地址开始读取指定长度数据( k# A% _. t: T/ K. e
  384. void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   // 从指定地址开始写入指定长度的数据/ C; x4 ^- C, a( R/ x+ P
  385. void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   // 从指定地址开始读出指定长度的数据
    ) O% X3 n/ G& d5 I( @% F
  386. ( |$ E& y& x, @6 Q0 U8 C6 Q+ _: g! x
  387. u8 AT24CXX_Check(void);   // 检查器件
    - T' h' s2 _3 d. D# `' \9 z0 A
  388. void AT24CXX_Init(void);   // 初始化IIC
复制代码
/ z( L0 `. e" g" F; V0 x& y# d8 S; ^
六、应用实例% {% T( B7 K7 ?3 b% _2 i8 N& X6 K: E# z
给AT24C02写入一个数据,读取一次确认写入正常。注释掉写入程序,拔掉电源。一段时间后,插上电源再次读取之前写入时的地址的值,串口打印结果。AT24C02的初始化程序如下. P7 ~6 Q# X! z4 k
  1.     AT24CXX_Init();   // AT24C02初始化
    1 Z6 ~" R! K( E
  2.     while(AT24CXX_Check())  //检测AT24C02是否正常
    % {) |1 M1 @% J6 L) }
  3.     {
    ; o+ n, A) c; b4 ], X/ ]1 M3 ?
  4.         printf("AT24C02检测不正常!\r\n");
    3 \7 x/ a1 ~" Z, @( |+ _3 ~
  5.         delay_ms(500);
    ( c- L9 F$ O* }/ F5 p+ T
  6.     }$ t# T8 Z7 \" g* c) F$ u
  7.     printf("AT24C02检测正常!\r\n");
复制代码
, N$ w8 V0 q3 e9 o0 E  g
main函数如下
" T$ D9 U6 }, j: e5 z
  1. u8 gWData = 0xaa;   // 准备要写入的数据
      c$ W" I5 k. t) F& |1 c: f$ V
  2. u8 gRData = 0xaa;   // 存储读出的数据& x7 P. S; E0 B1 B$ D6 H
  3. 0 a6 a9 A- G( J  |3 W6 A" A" w
  4. int main(void)
    4 s8 m- O# Q3 @8 F2 e) E3 u  h
  5. {( `( b0 H; L- X1 E+ l6 P+ u
  6.     Med_Mcu_Iint();   // 系统初始化
    " L: Q( S+ y8 v. V/ w3 F
  7.    
    ) x  s7 [5 q9 Y, p. W* i: g
  8.     AT24CXX_WriteOneByte(0,gWData);
    ! L9 X$ y. w$ F/ G; C+ l
  9.     printf("写入的数据是:%d\r\n",gWData);& z0 j3 r: ~. p2 v
  10.    
    + E) X- z* |8 f+ Z( p- z
  11.     gRData = AT24CXX_ReadOneByte(0);
    - f' m2 l, s8 \2 j5 V
  12.     printf("读取的数据是:%d\r\n",gRData);
    ; x7 X, e0 R; r2 T7 y, I
  13.     ' W+ o; }3 a3 m0 s! A6 s: U8 {
  14.     while(1)
    ! E6 B- G1 z9 O: a$ P
  15.   {
    3 z2 r2 w: x# \  P1 m! p: ?
  16.     }# }" W$ x, Q% f4 @  ]
  17. }
复制代码
1 G5 ^# X# l3 P8 L+ j+ L
串口打印结果如下9 y2 u! i" e' v( O) D
, z6 t1 z% w$ H; C/ {

  M# d6 x" }' T
串口打印结果

7 O$ _6 X+ `1 }+ {

, Q3 J2 c/ F- S# W+ y! N0 a
5 F- w8 H; K: D; [7 U. M: i* F
七、拓展应用
; n6 h5 B# Q2 H. X0 y( l) i, M, kAT24C02这种掉电数据不丢失的特性,使得它可以存储一些重要数据。比如将一些校准数据写入AT24C02中,再次上电之后就不会丢失。或者用AT24C02记录开机次数等。这些原理与应用实例中的例子原理相同,这里就不再赘述了。( z  y+ x$ q$ R4 a

7 W' [' c+ P, w. L
" p6 r3 G: v( S: s
- {$ a' l1 a/ X$ O# Y' M  F
转载自: 二土电子5 y$ B  ~5 \: J" R$ x+ p* G
如有侵权请联系删除; [9 }- ]6 v1 P
9 l: h' E3 n- @- D1 B" C
微信图片_20231023203400.png
收藏 评论0 发布时间:2023-10-23 20:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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