|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
关于单片机EEPROM数据保存的若干经验总结 附带stc单片机程序0 ?9 }/ z. W6 w- |
2 t; f D+ {9 L5 K/ M1 h
@+ o' y: y4 o- H
因为要保存的数据可能是千变万化的,字长可能从8位到32位,其中包括char(8)、short int(16)、 int(32)、float(32),而不同数据类型在不同体系架构上字长各不相同,复杂点的甚至包括结构体Struct,5 d2 S) [3 s Q7 `( r
因为结构体包含数据大小未知,完成由用户定义,如果保存数据时要考虑到这么多的变化,那能把人都搞晕,因此设计一个以不变应万变的数据保存机制就很好了,好比是复杂平台中的数据串行化保存。
) t$ M1 W4 m; ^' c6 C, ~在单片机里面不可能实现这么高级的技术,但是也可以通过一个小小的技巧实现类似功能,方式就是通过联合体来保存,比如下面所示
4 ?' e, E* V" t/ `5 t5 J
2 C' t7 t5 L/ Z# t struct e2prom_data
' N' ~: ]0 o; t) B2 D/ \ {, D& c/ L6 T4 l; \2 v& D) L! V& w
char TEM_compensate;
( ]4 X7 A0 X; z5 ~, q unsigned int sterilization_temperature[10];//0.1/ Q( I" R9 g& `4 ?& Y' T9 _0 u
unsigned char sterilization_time_min[10];2 s9 }+ M* _* O4 B
unsigned char exhaust_times;4 k/ O1 \' B1 c* ]- G# s
unsigned char prebalance_time_min;# x8 }( m, v, f+ g% M! r
};0 h$ m& @9 h# e, I: P- U4 u1 _
5 j3 H# J' K/ p# |6 Ounion sector/ |" h/ T2 S3 c! p
{
3 I3 E% C# @. C; K/ q# N0 F struct e2prom_data sterlization_data;
4 t) H! w+ D( q( i$ [$ q unsigned char storage[ sizeof(struct e2prom_data) ];. q) k# }9 T. W# w5 [" P
} e2prom;
( t$ c0 k3 o9 D4 }* `- a0 Z0 H5 N# N1 _
$ l+ a- ?; A: `( [2 y' B
联合sector代表实际的扇区,大小不能超过扇区大小,而上面的结构体就用来保存真正要用到的变量,然后通过联合体sector里面的unsigned char storage,统一转换成1个字节来保存实际数据,极其方便。6 C ^0 }$ ~; M+ E, k! s2 j6 |
而要读取数据的时候可以通过下面的 void read_sector(char secn)函数来统一操作,把数据统一读取到内存中,确认保存后再通过void write_sector(char secn)统一保存。 J, ?; d! ^% X' \( M
效率很高,用内存来缓存数据,可以减小EEPROM擦写次数,提高寿命。2 T, v k6 p+ `8 {: e4 e
! T# M" I5 _' t* d( s. B4 v8 z
0 C- q6 M' u( I' {% u2 f& J( g) ~
void read_sector(char secn)
; c9 b3 B- l; q7 {0 I l{
, E/ O, r. ?3 b E! C int i;
, L! R' B% h i; g int E2prom_sector_start_addr=(secn-1)*512;6 |1 l! E4 O: C
for(i=0;i< sizeof(struct e2prom_data);i++)- n u3 i7 y8 M$ K7 U5 Q6 k
{: k/ b+ } X- L2 [
e2prom.storage=Byte_Read( i+ E2prom_sector_start_addr);
% z. H' u/ f8 m$ h }
( ]5 N* b& m7 B" F: o- X IAP_Disable();
]- Y2 `1 V8 r x}
, o7 P9 ?2 p; k
: {8 a7 A' A8 e, k$ Q" ?7 {! W
void write_sector(char secn)1 j; F8 G* b) v$ t# e3 r
{$ x. M- C& W4 I6 S; B' n- i
3 F/ Z b) j1 T0 ?% O0 F
int i; _' t7 j, S1 L& Y# }
int E2prom_sector_start_addr=(secn-1)*512;, }' I2 D6 `/ q* J( u$ |
% z O; o! S! ]% Z
( q+ B9 M: j# \2 v5 F
Sector_Erase(E2prom_sector_start_addr);2 W0 u3 j* ~, s6 M& D
for(i=0;i< sizeof( struct e2prom_data );i++)
/ ~6 x! p$ }5 j! V- ? {
" V+ [' H: b8 o0 \9 W" \ Byte_Program(i + E2prom_sector_start_addr, e2prom.storage);0 Y) q+ I6 m( H
}* A9 b3 |' H1 p
IAP_Disable();: A ?% Q! l( a! _% s& d' a& Y2 f
}
2 h+ R, z6 n8 M7 r! @& J8 E0 k3 \4 G3 m" ?
+ B/ N" {% s2 |8 ^3 H
唯一不足的地方是实际数据地址是固定的,如果常年累月读写次数多了的话,EEPROM还是有可能出问题的,下一步改进的地方就是通过实际一个虚拟存储空间来延长EEPROM寿命,
5 A- h) A9 |: \# R( P实际方案是比如一个扇区是1K字节,那么把1k分成256个单元,每个单元4个字节,扇区首单元保存扇区状态,剩余255个单元作为实际存储单元,而每个存储单元又分成2+2布局,前两字节保存实际数据,后两字节保存虚拟地址,1.写入时写入数据紧跟后面写入虚地址VirtAddVarTab(0<=i<NumbOfVar)2 Q: C; v; d2 g5 j; V
2.每个Page第一个地址写入该页状态(Earse,Reveice,Vild)
3 t3 e1 z } `( x) Q$ v" x- ^) B7 U
+ f; U7 y6 H' b7 k相同地址再次写入时不会把上次写的擦掉,而是在模拟EEPROM区尾部未写过的地方再次写入数据、虚地址,
0 g6 E7 \( l9 J9 Q3、 读的时候是从尾部开始匹配地址,也就是读取最后一次写的内容。
" f* w+ @: d6 C, X. m4、模拟EEPROM区分为2页,如果一页满了把这一页内地址不重复的数据复制到另一页后擦除,2页交替使用。8 x% t" D2 [4 [) I9 P2 w- [ m' l+ U
% {, d: C5 l& I5 t一个代码:8 p+ X% b, r# [9 s7 {! H" j8 x
& i, ?$ l; y7 F! C* j! [
2 q+ f6 A0 V& S. l! F: y+ W. T7 Q* r
, {% O) t T9 t1 u+ | |
|