|
EDA365欢迎您!
您需要 登录 才可以下载或查看,没有帐号?注册
x
小白菜的EEPROM学习之路
1 n8 {: @& K7 V! M' n% V5 Z* D AT24Cxx全系列驱动编写' M6 B. A& `5 U8 F$ }
上回书说到了标准IIC的编写,函数参数是指针和字节数,并非是以IIC地址和寄存器地址作参数,何故?小白菜考虑着,要想真正的适应大部分IIC器件的IIC操作而不必写两个功能相同的函数,用指针和字节数作参数是最好的选择。大虾们可能觉得这是为了统一而统一,这点必须承认。在参数传递效率上,确实比直接传递数据要低,但是小白菜接触到的IIC器件,没有一个是需要时时写入的(这里的时时是指MCU空闲下来就读取或写入IIC器件数据)。用的最多的是EEPROM、还有xxx7290(键盘数码管扫描芯片)、铁电存储器,测温芯片。这些器件没有一个是需要实时操作的,也就是说小白菜接触的IIC器件对实时性要求不高。于是,小白菜可以忽略参数传递效率的问题。当然“为了统一而统一”这个目的是去不掉的。, n! a1 Y: s. p! l: ?% a
一:为了那“可爱”的目的。7 I* U7 _5 l/ V. X5 A) a
还是2011年,小白菜空闲时,觉得以前用的AT24Cxx系列EEPROM的驱动不能相互兼容,你用24C02和用24C64,就得换驱动,从工程中去掉原来,然后添加上新的,相当的麻烦。于是小白菜便想,都是同一系列的产器,为什么不能用同一个驱动?
: b" ]+ R$ r4 Q6 @: p2 j于是,小白菜得到了他的目的:4 t" i- I( w' ]$ t7 Z
1编写一个能适应AT24Cxx全系列的驱动函数,对外只有两个函数,写EEPROM函数和读EEPROM函数;& ]% K. q/ s" b9 N
2移植时(包括更换不同容量的芯片)只需要改变很少的宏定义选项就能完成。* g& ]! A/ o$ X( G
二:发现共性(操作过程的比较与抽象)) d' S6 R; m: Z! E: k% w$ P" X
1为了实现这两个目的,小白菜开始看手册,并写记录下AT24Cxx系列EEPROM的一些参数,见表1和表2。$ U' `0 j1 Q$ K( Z
表1:AT24Cxx比较1 X- c/ a) a8 d/ v9 _ T
型号
) `' m+ {) o: N- ~容量(字节)7 N0 L' k: R5 L
最大级联数
+ M% n6 B0 s0 R5 g& {- H- p页字节数: o: t2 j8 P3 z p0 V
地址字节数: y! `. s$ p5 q. {( {# w
写入时间
* s% `4 G B5 M1 wAT24C018 j: U; O0 \, {( B3 r2 \2 X# M+ g8 F
128 = 0x00802 L; Z: ]8 G9 V0 J6 f
8
! D- w7 U( E. Q83 b0 R" M% {0 f% m* N# E
2
: B9 h7 Q6 Y, y. ^6 s ; w4 h' M2 k7 E- F" c3 b- Z3 L6 m
5ms
p! P* [, M( C& S5 D9 L( ^ 9 I+ T( [9 i1 V0 K0 F8 e+ A' O
(最大)
/ |, L) l" w; WAT24C020 x: j& f# c$ ~
256 = 0x0100% b. \1 j7 p6 B8 p, d* N. |
8
4 a4 P# Q. n4 b7 s) t, b8
* Y& `% w, N# D3 p- T+ v! p2( D$ w% M: u! s z6 O
AT24C04" J5 w% M; f! V
512 = 0x0200
$ h) X! i+ f5 n- @8 I q" ~$ C4) k8 L: [. p$ B
16; U( q3 m( Y6 i& x
2
2 o0 [' n# j8 e# w- T/ x+ U" [6 ~AT24C080 I. d Q3 u q5 T8 E2 g9 K! `
1024 = 0x0400: ~( G" e7 I" E% g
25 U; f# |5 ?- U9 V1 Z& P! R
16/ R3 I; a0 t4 t$ k5 ?( S2 ^
2+ a( o# g. d, C5 [/ D
AT24C16) \' G6 U- P$ U9 b7 y* f
2048 = 0x0800
* l/ ?. A N ~1 Y1 m5 x$ l+ s, B+ g, Z, T; d
16
' l" e& z# K3 w' \5 k4 }& A4 b+ B8 {2. R+ z! c6 _. y! K7 \3 x3 m2 \
AT24C32' I0 Y O5 O$ k" c
4096 = 0x1000
# _ H2 N. P: O8 w* J8
: f" C$ C8 R' g' [3 e! {328 z% b# S& U- t; r
3$ w5 e6 ~' C, Q# }4 t
AT24C64
5 p8 p3 N, S `1 \# l d8192 = 0x20003 |1 z9 c: c9 F) x9 ~- b
8
/ T- s5 Q- V7 C3 S32
0 h: Q0 ~" u5 r* y9 V) U7 p38 ?+ R$ S( P' t6 {8 j$ C. P
AT24C128
, p6 f( g+ @8 h16384 = 0x4000" V- ~0 w" j$ g) S5 d
8
2 \7 x( Q4 I" [0 R/ s* Z- j& T64
, x$ H5 T- Z5 a }3+ D2 r7 i4 Q, O5 l9 e) ?
AT24C256+ m& l& g+ O8 x" @; d
32768 = 0x80002 D4 Z0 I9 F9 \$ c
81 h- R0 _3 [3 k! V( U
64
% B5 m ^) U. t1 z4 d3) [! s$ O) b8 e
表2:AT24Cxx的IIC操作地址比较(二进制), _# D9 `! R2 q% X, g
( ]) @! Q1 Y* j- t
A2、A1、A0指的是芯片引脚,a14—a0指的是字节地址& v# \1 Z$ U4 Z5 q& }6 J3 W {. i
型号
7 E7 D$ ?/ | a6 ^4 G第1个字节+ X/ B5 f6 _, A$ I: E2 v ]
7 v, s7 w7 v7 l ?: Q C( B9 r
MSB----LSB
7 C" q9 {+ F+ U" N: N% D1 v第2个字节* g- ?7 B& l% j& Y
+ l5 N: q" [; h% ^MSB----LSB! m) W. B E( k- N" H) v. f. O
第3字节
* Y6 @: \% w1 g P; d ' H4 B4 a7 k" k4 }! J8 J- t) A( w
MSB----LSB
, o3 e5 C' n8 ~/ p3 N+ jAT24C01
I* I/ E7 ?* n* U1 0 1 0
5 f; C" ?: m* G 8 G% V8 r, D, c! |
A2 A1 A0 R/W3 ^9 z2 W) ?& }& F5 h% G1 n
0 a6 a5 a4
3 {; y. }4 j" _3 } x4 g5 K% S6 c 8 w$ I: h r- R1 M- a1 g! \
a3 a2 a1 a0- g# r9 J# t1 Q7 m' m# R* D4 ]
不发送( j: [- l' a& y; S |: @' D
AT24C02
# l. q0 {. }# r: l2 u0 ~- l& X1 0 1 0
$ ?- e9 y X, I4 x |
& I: [( L! ^+ f- I+ jA2 A1 A0 R/W
5 L- }9 k' L# z+ Oa7 a6 a5 a4+ }7 S( f7 }! I t: {2 ~
9 Y& n E E* N$ z T' `. ` ya3 a2 a1 a06 u, p" z2 ?2 o" h2 s+ O. K! x0 G% Q
不发送- d3 G1 F. Q" Z7 [( {1 X
AT24C04
$ u$ d1 v) q6 w! C1 0 1 0/ j8 K* y3 l3 S1 I6 P! N; n
! Y6 D* p' }: \
A2 A1 a8 R/W
2 ?: A3 |, P# Q! P, Z& ~a7 a6 a5 a4
- [7 h; x" E2 Y4 h$ l; n1 I! T
; K, Q, A+ ^, C! J; [5 qa3 a2 a1 a0
2 ?; W& s2 h8 C/ N4 C不发送
9 ~% U2 p4 [2 v0 C/ RAT24C08
- H" O( x b# G x9 c/ R7 f+ n1 0 1 03 F' ]! B2 t; {* m l9 _
# w8 @! H3 d% G% @# xA2 a9 a8 R/W
4 k# X$ v- G9 d" X" ^ Wa7 a6 a5 a4
% @6 E* E: c" O: X/ v# b
2 `1 I' D; N: o( t& h' ea3 a2 a1 a06 [4 }: z8 l9 V" D/ R0 U* i
不发送
3 w6 [6 R X1 ?) iAT24C16
+ K( N9 _5 c* A+ U8 H+ Q. r1 0 1 0% k3 M9 t9 p0 s/ d) I
1 L. U7 r8 A! a1 p
a10 a9 a8 R/W
* [2 B% j( G6 o1 F4 T" {a7 a6 a5 a4! X/ q! |, ?* F# Q4 |
! H3 s% H, i; Xa3 a2 a1 a0, w3 N& a# `. a! v: ?$ L
不发送7 O# q! A) f. V# T6 N! S
AT24C32. g0 _7 d4 E: z0 C' c* g+ C
1 0 1 0! S$ W( t5 l& X) C$ _7 F# s
4 S, {# l3 c# N4 k* F! v) BA2 A1 A0 R/W
( {0 W+ y) p- q6 i0 0 0 0/ U% f: n( k7 C/ [( v
# `$ \- c& L' J9 B( O4 X- ~a11 a10 a9 a8
+ Z. Y0 ?* k# j( Q9 F6 ]) `9 |a7 a6 a5 a4
( Q& O( ?. j$ [1 S7 p% v
4 J0 ^- ~. \. a2 ?. Na3 a2 a1 a0
" \, I3 B/ y0 C$ YAT24C64
( }6 h" U+ q9 q: K9 r, c1 0 1 0
1 o t8 J9 {* k, [% a 2 p, L6 d* t" w, A
A2 A1 A0 R/W
: R1 T% N1 c& H% F: d: t0 0 0 a12
+ M4 K' y+ g s 5 R/ c2 m8 r6 y: X! W
a11 a10 a9 a8
9 \, g! u$ y4 ha7 a6 a5 a4 l* w5 A7 ]4 w$ h( V( q7 W% T
, H# o/ I! I( c
a3 a2 a1 a0
) @9 O% ^$ i6 o uAT24C128
% X# X: a" j$ p6 k- Y6 [1 0 1 0
: M S0 f" P- w# n# e0 W4 e' @6 U
) O8 p( m9 r2 m% T- q3 x9 [$ g& y$ qA2 A1 A0 R/W, j6 R) N4 ]; E! p" R+ r0 _
0 0 a13 a12
# a7 Y+ k/ j A ( q6 N0 d' S& @6 D* R6 }* c5 X6 y
a11 a10 a9 a8
2 F/ f) d r- |3 c* }a7 a6 a5 a4: {7 r# ?: y5 F/ h8 F# n
( u; p: R4 ~: _) s
a3 a2 a1 a0
" r9 Y8 P+ b! e4 @4 ]) OAT24C2566 ?) y6 ~7 q' Y1 w9 X9 w; X0 j
1 0 1 01 x! e2 z$ |4 l7 @( z
3 k& X: B0 E% Z) H" V
A2 A1 A0 R/W8 Y M9 N% a, b* \$ ?* E
0 a14 a13 a12
) |4 E; a- {9 T, L( g0 H( R ! @ Q$ J, i* K
a11 a10 a9 a80 b' i( l7 ?4 B: Q: d
a7 a6 a5 a4
- e3 V- s* p/ s2 S$ x
% @' }' o5 r: {2 Z- F. b E7 s6 o$ ga3 a2 a1 a0) O% S5 c* P: y- y6 t. f
由表1和表2,小白菜开始想,不同容量的需要进行地址处理和页处理。小白菜还设想,在应用中,不大可能不同容量的EEPROM一起使用;有可能访问的数量大于芯片容量,所以要有溢出检测……小白菜想了很多,并整理了一个大体的思路。
6 ?: M) N! ?: w* a% o! b读写函数 → 先要进行参数检查 → 进行溢出检测 → 地址处理 → 读写数据( → 写数据时写入等待) → 返回操作状态。% G0 L6 V1 j( h9 N
三 代码编写% @% s( `- F+ p* J3 G; o/ M
小白菜用上面的流程,开始了代码的编写。写代码时,地址处理部分需要使用条件编译来实现不同芯片的操作;写入等待函数需要有超时机制……写啊写,写啊写,小白菜终于写出来了。列位看官,请继续向下看。
: ~+ }, P) u" n! }& @* K2 V, G四 使用说明; v# e4 w! q2 f% y
4.1 移植修改 移植修改在H文件中的“移植修改”部分。这里有5处需要修改。' h" c* J6 B0 }5 B2 E/ |
//----------------------------------------------------------------------------//% b8 @4 U" r+ R5 X
// 编号:1( y n L% r: B# P( h \* J
// 名称:4 u3 _3 p/ v" s
// 功能:单片机寄存器头文件,例如reg51.h# ^4 _$ z/ b( z; |6 c
//----------------------------------------------------------------------------//
* O5 F5 y0 @: L& [0 j" ^#include "ATT703x.H"
; ]; K1 S8 u, Q3 C4.1.1 请您把使用的单片机的头文件包含进来。大虾们用过MCU 多了,知道不同的MCU,其寄存器定义是不一样滴,不是所有的51 单片机都用Reg51.H 或Reg52.H 头文件。) x2 C+ Q5 C( O9 T3 @
//--------------------------------------------------------------------------//
' U& J7 p: R! @- `// 编号 :2
8 a& |1 T. Q/ v// 名称 :AT24Cxx/ P) f# O3 E1 M# O& a% p
// 功能 :选择您所使用的EEPROM芯片型号。只能启用一条宏。
" ?/ j; t" C5 q; G// :不支持一条总线上挂不同的EEPROM,支持同类型的多个EEPROM挂在总线上。, c& H5 j' ]) d8 q% g) o
//--------------------------------------------------------------------------//
! O9 Q& z# Z( p2 E! g# y% p( d// #defineAT24C01 // 使用AT24C01,则启用本句并屏蔽其它语句。
" i5 [$ o# n2 u// #defineAT24C02 // 使用AT24C02,则启用本句并屏蔽其它语句。4 x9 V- D. ?6 g; P& S
#defineAT24C04 // 使用AT24C04,则启用本句并屏蔽其它语句。
: [, w/ n$ |% }( {+ c7 M- o2 o// #defineAT24C08 // 使用AT24C08,则启用本句并屏蔽其它语句。4 z0 s* ~! Z2 L' s4 s5 W
// #defineAT24C16 // 使用AT24C16,则启用本句并屏蔽其它语句。
+ Z' E3 G( v* R% R& B) l# q9 Y// #defineAT24C32 // 使用AT24C32,则启用本句并屏蔽其它语句。* R* T6 w1 M+ d3 Q* E1 E
// #defineAT24C64 // 使用AT24C64,则启用本句并屏蔽其它语句。
) Z R, Z) A; [0 e, E( ~' {$ v// #defineAT24C128 //使用AT24C128,则启用本句并屏蔽其它语句。
. k/ F# ~/ d, a- T3 F F4 T# t// #defineAT24C256 //使用AT24C256,则启用本句并屏蔽其它语句。" Y! B$ r% y* p+ K
4.1.2 这里启用您所用的芯片。不支持不同容量的芯片挂接在同一总线上。3 y# r* M, o: b6 B& O z8 h9 {
//--------------------------------------------------------------------------//3 X0 z! D7 Y/ ?8 W
// 编号 :3
- p1 c) L! l3 j! |$ |) q6 J// 名称 :AT24CXX_WP_ENABLE1 F2 b$ K3 M1 B2 ^
// 功能 :启用AT24Cxx的写保护功能。为1时启用写保护。为0时不使用写保护。, I# |4 o' G* }) ` s. R
// :当WP引脚接地时,请禁用写保护功能。否则会浪费系统资源。
, N6 o. j; x8 @% \//--------------------------------------------------------------------------//
; ^" k! h. i" Y4 ^* m/ `( S3 e# k#define AT24CXX_WP_ENABLE (0)& u4 M* g$ a4 c( p- L
//--------------------------------------------------------------------------//
9 \: |. P7 x" L9 K* q o// 编号 :4
4 z" n5 \4 a# X// 名称 :AT24Cxx_WP7 w9 B. p( S2 y6 y; Y, ?" J
// 功能 :写保护引脚所用的口线。启用写保护时,才需要设置本参数: L4 B s: l' I7 z% ~; K" p
//--------------------------------------------------------------------------//
2 N8 @, Q4 Q& B9 k+ ~9 o#if (1 == AT24CXX_WP_ENABLE)' a: \7 f! E- w
sbit AT24Cxx_WP = P1^2;1 ~3 ^, e) d. R y8 t
#endif3 y( [# C6 e+ U* e* r
4.1.3 这里是关于WP的操作,您可能并不使用写保护并把WP接地。如果AT24CXX_WP_ENABLE为0,即不使用写保护时,写入允许和禁止函数不编译。如果您为了减少改动,也可以把这两个函数体进行条件编译,而只留下一个“空函数”。
5 D8 s; M9 [- \) G//--------------------------------------------------------------------------//% x- P: V4 q; T& D* c* w" N
// 编号 :5- @7 g J7 D# L2 M' O
// 名称 :AT24Cxx_Delay_1ms()1 @ e8 p% m; T9 |" l; Q
// 功能 :精确的1毫秒延时函数。这里请使用您系统中的微秒延时函数。
4 [3 R- n! }' V) c+ B. i// :例如,您的延时函数是Delay_1us(),那么您可以使用下句2 m/ {% n" i$ F
// :#defineMK_Delay_1us() Delay_1us()
5 H) l9 J+ W2 e" X% Z// :来实现延时。* V, z. ?' V# p8 L
//--------------------------------------------------------------------------//
7 w# O: m, [# N0 @: _% i#include "Delay.H" // 您系统所用延时函数声明所在的头文件。
1 h% h# A) I' [4 A( j* M* u#define AT24Cxx_Delay_1ms() Delay_MS(1). f9 S* o' u- o9 _
4.1.4 这里的软件1ms延时函数用于写入等待。延时必须在1ms左右。
. V3 k3 R0 V( ]& l1 p+ Y) H O4.2 函数说明
v7 H6 V- C7 M/ c4 \0 C4.2.1 从AT24Cxx中读取数据函数
1 o: Y. F% m' j//----------------------------------------------------------------------------//
" l( T' D4 D) f- R9 @; K// 从AT24Cxx中读取多字节数据函数(对外接口)% ]* v3 n3 s, m" r
//函数名称:AT24Cxx_Read_Str; Z( z) E8 x* T- ]3 ~! Q
//函数功能:从Addr指定的地址开始读取AT24Cxx,一共读取Num个字节,数据读出后存0 j6 \- Z' b2 H* f/ o) h' m
// 放在PDat数组中。% g1 Q/ `; |/ G( c& L V
//入口参数:1 @4 E0 f# W1 \# H4 C' H3 q" R
// A2A1A0:对应芯片A2 A1 A0引脚,低3位有效(高位被忽略).
& P* Q& c: }7 D2 E1 i$ _7 g# I+ w// Addr:对24Cxx进行读操作的起始地址。
) C. y: `1 P6 U: f3 H! m$ y// *PDat:数据读取后存放的首地址
0 I: h. n0 q+ y# \1 G3 }- j; Z// Num :要读取的字节数+ G, x5 i- `; H5 G, k
//出口参数:0 = 成功,1 = 失败。
( C1 @. g0 S2 B9 i' D//重要说明:1.读取的第一个字节放在PDat[0]中,第二个放在PDat[1]中,以此类推。
6 f1 |& @9 p h3 y// :2.若EEPROM剩余空间不足,函数报错。
1 k$ v [) U7 }: T//----------------------------------------------------------------------------//
: ~# N3 I. {1 j9 ?6 Y3 fextern uint8 AT24Cxx_Read_Str(uint8 A2A1A0, uint16 Addr, uint8*PDat, uint16 Num)
0 T+ Q3 b- }3 r3 J, ~4 C3 y第一个参数A2A1A0的低三位分别对应A2、A1、A0,并且不能对该参数进行检查,所以一定要设置正确。
3 X( S- U0 u8 `) o应用示例: r( @# T2 z+ l2 V K2 c
芯片的A2、A1、A0接地,并且从0x10地址开始读取,读取的字节数50,数据读取后存放在unsigned char Buf[100]数组中。
# l9 ]% R h& H解析:由于A2、A1、A0接地,所以第一个参数为0,函数调用是
Q! I7 o& V) E8 l+ y/ _AT24Cxx_Read_Str(0, 0x10, Buf, 50)( q7 i- ]* R4 i/ B {) o+ E
Buf中存放的EEPROM中(0x10 + i)单元的内容,# `- l2 i1 q# A0 }' _2 s6 l
4.2.2 向AT24Cxx中写入数据函数' s5 w7 ~" C6 p1 y# i5 j
//-------------------------------------------------------------------------------//
& I, _8 J9 a! n: Z// 向AT24Cxx写入多字节数据函数(对外接口)1 p0 G. c6 ~8 |5 f' M& g
//函数名称:AT24Cxx_Write_Str1 S# `0 t: ^* L% p- F
//函数功能:向AT24Cxx中写入多字节。写入的起始地址由Addr确定,数据存放的首
% F* o5 \0 V2 ~, `' A5 V" n// 地址在PDat中存放,写入的字节数是Num(16位无符号数)。
# q |- }+ | P+ C; \//入口参数:
* x% | Y, C' m' k3 ?// A2A1A0:对应芯片A2 A1 A0引脚,低3位有效(高位被忽略).5 R8 k$ q8 v: \3 k3 c$ |
// Addr:对24Cxx进行写操作的起始地址。
4 e1 F' Z' b# q+ n// *PDat:发送的数据存放的首地址
9 I3 V1 r/ j; M# T% Y g// Num :发送的字节数
$ T8 {/ u7 o$ ~//出口参数:0 = 成功,1 = 失败。
! u3 [3 j0 B, q//重要说明:1.先发送PDat[0],再发送PDat[1],以此类推。2 H3 l) Q9 H* V: o, {) W, _ z
// :2.若EEPROM剩余空间不足,函数报错。
. ?) f9 G9 _: ~6 [ e; K+ ^' [// :3.若启用了写保护功能,必须先使写保护失效,否则无法进行写入。
9 h8 a; o0 v5 y3 H//-------------------------------------------------------------------------------//
8 U; N2 B% L) v% v* h8 b O5 eextern uint8 AT24Cxx_Write_Str(uint8 A2A1A0, uint16 Addr, uint8*PDat, uint16 Num)
9 p0 f+ @% y5 c第一个参数A2A1A0的说明见4.2.1。
% `4 @0 U/ a3 k- g3 H4 _若启用了写保护功能,在调用本函数必须调用写入允许函数,否则函数写入出错。
5 d1 u9 w3 `: e; H; C应用示例:2 ]1 M; ^; h9 G) t' p
芯片的A2、A1、A0接地,并且从0x10地址开始写入,写入的字节数50,写入数据存放在unsigned char Buf[100]数组中。Buf写入EEPROM中(0x10 + i)单元。, b* v- w: ]5 [
解析:A2、A1、A0接地,所以第一个参数为0,函数调用是
' N' U e" U9 J" oAT24Cxx_ Write _Str(0, 0x10, Buf, 50)
( c( C2 C5 Z$ M+ ?4 ^3 Z- _4 e4.2.3 AT24Cxx定义允许禁止函数. | r: B# ]3 Y+ u# |6 i7 O
extern voidAT24Cxx_Write_Enable(void); // 允许写入。
* B4 \: `( \" v9 S a' rextern voidAT24Cxx_Write_Disable(void); // 禁止写入。
1 \1 K4 t$ w9 c# z! S$ O8 r0 r. z2 }这两个函数是写入允许和禁止函数,实际是操作WP引脚。您也可以改为宏定义,这里小白菜就不弄啦。这两个函数受AT24CXX_WP_ENABLE的控制。AT24CXX_WP_ENABLE为1时,即打开写保护,当写入时,必须先调用AT24Cxx_Write_Enable()函数,以使能写入。
& i) q0 q% E) a# g( k! ]这对函数应成对的调用哦(就像进入和退出临界区函数一样),要不然写保护有没有意义了。
- B$ U, L* T! g; J2 R% G五 最后的有用的话+ y7 z0 A4 j5 @0 C: b7 V
这套驱动,小白菜只测试过AT24C64和AT24C04,其他并没有测试过。所以要慎用哦。欢迎各位童鞋进行拍砖!要是有Bug,小白菜也非常希望大家能给小白菜说一声哦~
& [ |. O1 j( p6 |/ y! }' {
; v! X9 f3 {' w% Y8 P/ S. ` |
|