|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
关于单片机EEPROM数据保存的若干经验总结 附带stc单片机程序: ?2 F" M$ d& _/ H5 P) Y1 S7 `
3 V0 C3 j. S2 [9 j! l! h# Q( k
6 H9 A. c! M2 F7 ^* X因为要保存的数据可能是千变万化的,字长可能从8位到32位,其中包括char(8)、short int(16)、 int(32)、float(32),而不同数据类型在不同体系架构上字长各不相同,复杂点的甚至包括结构体Struct,; J( w7 A. H9 E) e6 ~5 U
因为结构体包含数据大小未知,完成由用户定义,如果保存数据时要考虑到这么多的变化,那能把人都搞晕,因此设计一个以不变应万变的数据保存机制就很好了,好比是复杂平台中的数据串行化保存。* m. @6 Y( U% }/ t
在单片机里面不可能实现这么高级的技术,但是也可以通过一个小小的技巧实现类似功能,方式就是通过联合体来保存,比如下面所示5 y8 L* X; a2 ]2 E: H; r
% y. K m. N6 s7 w& Y" d struct e2prom_data& x1 ?4 l- s' j- `! u, b
{
' U- H1 E( M2 v- E3 g char TEM_compensate;! a3 _* M& \" f
unsigned int sterilization_temperature[10];//0.1% n: p1 w- G# a' t
unsigned char sterilization_time_min[10];% L& P+ A" w/ f! t# O- N
unsigned char exhaust_times;; t& s1 y8 V& S. q$ ? v! c
unsigned char prebalance_time_min;
7 y+ ~& N% U$ u" c* M/ }- T };; W7 e: q& u- z8 Z8 d
# t# a& \9 V0 F9 |6 Ounion sector
1 _ M* X/ d. Z0 e. m6 ~3 u1 P! d; _) T{- s+ a$ f: x1 f9 d
struct e2prom_data sterlization_data;; D) Y' j, e2 {+ `9 g {: e5 A
unsigned char storage[ sizeof(struct e2prom_data) ];
/ |- ?+ B3 x" k} e2prom;. E; ]) A4 R8 q) D. X |6 r
: H# Z/ s0 g9 S: a
, U2 p2 |6 g; N( i 联合sector代表实际的扇区,大小不能超过扇区大小,而上面的结构体就用来保存真正要用到的变量,然后通过联合体sector里面的unsigned char storage,统一转换成1个字节来保存实际数据,极其方便。
; _' U4 c v! G, u9 c+ ?8 _! |而要读取数据的时候可以通过下面的 void read_sector(char secn)函数来统一操作,把数据统一读取到内存中,确认保存后再通过void write_sector(char secn)统一保存。
: z% W: d9 A, ?$ b* e7 A' o% u! @. [效率很高,用内存来缓存数据,可以减小EEPROM擦写次数,提高寿命。5 H0 k. A( @, v: b
' l' y& ^# M3 ~, P0 G+ ?- v' Y _$ a# Z
void read_sector(char secn)0 O6 ]# |( U$ M! \( I
{
% E6 g+ t: L. @5 \7 a int i;* f0 \+ {% q4 s8 d4 f. K- d: ^0 p2 Y( q
int E2prom_sector_start_addr=(secn-1)*512;
# @% {& F, A* U1 [. r5 c/ _ for(i=0;i< sizeof(struct e2prom_data);i++)
7 h) o$ C g( e' b3 o! A0 H0 q {
# }3 ~* ^/ e5 A# d6 K$ ?; k9 ~- b e2prom.storage=Byte_Read( i+ E2prom_sector_start_addr);( {( T A5 i) f- p. p
} T6 C% w% U" j: O0 t
IAP_Disable();+ J# J8 i/ l/ Y) j5 R# z0 w" l
}
! p+ w7 H' [# e% J
; @% o6 U+ J# b$ z ~) Y
' l5 H# M$ K. L/ Tvoid write_sector(char secn)
/ X: `' A- W' s' e9 H: F{. S1 o% Q* T, Z9 @% k+ `
$ b# x f9 Y' d7 Z5 A
int i;
) n% B/ _# J% w. L* B+ j int E2prom_sector_start_addr=(secn-1)*512;: f+ q v& a( J
1 U( s- s- e& e8 \
: E4 \; b3 F% h2 w$ e" M3 O* m0 w
Sector_Erase(E2prom_sector_start_addr);6 V! Z' x, q8 Y' m
for(i=0;i< sizeof( struct e2prom_data );i++)9 }6 p2 } |' m& D) \- V) J
{
! O/ C. b$ a% X ^ Byte_Program(i + E2prom_sector_start_addr, e2prom.storage);
/ L# X- V& y! p" [6 g4 i }4 V3 v- q4 W" e; [8 i& k
IAP_Disable();5 ]( d. o( G$ H) ]& F
}1 y' D9 g s. q- Q+ J2 [" }5 V
% k$ G. L- b+ @6 B5 W3 }
( z2 U' q1 @: w5 ?" `9 T/ T唯一不足的地方是实际数据地址是固定的,如果常年累月读写次数多了的话,EEPROM还是有可能出问题的,下一步改进的地方就是通过实际一个虚拟存储空间来延长EEPROM寿命,
1 C1 C. q! S, w7 N' n& s* M$ Y实际方案是比如一个扇区是1K字节,那么把1k分成256个单元,每个单元4个字节,扇区首单元保存扇区状态,剩余255个单元作为实际存储单元,而每个存储单元又分成2+2布局,前两字节保存实际数据,后两字节保存虚拟地址,1.写入时写入数据紧跟后面写入虚地址VirtAddVarTab(0<=i<NumbOfVar)9 S, s5 }3 `% c6 _7 M& B' L5 L$ U
2.每个Page第一个地址写入该页状态(Earse,Reveice,Vild)$ A8 L4 d6 z2 g; n' M; D
) C2 A) L7 X+ y( f! R相同地址再次写入时不会把上次写的擦掉,而是在模拟EEPROM区尾部未写过的地方再次写入数据、虚地址, & ]# ?: M. o# [* E" r% [
3、 读的时候是从尾部开始匹配地址,也就是读取最后一次写的内容。
3 n* ? S P4 N* Y1 a! c4、模拟EEPROM区分为2页,如果一页满了把这一页内地址不重复的数据复制到另一页后擦除,2页交替使用。0 D) h7 b6 K' m$ }
0 d! s. K) F: m- [% v1 b e) Y
一个代码:
( ?( ~+ W* L: x/ t/ M2 d+ A; {$ W( J; @0 \
& F+ y V, u! g+ X6 ^
' N- v3 ^( m! G
9 ~6 I! M6 w, c3 B% q3 o |
|