|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
关于单片机EEPROM数据保存的若干经验总结 附带stc单片机程序1 _/ ]& l- z7 V+ ~
& B. q, U, L* ? P
' [# k0 q& L8 ]' {7 _4 i. a因为要保存的数据可能是千变万化的,字长可能从8位到32位,其中包括char(8)、short int(16)、 int(32)、float(32),而不同数据类型在不同体系架构上字长各不相同,复杂点的甚至包括结构体Struct,
! y9 C3 B7 t/ m4 U3 ?因为结构体包含数据大小未知,完成由用户定义,如果保存数据时要考虑到这么多的变化,那能把人都搞晕,因此设计一个以不变应万变的数据保存机制就很好了,好比是复杂平台中的数据串行化保存。! v$ ^2 j/ T! K S) H% u
在单片机里面不可能实现这么高级的技术,但是也可以通过一个小小的技巧实现类似功能,方式就是通过联合体来保存,比如下面所示, l* P1 p8 U7 p3 X; o! p- r
4 D6 G* f+ o1 b- f6 _9 x* \" f$ C
struct e2prom_data
- W, E* t8 X6 {5 X; f2 S {
) {( r% h8 ]0 d; O$ J char TEM_compensate;" G' S6 B; Y8 ~3 J
unsigned int sterilization_temperature[10];//0.1
+ d' ~9 m6 L; F5 b- f% d5 n5 R; t3 T9 L unsigned char sterilization_time_min[10]; m6 a( E. b4 |" {5 A% U
unsigned char exhaust_times;
9 E# }' b" @! N. V unsigned char prebalance_time_min;1 @ A6 _) O; }& R
};+ d3 o1 }" z# B: C/ L
+ m9 u2 I' f% U$ z0 v! {$ a* Nunion sector$ Y, M- t# I0 S. _! S S# T
{* Q4 y$ B1 r( n0 R$ J. {; \" g2 Z8 X
struct e2prom_data sterlization_data;
9 O" s8 @( ^& R; {/ s unsigned char storage[ sizeof(struct e2prom_data) ];
; n- I$ Y; w1 b# X4 J} e2prom;8 ^' p& b2 `7 m, B. a' N
9 m/ p6 A' r7 f6 J4 s; K) {7 n
9 ~ Q. e+ z( F, @# v 联合sector代表实际的扇区,大小不能超过扇区大小,而上面的结构体就用来保存真正要用到的变量,然后通过联合体sector里面的unsigned char storage,统一转换成1个字节来保存实际数据,极其方便。/ W/ t! O- w" [4 s
而要读取数据的时候可以通过下面的 void read_sector(char secn)函数来统一操作,把数据统一读取到内存中,确认保存后再通过void write_sector(char secn)统一保存。) { A! w& ^6 F( r
效率很高,用内存来缓存数据,可以减小EEPROM擦写次数,提高寿命。& f3 c. ^! V' V6 R9 q1 _9 S
3 e# V6 O! m& v! y* Y; u5 C" \( y$ w8 f/ {0 s T
void read_sector(char secn)- z ^4 h# V; F% q9 w8 _
{
! I& R# P5 X! i" |7 Q' v/ D! w1 f int i;
3 z# O0 w+ P# A+ H- ]7 F$ [( [- L int E2prom_sector_start_addr=(secn-1)*512;* H: J' q1 [- g5 m
for(i=0;i< sizeof(struct e2prom_data);i++)( L; ?/ Q7 @ ~- r/ j
{1 s1 T# ~6 I7 c$ D6 X
e2prom.storage=Byte_Read( i+ E2prom_sector_start_addr);
9 S: C6 U4 U. N0 i }) A- ~& s$ R# }+ q; z" I
IAP_Disable();' x+ e- r% [1 M- f% A- r1 E
}& s( z. r4 y4 @9 {, \
3 a: G% Z# x- A( \! k
5 Z! @" W/ t* D8 gvoid write_sector(char secn)
3 `' p/ ^+ b ]/ \3 p# T/ \9 i0 }{
; x S7 J' J6 Q7 w1 ]8 g
! p8 \; S5 a, d' z" y int i;
6 `$ ^# ^! C8 |* ~! [" a t int E2prom_sector_start_addr=(secn-1)*512;3 `. J7 L+ @3 w+ N) U- u, }3 h$ p
6 f( O& M; R [4 B' J6 G2 }
4 F% C4 Z# i3 k3 n/ _; t+ N Sector_Erase(E2prom_sector_start_addr);' K4 t) k, ~0 ~2 ~* z! W# T% i* t" @
for(i=0;i< sizeof( struct e2prom_data );i++)
. h7 p M6 y& _1 |8 N2 U {
" E. H) Y6 O; p& R6 n+ F Byte_Program(i + E2prom_sector_start_addr, e2prom.storage);
+ D2 i O6 J5 Q, N2 D- B }
; O& G0 D2 V4 A, m1 @ IAP_Disable();8 `* X; L' b0 v& N" i
}4 B7 {4 _3 G4 U# ]9 J, n
Q. u6 m- K) m1 q/ w
% w* j& z K, X1 J+ Y! r4 k唯一不足的地方是实际数据地址是固定的,如果常年累月读写次数多了的话,EEPROM还是有可能出问题的,下一步改进的地方就是通过实际一个虚拟存储空间来延长EEPROM寿命,
t: B$ R1 {$ b0 r$ Y实际方案是比如一个扇区是1K字节,那么把1k分成256个单元,每个单元4个字节,扇区首单元保存扇区状态,剩余255个单元作为实际存储单元,而每个存储单元又分成2+2布局,前两字节保存实际数据,后两字节保存虚拟地址,1.写入时写入数据紧跟后面写入虚地址VirtAddVarTab(0<=i<NumbOfVar)9 a% ]# Y. e) z2 ^) o. E, k6 `
2.每个Page第一个地址写入该页状态(Earse,Reveice,Vild)
! D+ c* [4 k {0 y8 ]4 V& r, S1 g( y6 g5 a9 h
相同地址再次写入时不会把上次写的擦掉,而是在模拟EEPROM区尾部未写过的地方再次写入数据、虚地址,
! L0 Y* ]* e* [$ V3、 读的时候是从尾部开始匹配地址,也就是读取最后一次写的内容。
2 J! g2 y6 c( x4、模拟EEPROM区分为2页,如果一页满了把这一页内地址不重复的数据复制到另一页后擦除,2页交替使用。$ F. i( w) ^6 E+ |! K" p* p
1 a0 O; [, K( x一个代码:
, L# b: p0 k w4 J+ ]2 a) z% A1 d* N" t" W/ f1 G" a+ Y' {
! V9 t4 G- `3 L7 U" K
/ `& @5 K6 s1 Y7 i
4 \0 n/ d8 w( e8 j9 A) w9 q |
|