|
EDA365欢迎您!
您需要 登录 才可以下载或查看,没有帐号?注册
x
小白菜的EEPROM学习之路
% `8 Q* a/ Y, b& O \) |8 ?2 m8 a AT24Cxx全系列驱动编写
) }8 s9 B. Z5 u上回书说到了标准IIC的编写,函数参数是指针和字节数,并非是以IIC地址和寄存器地址作参数,何故?小白菜考虑着,要想真正的适应大部分IIC器件的IIC操作而不必写两个功能相同的函数,用指针和字节数作参数是最好的选择。大虾们可能觉得这是为了统一而统一,这点必须承认。在参数传递效率上,确实比直接传递数据要低,但是小白菜接触到的IIC器件,没有一个是需要时时写入的(这里的时时是指MCU空闲下来就读取或写入IIC器件数据)。用的最多的是EEPROM、还有xxx7290(键盘数码管扫描芯片)、铁电存储器,测温芯片。这些器件没有一个是需要实时操作的,也就是说小白菜接触的IIC器件对实时性要求不高。于是,小白菜可以忽略参数传递效率的问题。当然“为了统一而统一”这个目的是去不掉的。) Y4 c$ C: ^; f! F
一:为了那“可爱”的目的。
1 [4 l$ p9 _: X/ h" U) D还是2011年,小白菜空闲时,觉得以前用的AT24Cxx系列EEPROM的驱动不能相互兼容,你用24C02和用24C64,就得换驱动,从工程中去掉原来,然后添加上新的,相当的麻烦。于是小白菜便想,都是同一系列的产器,为什么不能用同一个驱动?% \% j9 V% k+ P0 n( K* ]
于是,小白菜得到了他的目的:9 [. Y8 f5 W- b- e, |+ K
1编写一个能适应AT24Cxx全系列的驱动函数,对外只有两个函数,写EEPROM函数和读EEPROM函数;/ M2 W& d% x7 F: j
2移植时(包括更换不同容量的芯片)只需要改变很少的宏定义选项就能完成。0 [$ V1 |5 c3 w6 w
二:发现共性(操作过程的比较与抽象)
% V' s$ D9 |+ B+ O. X1为了实现这两个目的,小白菜开始看手册,并写记录下AT24Cxx系列EEPROM的一些参数,见表1和表2。$ ` p9 Z) m. [# a3 u
表1:AT24Cxx比较9 w0 }$ [5 ?3 Y
型号
" @0 Z5 O4 ?$ d* V' }) K2 q% y# R1 v容量(字节)
. N3 Z5 ]* o) s最大级联数* Z9 y$ {! a1 K/ x. ^
页字节数
9 O5 k5 z( p2 G8 `0 X& ?地址字节数, H; h& j0 H$ J- a6 ?* L! w$ m% j2 {
写入时间1 \* j" L* a! {7 e: P
AT24C01! i, J2 a5 X p4 r; l
128 = 0x0080
9 d/ C) Y1 l4 k8 N! o8- q" m. N! ~7 P3 ^7 D
8: L; @# `" [$ c
20 ~& o% W" ^! q0 t7 ^
$ d8 x, R8 K0 e& f5 u0 {
5ms
" N0 V& w& @! S v- X ) c! r4 v# ~# ^0 |$ z T4 h9 t
(最大)! y q7 x3 ], Q" @
AT24C02
+ @5 B, ]9 O8 S256 = 0x0100
* H) I2 I9 f% T8 d8
2 @7 H5 {" E1 n* N8
9 [ Y6 i( O# R4 A2 c24 K$ G% T/ B2 F9 G
AT24C04: q+ l7 H; x6 |1 d( e+ [$ ^/ ~' a
512 = 0x02008 t# B5 I. ^6 P& {4 ^4 Q4 k
4
; J$ l( K7 T2 w" O+ t16
. S( g& T$ k j& c! R' t24 P: E1 q6 _- ]) n
AT24C089 k9 d0 r& u" K3 H* U) n) W7 Z
1024 = 0x0400& F! G* z8 s$ J6 [, |9 X
25 \5 |8 m7 m( V2 s& v7 u
161 ^: e: d+ c3 Y7 s+ a# T+ s
2/ U, {8 F; t0 ]* F3 r- a ]
AT24C16
# B' S5 e) d7 F( Q+ y& a2 c- |3 T2048 = 0x0800
9 n6 j J) n( y: L: ?% _1 N7 n; a* I+ V: b
16
9 U1 F/ j7 d, p6 w6 T5 A& O2
* W& _$ s* N0 [AT24C32
8 F1 Z( [& Q1 S( R5 r4096 = 0x1000/ k& ]' Z8 j6 c
8
& A3 d7 m- x, _- C3 P! T" }32
2 o; L3 [" |( ?3/ X; c# E2 G9 u S% e$ x
AT24C64: |% F& u3 |8 \ t0 L [
8192 = 0x2000" I1 t3 K* Y" r/ d+ o
8. Y* f: E% b2 w
327 |8 \7 Y& b2 D( r
3
3 z) Y6 }2 C! f" {AT24C128
4 ?$ o( O& R9 I8 l% E16384 = 0x4000
: z3 L; L8 \+ f+ P O/ a+ F7 D8( M C( _8 y0 d
64
! O: ]' n {4 g* k t: I9 M0 W3$ p" D0 W/ n, G. e4 c3 n
AT24C256# w( [' g' u$ j5 y) K2 ~2 i
32768 = 0x8000
# e3 B4 F& \% Q8$ W w1 H, E) R( e
64! A# c* m ~. n" ?' i! G7 N
3
2 o5 ?* t8 r+ q/ x表2:AT24Cxx的IIC操作地址比较(二进制)' F& X" B) t u* x, O+ F
X! v; n/ C% c q" d+ ZA2、A1、A0指的是芯片引脚,a14—a0指的是字节地址
, `: P7 s- X; P型号' I* F/ _3 ]/ ?7 S- G
第1个字节, J& q/ Z: w4 }" h
5 p! H% I9 L6 _: Q+ T/ _+ f. g
MSB----LSB
" C9 p$ ^* E2 Y' ~$ g/ e3 @第2个字节
5 T+ [5 A2 f, T! O3 R; o% T
Q( p0 ^/ D, `4 nMSB----LSB
- O; G. U4 B- q- H: o1 H第3字节
J y0 F+ W/ B# V; u+ E
% E/ W( ^/ z8 O+ pMSB----LSB
3 b3 P0 C0 U6 t9 m( sAT24C01! ?% C$ K2 j; j/ O: h; q
1 0 1 0
$ C, a' O- n9 G6 J; h
' e; \* V# U$ w @( NA2 A1 A0 R/W
, l- ~! V/ v" D- g: t! ?& I4 m4 U0 a6 a5 a4 G( \4 W; N+ `
/ f/ ~ ^) G$ `9 f: T2 c; F
a3 a2 a1 a0
, N9 J0 ]$ E$ f u, h% M, [ T不发送
3 u- q; Z! i3 X$ M7 s( N) NAT24C02# ^& e2 N) r; K1 s2 r3 B/ Y: K
1 0 1 0
+ B3 l4 d0 ]6 k
! U: T( p5 R1 h% qA2 A1 A0 R/W9 J/ W, G3 [( o
a7 a6 a5 a4" Z' E" ^. `# E- Q
7 s8 a( X/ }: i5 a1 [5 Ka3 a2 a1 a01 u9 v! F. T+ i7 F+ l
不发送* ^; |& N; |2 y
AT24C04, O7 B9 v- {: C! s6 }1 ?, S
1 0 1 0
9 ~6 S# J( b5 q( \ ! C1 Y i, R* F
A2 A1 a8 R/W$ t. H4 b H6 I i5 X0 R1 b
a7 a6 a5 a4
u* D9 J- ]7 D0 Y
! D3 c& G+ B5 `4 g% k3 |a3 a2 a1 a0
! P) U. X; @% ^* U不发送
, \- y4 w7 d& h8 d) \ lAT24C08 f0 R. K, D* e, ^# [, S! a8 \7 k
1 0 1 0: `/ ]7 p3 d- _ O
' Z) f- b! e9 G, o3 @' ]
A2 a9 a8 R/W# S9 U! q7 v$ K1 e+ E/ e
a7 a6 a5 a4
- N. y# ?" C2 X# t 9 ?2 e7 p. J+ p: p: q
a3 a2 a1 a0* B& k% l; z2 [* | w: |
不发送
3 ~5 I; ~4 `$ [# L# NAT24C16
# [+ Y+ A& J2 z) i. ~( F1 l9 P1 0 1 0
5 r C1 X8 e) |, d 0 P: D9 V4 U9 a. W& c+ G% D8 L/ D' u
a10 a9 a8 R/W9 P; _" h4 [. ~ d3 x2 ?
a7 a6 a5 a4
/ s4 \9 a: o% y* q2 Z5 M, e m9 V- S# N1 u1 }$ i/ C3 z
a3 a2 a1 a0
7 k& `6 F4 u, t不发送' F. r t' Y" E, @
AT24C32
6 \$ J* `! M, [' A) }1 0 1 05 Z/ z8 E- s- q/ g
: h# g+ P" { B' L! J# E
A2 A1 A0 R/W8 I* U# T; O2 \7 f
0 0 0 02 m1 p9 v4 ~- l7 v. o5 R
4 [( Y4 l! e, `5 n+ z9 n- f7 Y
a11 a10 a9 a8
4 P( O O, Y: R0 aa7 a6 a5 a4
( ^* y; @7 [0 e" B- G# R 6 ^ f' A8 o0 H2 ?+ a
a3 a2 a1 a09 m) l0 k" y, f0 f2 W' M* C
AT24C64
" `$ J( G" P% v9 s1 0 1 07 ?/ v) m- q- H; n/ @+ o& B2 g5 b
( c$ I) y) c' a! _1 }A2 A1 A0 R/W- m N* q) @! j
0 0 0 a12
& m7 H; L0 P# v" g: Z$ J' { : ]! ^! P" P: D, U6 m2 h
a11 a10 a9 a8& g! A( g' z7 L' _3 l
a7 a6 a5 a4
9 p5 m( J- S4 Y' Y
" u$ O8 L" [: t. o- c& x# p8 M" @3 D1 R( Na3 a2 a1 a0: V+ U# H- j, O) \+ l2 g( c
AT24C128
0 }/ q1 c$ [) j" E1 0 1 0
+ l2 E5 b' u/ W
5 Z6 z) s9 o& F, NA2 A1 A0 R/W4 ]. y: T b% I& J1 Y- `/ n
0 0 a13 a12
- I# [: L, a; v+ T0 e$ I& C
# F! m6 z* ~$ a" n: ua11 a10 a9 a8/ R1 B$ H$ A4 s4 w; F2 g
a7 a6 a5 a4
( o4 `# H# l- h- T1 N# U4 G
4 {& C5 Q7 C. ~' Oa3 a2 a1 a0" V9 a1 j% m& {
AT24C256
) l+ y# f7 `. Q- ~3 U e# r( @1 0 1 0) R8 x2 y$ @+ d5 K# ^% f
4 b' y' w& r) V+ g* pA2 A1 A0 R/W8 t F* h) Y5 f3 R" ]0 }! Q1 a/ m
0 a14 a13 a122 f; F1 a4 s7 v% j' O. M0 s
q- F. I* l1 g2 j9 B
a11 a10 a9 a8* Q7 s$ ~* _* O
a7 a6 a5 a4/ k9 g) o" E! z7 _ P/ `
% X+ E$ m8 t) W- C( W
a3 a2 a1 a0! Z3 h9 C- W* R
由表1和表2,小白菜开始想,不同容量的需要进行地址处理和页处理。小白菜还设想,在应用中,不大可能不同容量的EEPROM一起使用;有可能访问的数量大于芯片容量,所以要有溢出检测……小白菜想了很多,并整理了一个大体的思路。
2 T9 s+ {4 ?4 c+ X/ F1 I读写函数 → 先要进行参数检查 → 进行溢出检测 → 地址处理 → 读写数据( → 写数据时写入等待) → 返回操作状态。
- C- O! j( c% {: k y+ ?- z8 v三 代码编写6 \2 j: b" K* l, l( H
小白菜用上面的流程,开始了代码的编写。写代码时,地址处理部分需要使用条件编译来实现不同芯片的操作;写入等待函数需要有超时机制……写啊写,写啊写,小白菜终于写出来了。列位看官,请继续向下看。& `1 c& p4 B! u0 v
四 使用说明% i+ U5 [, i U4 U
4.1 移植修改 移植修改在H文件中的“移植修改”部分。这里有5处需要修改。
! L5 O. _( ]2 ]2 z2 b//----------------------------------------------------------------------------//
! x. U( R g( h( G// 编号:1
. o! r; J! W. ?7 J// 名称:
+ V: T) f; ?1 E& u// 功能:单片机寄存器头文件,例如reg51.h
. D; b) h" }" U( f. b4 O+ H/ Y, B//----------------------------------------------------------------------------//+ @& V5 o5 m$ o7 ?& ~3 ]
#include "ATT703x.H"4 s- R# \3 i L2 I
4.1.1 请您把使用的单片机的头文件包含进来。大虾们用过MCU 多了,知道不同的MCU,其寄存器定义是不一样滴,不是所有的51 单片机都用Reg51.H 或Reg52.H 头文件。
c- h6 Y" h- L+ w3 b//--------------------------------------------------------------------------//3 U I* O8 O$ w9 g. |
// 编号 :2: S1 @3 W4 I; u* k1 G7 j2 z
// 名称 :AT24Cxx
2 D% I9 ~& ^; d% s6 n s+ e" V// 功能 :选择您所使用的EEPROM芯片型号。只能启用一条宏。, Q% T. ?; E4 V# M3 @/ I, i( C
// :不支持一条总线上挂不同的EEPROM,支持同类型的多个EEPROM挂在总线上。/ |4 X! N. F/ ^: z$ i9 H2 X6 ~, u8 C
//--------------------------------------------------------------------------//5 J1 C& A$ k$ a) i8 y& X2 N+ s! n
// #defineAT24C01 // 使用AT24C01,则启用本句并屏蔽其它语句。 G# ^, e# q7 |/ q. |7 N
// #defineAT24C02 // 使用AT24C02,则启用本句并屏蔽其它语句。! ^2 o7 Y1 l6 ~
#defineAT24C04 // 使用AT24C04,则启用本句并屏蔽其它语句。
% O/ J9 q( F! h0 x8 l4 X# i+ w// #defineAT24C08 // 使用AT24C08,则启用本句并屏蔽其它语句。
' h+ N+ ^2 g4 C7 S: ] T// #defineAT24C16 // 使用AT24C16,则启用本句并屏蔽其它语句。
! ]4 x$ w* @/ A8 R( V// #defineAT24C32 // 使用AT24C32,则启用本句并屏蔽其它语句。3 U* }$ A) d9 f$ Y6 l
// #defineAT24C64 // 使用AT24C64,则启用本句并屏蔽其它语句。
' a! D7 G9 s1 t6 {, C+ i8 V// #defineAT24C128 //使用AT24C128,则启用本句并屏蔽其它语句。2 Z0 I' y& C* K4 \# L. Q3 a0 Z
// #defineAT24C256 //使用AT24C256,则启用本句并屏蔽其它语句。
" \( m8 o' z/ l4 Z2 A% c" P; X4 H4.1.2 这里启用您所用的芯片。不支持不同容量的芯片挂接在同一总线上。4 y7 d) _' f' n0 m0 e& J; _
//--------------------------------------------------------------------------//
3 ~3 p* U" r4 V1 R: K// 编号 :3
, m0 e4 f! j7 U: C// 名称 :AT24CXX_WP_ENABLE
% D/ y5 R; L* u# c, E. X0 q# H// 功能 :启用AT24Cxx的写保护功能。为1时启用写保护。为0时不使用写保护。
# v4 q' D; I ?, d2 w// :当WP引脚接地时,请禁用写保护功能。否则会浪费系统资源。
4 [$ E: \$ ?9 k- C//--------------------------------------------------------------------------//+ U: X a. U1 _5 ~$ h
#define AT24CXX_WP_ENABLE (0)2 A2 J6 d# @# r2 ~
//--------------------------------------------------------------------------//
, B7 A" B! k7 E// 编号 :4
$ ~* d {0 h3 ? G+ l// 名称 :AT24Cxx_WP8 I u$ u9 N2 p# g
// 功能 :写保护引脚所用的口线。启用写保护时,才需要设置本参数
) g8 i& |# J- u3 P//--------------------------------------------------------------------------//9 B, \- ]8 l; o
#if (1 == AT24CXX_WP_ENABLE)
1 ?1 _9 F% p$ ~' h; ~4 ~ sbit AT24Cxx_WP = P1^2;, r' E' M( X( s+ G4 l9 m
#endif5 {# E7 \( }. y5 t L2 I" o
4.1.3 这里是关于WP的操作,您可能并不使用写保护并把WP接地。如果AT24CXX_WP_ENABLE为0,即不使用写保护时,写入允许和禁止函数不编译。如果您为了减少改动,也可以把这两个函数体进行条件编译,而只留下一个“空函数”。' k, @9 O; u; u, I( X9 p5 n
//--------------------------------------------------------------------------//
7 v K# W9 k3 R5 D// 编号 :5: w5 n- u: y0 V( J# G3 G8 k; W
// 名称 :AT24Cxx_Delay_1ms()+ {) F4 i1 q2 [( n8 {
// 功能 :精确的1毫秒延时函数。这里请使用您系统中的微秒延时函数。
+ e( l( b6 u* K5 v1 G5 u// :例如,您的延时函数是Delay_1us(),那么您可以使用下句/ F$ u: ?4 T' ?
// :#defineMK_Delay_1us() Delay_1us()8 {1 N- J1 f9 j D; @# l
// :来实现延时。
$ C, [- @- v$ f7 V( S W) {, i$ p9 \//--------------------------------------------------------------------------//5 z6 ?0 J9 R( J
#include "Delay.H" // 您系统所用延时函数声明所在的头文件。' M/ C2 g7 c F- j, h
#define AT24Cxx_Delay_1ms() Delay_MS(1)) _" S" x2 o7 H9 c# j
4.1.4 这里的软件1ms延时函数用于写入等待。延时必须在1ms左右。. e) K* `3 u' g: I9 U
4.2 函数说明 # \& {9 S. U8 L( H
4.2.1 从AT24Cxx中读取数据函数, }% ^' h3 x( U! z; C3 ?
//----------------------------------------------------------------------------//. i# m" }, v! ~( o: T! p; u% I
// 从AT24Cxx中读取多字节数据函数(对外接口)
; U! ^ I* q& Y//函数名称:AT24Cxx_Read_Str6 p2 x8 m& D `1 c* |$ w9 ~
//函数功能:从Addr指定的地址开始读取AT24Cxx,一共读取Num个字节,数据读出后存1 o/ ^ ?/ G6 L3 y- Z4 s4 H
// 放在PDat数组中。& q9 u+ [9 o5 [& z+ ~* ~: s
//入口参数:6 h# s$ Q' [+ E# o% j
// A2A1A0:对应芯片A2 A1 A0引脚,低3位有效(高位被忽略).* Z0 h: e( D* `2 k4 A
// Addr:对24Cxx进行读操作的起始地址。+ e+ Q( j8 {. {) ~3 u
// *PDat:数据读取后存放的首地址
7 x2 \7 M, K' |# z// Num :要读取的字节数
7 \ D9 G, |+ w- Y/ Y8 g//出口参数:0 = 成功,1 = 失败。& U _# L5 U! y- U7 S+ \# y- @
//重要说明:1.读取的第一个字节放在PDat[0]中,第二个放在PDat[1]中,以此类推。
" O- E! B2 G( }9 {) d// :2.若EEPROM剩余空间不足,函数报错。
1 _+ ^3 I0 H$ h0 o9 L6 a0 H//----------------------------------------------------------------------------//
% R( j# s. k/ ^% ^, {9 A7 H( wextern uint8 AT24Cxx_Read_Str(uint8 A2A1A0, uint16 Addr, uint8*PDat, uint16 Num)6 U6 y! x5 `% }1 M3 n
第一个参数A2A1A0的低三位分别对应A2、A1、A0,并且不能对该参数进行检查,所以一定要设置正确。& ^1 `& L' r) {7 g0 v
应用示例:
& ^: o8 v8 @$ m2 n* K% _8 p 芯片的A2、A1、A0接地,并且从0x10地址开始读取,读取的字节数50,数据读取后存放在unsigned char Buf[100]数组中。
& w& G; H0 M2 O( E/ ^解析:由于A2、A1、A0接地,所以第一个参数为0,函数调用是% q& ~9 j; Q* {! r" b8 m
AT24Cxx_Read_Str(0, 0x10, Buf, 50)) S3 d0 ~5 p! M3 f
Buf中存放的EEPROM中(0x10 + i)单元的内容,& s/ W; F, H) W' g' i
4.2.2 向AT24Cxx中写入数据函数
/ O% V2 a" o4 O: O3 F0 ?//-------------------------------------------------------------------------------//
' d* S$ R2 i: W4 y O& O. }// 向AT24Cxx写入多字节数据函数(对外接口)" y" R$ q7 S" U: P" h; J9 N
//函数名称:AT24Cxx_Write_Str$ L# W( P5 m9 D! o
//函数功能:向AT24Cxx中写入多字节。写入的起始地址由Addr确定,数据存放的首
" |8 c' f' z/ q5 C8 H U// 地址在PDat中存放,写入的字节数是Num(16位无符号数)。3 Q+ R+ L4 `2 h9 I0 F0 H1 s, X
//入口参数:7 r7 n5 a7 q# A- K, s7 i0 D& H4 U
// A2A1A0:对应芯片A2 A1 A0引脚,低3位有效(高位被忽略).% ^& F" _' ]8 c( r9 W5 v0 C
// Addr:对24Cxx进行写操作的起始地址。
+ W: ?: m' C% f" r: ^// *PDat:发送的数据存放的首地址( n- C# \; q' d6 n+ _* R: K
// Num :发送的字节数; i. \& ?1 L) ]/ m8 ^8 T
//出口参数:0 = 成功,1 = 失败。$ ^5 G0 ?7 x3 f X$ ^7 g
//重要说明:1.先发送PDat[0],再发送PDat[1],以此类推。
6 a9 r( z! F+ D k- i3 q// :2.若EEPROM剩余空间不足,函数报错。" N% p4 \4 s& J: F
// :3.若启用了写保护功能,必须先使写保护失效,否则无法进行写入。
! k4 i7 F' y% }# g+ L//-------------------------------------------------------------------------------//: N+ O' Z8 d! O+ U1 C$ Q: o
extern uint8 AT24Cxx_Write_Str(uint8 A2A1A0, uint16 Addr, uint8*PDat, uint16 Num)
. \2 w J) l; q* Z第一个参数A2A1A0的说明见4.2.1。
) F9 x4 s. t" l9 L若启用了写保护功能,在调用本函数必须调用写入允许函数,否则函数写入出错。
. I1 m Q# e6 i, S/ ?3 [) H9 G应用示例:+ z/ m4 t6 e( w* p8 {1 P- o6 c
芯片的A2、A1、A0接地,并且从0x10地址开始写入,写入的字节数50,写入数据存放在unsigned char Buf[100]数组中。Buf写入EEPROM中(0x10 + i)单元。, r" v; Y- x& R' m! I
解析:A2、A1、A0接地,所以第一个参数为0,函数调用是
2 \% f6 Z7 P/ dAT24Cxx_ Write _Str(0, 0x10, Buf, 50)1 Y- s- f/ @0 p! V' g. C
4.2.3 AT24Cxx定义允许禁止函数
+ _% t+ S. R& y0 uextern voidAT24Cxx_Write_Enable(void); // 允许写入。8 _6 }2 F( W# K' A& u/ G
extern voidAT24Cxx_Write_Disable(void); // 禁止写入。
L; l0 q# z" C" J这两个函数是写入允许和禁止函数,实际是操作WP引脚。您也可以改为宏定义,这里小白菜就不弄啦。这两个函数受AT24CXX_WP_ENABLE的控制。AT24CXX_WP_ENABLE为1时,即打开写保护,当写入时,必须先调用AT24Cxx_Write_Enable()函数,以使能写入。
! w0 _$ \) }* ^2 i这对函数应成对的调用哦(就像进入和退出临界区函数一样),要不然写保护有没有意义了。
- T& C! Y {- _8 ?: l五 最后的有用的话
' `1 v' H' q6 R& y4 H; ^这套驱动,小白菜只测试过AT24C64和AT24C04,其他并没有测试过。所以要慎用哦。欢迎各位童鞋进行拍砖!要是有Bug,小白菜也非常希望大家能给小白菜说一声哦~
7 ^9 ?7 k! F/ |; n7 T' ?! K5 u7 ^. X: @/ E& k
|
|