|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
关于单片机EEPROM数据保存的若干经验总结 附带stc单片机程序1 w6 C# J4 {! S, }
* c9 D' N8 i4 Y1 g/ [0 h6 g8 Y
( a; {: ^- r; j2 ?- u* h
因为要保存的数据可能是千变万化的,字长可能从8位到32位,其中包括char(8)、short int(16)、 int(32)、float(32),而不同数据类型在不同体系架构上字长各不相同,复杂点的甚至包括结构体Struct,! R5 o/ K4 v2 \* a% m9 _# I
因为结构体包含数据大小未知,完成由用户定义,如果保存数据时要考虑到这么多的变化,那能把人都搞晕,因此设计一个以不变应万变的数据保存机制就很好了,好比是复杂平台中的数据串行化保存。& _4 j# F6 X( r' i: u" Z
在单片机里面不可能实现这么高级的技术,但是也可以通过一个小小的技巧实现类似功能,方式就是通过联合体来保存,比如下面所示! k6 O8 H% B, p X
) \& l# x# U; ?, x struct e2prom_data4 i& `5 w+ |6 Y4 |0 z, U6 ?! {
{0 l1 O( c$ _2 i1 r
char TEM_compensate;
. P; D) u: C: y, T8 ~* \& } y unsigned int sterilization_temperature[10];//0.1
' j8 p9 w6 ?+ @1 k: n unsigned char sterilization_time_min[10];
1 U* U6 G1 @1 r P5 h2 L1 c, p unsigned char exhaust_times;. {; D0 G! d$ e' @6 K; M4 \, H+ b
unsigned char prebalance_time_min;) j. y$ i4 W7 K4 V, \/ @0 L6 d
};
2 l% l+ f& g$ @& Q
! U2 v6 b" a& K. y* i' O- punion sector
9 ]& f& M$ P( F) ^{
$ L# M1 ]% Y% B6 j2 t0 x* e0 z struct e2prom_data sterlization_data;
* N* X$ B# q: o9 v4 E ]6 [ unsigned char storage[ sizeof(struct e2prom_data) ];5 T2 @- [3 E$ |# x+ m
} e2prom;, X" Y+ ^' `. ?3 z( L
. M- b9 w# }$ d. c# W
% T; U% [9 c0 X; u0 R6 I) _0 s 联合sector代表实际的扇区,大小不能超过扇区大小,而上面的结构体就用来保存真正要用到的变量,然后通过联合体sector里面的unsigned char storage,统一转换成1个字节来保存实际数据,极其方便。% A: D" `. f) s. u
而要读取数据的时候可以通过下面的 void read_sector(char secn)函数来统一操作,把数据统一读取到内存中,确认保存后再通过void write_sector(char secn)统一保存。# V( G4 N, h% O, P5 |! s4 |
效率很高,用内存来缓存数据,可以减小EEPROM擦写次数,提高寿命。
" I, [: O% X6 o) p9 x I: l
( a9 P" b( U" R( w4 u( O" n& Y5 [9 ?) L: |; M1 b3 o" r
void read_sector(char secn)
6 J* ?& d! g! V+ Q' c: b: C{
8 I4 o+ R% F3 O% `( E$ c8 ^5 k/ s int i;! N3 Q7 v- E6 _
int E2prom_sector_start_addr=(secn-1)*512;. k' v' d: K" y& B4 K* p2 u$ F
for(i=0;i< sizeof(struct e2prom_data);i++); _, x* F* _" X9 @0 s
{& D3 T8 M; Z7 N* w
e2prom.storage=Byte_Read( i+ E2prom_sector_start_addr);; K7 I r7 F( }4 k! ?0 w
}3 S% N! [9 j ~! n
IAP_Disable();
1 D1 K$ O! y* J( G( J; z}7 y+ l9 u3 K/ i$ W/ E# }# ]
5 ?- x% c |- \/ q4 B3 y) U
X/ @, S& y( K& O* evoid write_sector(char secn)3 B9 f$ h. Y& ?* W6 u
{0 T& c. j$ d4 R" ~0 ~
/ t" D* T l# `1 {4 i8 D. C- i1 E
int i;
9 A; D" f4 Q, ~) `$ l: f! a: H z6 R- s int E2prom_sector_start_addr=(secn-1)*512;
% o; m6 _9 h% W( v
~1 P) h3 z; t5 T2 P! {" n8 d
, }; k/ e) m' c6 c3 ] Sector_Erase(E2prom_sector_start_addr);5 m; C& G# g4 y. V
for(i=0;i< sizeof( struct e2prom_data );i++)" ^ ^$ ]1 T/ G, J
{
' j7 U7 ^$ T9 t6 K: X8 w) b Byte_Program(i + E2prom_sector_start_addr, e2prom.storage);$ q9 h9 i5 }$ v: A# {! I" V
}2 b2 R* z: Q/ D$ T
IAP_Disable();+ f2 S( L5 X" m( T& u
}, L! W E) V$ u( ~" O/ Z
( U8 @8 m3 Y; v3 ~: l2 m6 p+ c0 V$ ` r4 E
唯一不足的地方是实际数据地址是固定的,如果常年累月读写次数多了的话,EEPROM还是有可能出问题的,下一步改进的地方就是通过实际一个虚拟存储空间来延长EEPROM寿命,
, Q! w% \& j- n" N实际方案是比如一个扇区是1K字节,那么把1k分成256个单元,每个单元4个字节,扇区首单元保存扇区状态,剩余255个单元作为实际存储单元,而每个存储单元又分成2+2布局,前两字节保存实际数据,后两字节保存虚拟地址,1.写入时写入数据紧跟后面写入虚地址VirtAddVarTab(0<=i<NumbOfVar)' I; P* R7 ^2 ~- n8 P5 L; c
2.每个Page第一个地址写入该页状态(Earse,Reveice,Vild)( _* D- i5 `0 J1 L8 S( ^& }; ~( M
3 p) c2 [6 X3 i6 g. \相同地址再次写入时不会把上次写的擦掉,而是在模拟EEPROM区尾部未写过的地方再次写入数据、虚地址,
$ v. f! o5 p2 b1 G0 d3、 读的时候是从尾部开始匹配地址,也就是读取最后一次写的内容。 $ [# t* @: v: I3 O3 [
4、模拟EEPROM区分为2页,如果一页满了把这一页内地址不重复的数据复制到另一页后擦除,2页交替使用。! r3 ?& w5 B: H
1 y: k, u3 s- P: Z一个代码:/ P# s% l7 K: V% p/ n, P$ |& K# O j
0 D$ N9 e/ ?1 U$ t
( m( i* Y* x/ R1 \! n
1 ~' t; f. J9 R% R% e% t# Z
% G) I: }3 K) i" R4 w/ u- F% g |
|