我通常使用的技术是在数据前面加上一个 4 字节的滚动序列号,其中最大的数字代表最新/当前值。在存储 2 个字节的实际数据的情况下,总共 6 个字节,然后我形成一个循环队列排列,因此对于 128 个字节的 EEPROM,它将包含 21 个条目并增加 21 倍的耐用性。
然后在启动时可以使用最大的序列号来确定下一个要使用的序列号和队列的当前尾部。以下 C 伪代码演示,这假设在初始编程时 EEPROM 区域已被擦除为 0xFF 的值,因此我忽略了 0xFFFF 的序列号:
struct
{
uint32_t sequence_no;
uint16_t my_data;
} QUEUE_ENTRY;
#define EEPROM_SIZE 128
#define QUEUE_ENTRIES (EEPROM_SIZE / sizeof(QUEUE_ENTRY))
uint32_t last_sequence_no;
uint8_t queue_tail;
uint16_t current_value;
// Called at startup
void load_queue()
{
int i;
last_sequence_no = 0;
queue_tail = 0;
current_value = 0;
for (i=0; i < QUEUE_ENTRIES; i++)
{
// Following assumes you've written a function where the parameters
// are address, pointer to data, bytes to read
read_EEPROM(i * sizeof(QUEUE_ENTRY), &QUEUE_ENTRY, sizeof(QUEUE_ENTRY));
if ((QUEUE_ENTRY.sequence_no > last_sequence_no) && (QUEUE_ENTRY.sequence_no != 0xFFFF))
{
queue_tail = i;
last_sequence_no = QUEUE_ENTRY.sequence_no;
current_value = QUEUE_ENTRY.my_data;
}
}
}
void write_value(uint16_t v)
{
queue_tail++;
if (queue_tail >= QUEUE_ENTRIES)
queue_tail = 0;
last_sequence_no++;
QUEUE_ENTRY.sequence_no = last_sequence_no;
QUEUE_ENTRY.my_data = v;
// Following assumes you've written a function where the parameters
// are address, pointer to data, bytes to write
write_EEPROM(queue_tail * sizeof(QUEUE_ENTRY), &QUEUE_ENTRY, sizeof(QUEUE_ENTRY));
current_value = v;
}
对于较小的 EEPROM,3 字节序列会更有效,尽管需要一些位切片而不是使用标准数据类型。