在这段描述中,我们可以看出,24LC64是一个8K*8的一个存储器,总共64K bit的容量。因为存储深度为8K,也就意味着芯片的地址有需要有8K个,也就是有8192个,从0开始到8191,那么地址线的位宽就是13位。这也就是我们在写时序图中展示的高字节地址和低字节地址。此外,芯片的供电范围是1.8V到5.5V。芯片有页写功能,最多可写32字节。允许最多有8个芯片连接到相同的总线上。
* J6 h. x% N; K6 W3 Z
管脚及功能介绍:
1 l+ S2 f! j2 j7 D4 a/ J& `, v
+ n5 p. z) |- d' T8 S- S+ W
- ?' ?2 l6 x( b& M1 _1 h7 i
) q* h" X0 R3 ]
( r& \1 S. I) v
A0、A1、A2三个端口为片选输入,当这三个端口的电平与从机地址相同时,该芯片被选中,这些管脚必须接电源或者地。
. p% w! C' L; c4 _2 \6 s% O
; Q! a5 }$ o* a& W- n$ p
) m6 `) W/ U. o
, x& w: j" T0 |! {2 C
( ] V' T/ T" W6 {$ fSDA是一个双向总线用于传输地址和数据,在SCL为低电平的时候,正常的数据传输SDA是允许被改变的,如果在SCL为高电平期间改变就会被认为是开始和停止条件。
5 U: {! i5 ]9 T; E+ g' x `& \1 d
3 X( V: L. G& v; t: a; q6 ^: d
/ x1 y7 r' B/ B8 H! ^* F4 x* P6 L9 f
# f3 H3 s- g3 \! | B
5 c- U! T8 M! Y
% P- w( c: ^8 S/ D3 @1 a2 N- Y# G2 m- ^0 q/ J1 _1 y- ^" Y
+ a. Q6 D3 w, w SCL为串行时钟,用于同步数据的传输,由主机发出。
% @& t, ~5 K" u9 C' z) W
/ S8 [" T; ^: R$ v
2 ]# E- J7 }" l% W6 y7 W" ]
! j/ ?- \: m/ n0 `
" c: C+ r0 \9 h2 c, ~
9 O6 @ G7 f; r8 y5 X! D K9 f/ R2 j" o" X6 w
& f8 G$ U; Z; Y5 H6 G* [ 写保护管脚,这个管脚可以连接地、电源或悬空。如果悬空,这个管脚上的下拉电阻会让芯片保持不被保护的状态。如果连接到了地或者悬空,正常的存储器操作是有效地,如果连接到了电源,写操作是禁止的,读操作不受影响。
" M& p; S3 ~+ x* V2 V
$ o" c9 B: ]. ~" _- D
: H' ~! Q j7 h0 w. M1 N
/ z1 A8 e8 [ _! E+ P- I8 x( ~3 e/ o6 Z8 ~6 `2 H G
2 F# I! V+ Q2 D0 g4 d8 Z! ]7 Q! i1 S在SCL为高电平时,SDA由高变低被视为开始条件,所有的命令必须在开始条件之后。
$ w" T" d: O0 D( _% \% m% ]5 I$ Q7 a
在SCL为高电平时,SDA由低变高被视为停止条件,所有的操作必须以停止条件结束。
& V( }5 \! d5 }
9 H' o: m2 b% O. }# g" F
: _" _0 `/ t! L9 }
4 X. C# X4 ]: Q. J% j7 z
端口介绍完,这里要着重说明一下应答信号。每次接收完8bit数据,从机需要产生一个应答信号,主机必须产生一个额外的时钟周期伴随着应答信号。注释:芯片如果有内部循环在进程中的话,是不会产生应答信号的。在时钟为高电平的时候,芯片的应答信号必须拉低SDA,并且在SCL低电平期间保持稳定。
) U% L" X' {7 L" |) p* F' G
2 L1 N! A7 P3 [6 P5 {/ l9 a
9 D0 R" ?5 I0 V
( P9 s# V# N' N) {6 U. d" k, V: N- W5 J# x# e4 A2 C4 F5 u9 k: v
0 `+ X: X+ \1 [
, _* r9 a" T2 m1 N* C2 t* O
上图为IIC总线的示意图,其中开始条件与停止条件在上文已经描述过。其次是数据的读写,在图中,SCL为高电平时,地址或应答有效,那么我们就在数据有效的时候进行采数;在SCL为低电平时,数据允许被改变,那么我们发送数据就在此时间段。
# j. y, C; k7 L3 c. l
在了解了端口的作用及功能之后,我们做一个总结:
) x/ s$ n0 U7 }/ `8 c- G
1、起始条件:SCL为高电平,SDA由高变低。
2、停止条件:SCL为低电平,SDA由低变高。
3、数据接收在SCL高电平期间。
4、数据发送在SCL低电平期间。
% a( O1 A0 l: O% I! A& `" K# M& n
5、A0、A1、A2、WP在电路图中已经全部接地,在代码中我们不需要关注。
7 i! C( c1 s% W1 z$ ^ u* I Y1 s( J
4 U: o0 E$ M s- t# j. u" k
/ n1 B( C( y) G+ \) D. D* F, R
# U5 R; `/ H5 `3 ]# c
电路图中可以看出,我们的EEPROM的控制管脚只有SCL和SDA。
' ?9 A. H' M, b- T. S9 f
! h d, P5 R) q. W( u* ] h9 x
设计框架
' y+ b9 `; }% v; C% H5 u) v+ Q7 n7 r; y5 f0 J9 Q/ r6 N
* U% a6 c" C$ o% Z( J6 a6 G9 U Z8 q1 h( Z: F. h: o
( G# P4 X3 T( b7 H
! P! i- J. L& P A+ a& e( v; Q8 \: u
! Y9 J& Z. G: V q1 B% s$ g a
5 V1 f/ \% ]4 m* l2 k; M; t1 v
/ K/ {5 V! o- z3 ^9 J0 P按照上面的框架,完成各部分代码,最后在此框架的基础上,再加上数码管模块,用来显示从EEPROM里面读出的数据。
+ Q) B; ^4 i2 }7 z8 m+ c& T8 x新建工程:
' {9 z( V/ J: ]: O C3 s0 Y. \, R- k$ E) y) a$ s
7 c3 _; d& n R. M' g: I+ H5 e4 _4 f) V: Z9 }5 U7 z
' o: v6 `* N4 h4 ]! [
7 N7 X2 J; ~* r* r. R新建好工程后,新建文件,开始写代码,首先是写模块。
; l3 i6 L3 W7 c
写时序如下图。
& j" G% o3 P1 }1 i0 n# Z- L" p
7 r8 [2 I5 B/ f( g
v/ F) @, `4 h1 ^# o
N5 r' z! N/ z0 d我们以单字节写为例,因为在写的工程中,没写8bit,就要读一次ACK,所以在此我得做法是,读模块只写8bit的线性序列机,
2 n+ C! G: t& p8 V
代码如下:
" q8 o: u) m2 x4 {' [! M0 O
+ B9 Y6 } k2 p5 G
6 {* b' p6 g9 N; h" A8 P! T U3 |
. p5 l( A: d4 ]. h2 h* t2 @% |在写模块中,我们选择在SCL低电平中心位置发送数据,那么为了方便我们写线性序列机,我们将四分之一SCL周期看做是一个单位时间T,总共8bit时间,所以计数器需要计数32个T。
y+ a5 W i- l/ J1 i: m# _8 O! r: ~8 }+ C. z
6 A; J& W1 D1 o; w4 j D9 s+ m读模块代码如下:
7 n1 X; S# P6 V- g3 y2 k u
7 F/ C. N5 E8 k: G
; ^1 S/ S9 V% P0 I
8 W) f1 a( z9 T# _5 X在控制模块中,我们可以将每个bit分解开进行写,比如起始条件:
3 S3 p* e! g( q4 K* S; v3 h- G5 Q5 O
8 h* ]# r* d3 S. z3 A$ t5 Z
6 j0 A9 P3 G4 I
类比以上写法,停止条件也是如此。
4 P& @5 \- Z. l3 R
5 G& U/ I* w& W4 s$ ~7 |' \
: }$ _' o- M" a8 \" z6 u' h
8 Y' u& C9 }: Z8 Y' s! e4 G
2 h/ R1 d9 F4 Z3 J. O( Z% w7 {! R在控制模块中我们使用状态机来完成数据的写入以及ACK的判断。我们在第一个状态中,可以加入一个按键来启动整个过程的开始。
; k: `$ l; \2 g2 b% l) c! d" ~
0 I1 X0 y; m4 }在ACK读取的状态,我们在SCL高电平中心读取ACK的值,在此状态结束时判断ACK的值是否为0,如果为0说明响应正确,状态继续往下,否则返回起始条件状态。
2 e% S' L8 z) q$ [; I4 V* N' S
4 r b2 T8 K+ X7 [
0 L' |, w& Z' q1 f8 P. ?
$ E! c2 }- o3 }/ _1 u
在顶层代码中,我们需要加入三态门来控制双端口。
1 C6 d4 {% d) ?9 C
8 Y8 F: r6 e* ]# m
1 B7 r! c' P/ v
# j: K' _' n+ e. A6 W3 u% N( ~1 S) V# y2 G4 @7 J) a
在写好代码之后,出现了一个问题,那就是我们无法仿真,因为单纯的看波形,会发现我们得不到正确的ACK,导致状态一直无法继续。因此我们将使用仿真模型来进行仿真,在仿真模型中,端口为芯片的控制端口。
! ^0 `7 g. P2 N3 K3 l7 R& j
$ Y% {" p0 O' |5 F) W% f9 G+ B- z# s
0 a$ c3 H3 ?& e1 [; f- \2 f- C
( |9 c9 T# k* Z4 O: M& P2 _7 \4 ~9 F! f/ `* G! B0 K5 P r0 e
8 P+ L- p$ k/ P
3 G9 g+ x* L4 B! w& [# }) B. }$ g3 z6 l0 W/ R6 L! F5 P
0 X2 |2 I6 i9 a/ d& z
4 |; \) t% F. L( {
0 ?8 E `& _2 x/ @% \
: f+ o. a A/ J4 M3 Q
: j2 ~5 J3 s9 m9 s0 h q$ j2 [在此模型中需要我们注意的一点就是,写循环时间定义的为5ms时间,如果大家觉得时间太长,可以自行修改。
) n( w9 \) p$ j9 t
6 S( T' W( ^- {; r) ~+ G- }
. L9 F2 F! B& P; J& ~. T$ {8 l @0 E; s9 R) u) h& P' @! X1 ]
+ ?4 N3 G- o e2 _+ A9 w% ]. }" t0 _% _
+ R! d" q3 f1 ^' r/ O2 Q8 a0 v
仿真代码如下:
6 O8 ~6 u& b/ C7 _: _7 w
1 h( M9 A, N' M" J `# W" p' |
/ S/ g* W# o3 `; u Y$ X3 [5 j& ]( q6 @- C7 u" h6 W
8 Y9 w( L8 L! @7 n
" |7 F1 x a0 X. G; j! I, ]9 O5 h2 k0 t. A* v
7 ?8 [# `; e9 V( Y1 I
! S: M8 M/ ]2 }. g
: `5 D7 [4 H% F2 k2 ~! K 写好代码之后,我们打开仿真波形进行观察。
" @& c/ r! M- }4 }7 o9 U T: U9 `, x/ R9 L! p- j. R
- @3 x& R/ \' U8 P: b6 ?1 n/ x
/ H6 e( v }6 o _7 S
: a. O& j9 q+ y4 C
* [/ H! ]3 P3 g7 \4 I: d& v在仿真波形中可以看出,我们读出来的数据跟写入的数据时一致的,即表明驱动正确。需要注意的是,在写循环时间内,我们发送的命令,芯片是不接收的,所以会出现起始条件、写控制字、ACK三个状态一直循环,直到数据写入完成,仿真模型才会返回ACK。此时,状态继续往下进行,直至结束。
0 e P3 O8 e S$ J4 L
我们从仿真模型中读出的数据,高电平是为高阻的,模型无法拉高,所以我们在仿真中可以自行上拉,这样才能看到完整且正确的数据。
) R9 _) h- `- T1 O7 Z
0 @5 p; f4 Y# g- s( _( y
' I9 {+ C! y! L( M' k# A5 s7 t8 l, k( H/ ~2 e
9 I! v2 \! A% w8 O, A9 J% n( \! N
5 z! w3 w* e) ]. ?( ` P& I
' `5 I3 x8 O, [
至此,我们实验正确。
2 @( y2 d. x! H