如何保存值从指针数组到结构体在EEPROM

How to save values from array of pointers to structs in EEPROM

本文关键字:数组 指针 结构体 EEPROM 何保存 保存      更新时间:2023-10-16

我试图使用标准Arduino EEPROM- library Routine EEPROM.put()将4个结构体的所有值保存到我的ATMega328P EEPROM,并通过EEPROM.get()检索它们。我怎么能传递所有的值从我的value_table到这些函数?以下是我的数据。

typedef struct EXAMPLE {
  uint8_t part1[7][2];
  uint8_t part2[3];
} *ptr[5];

EXAMPLE VALUE_1 = {{
  {1, 8},  
  {2, 9}, 
  {3, 10}, 
  {4, 11}, 
  {5, 12}, 
  {6, 13},  
  {7, 14} 
},
  {15, 16, 17} 
};

在指针数组中有VALUE_1到VALUE_4四个版本。

struct EXAMPLE *value_table[] = {&VALUE_1, &VALUE_2, &VALUE_3, &VALUE_4};

这是我所提出的,但产生错误的结果。

EEPROM.put(0, &value_table); // 0 is first byte of EEPROM
EEPROM.get(0, value_table);

我想存储的是位于VALUE_1 - VALUE_4中的值,以使它们持久。

我非常感谢每一个提示!

只是猜测:

// writing (starting at some "eeprom_address" address)
int eeprom_address = 0;
EEPROM.put(eeprom_address + 0*sizeof(EXAMPLE), VALUE_1);
EEPROM.put(eeprom_address + 1*sizeof(EXAMPLE), VALUE_2);
EEPROM.put(eeprom_address + 2*sizeof(EXAMPLE), VALUE_3);
EEPROM.put(eeprom_address + 3*sizeof(EXAMPLE), VALUE_4);
// reading
EEPROM.get(eeprom_address + 0*sizeof(EXAMPLE), VALUE_1);
EEPROM.get(eeprom_address + 1*sizeof(EXAMPLE), VALUE_2);
EEPROM.get(eeprom_address + 2*sizeof(EXAMPLE), VALUE_3);
EEPROM.get(eeprom_address + 3*sizeof(EXAMPLE), VALUE_4);
// plus set the value_table in the same way as before
struct EXAMPLE *value_table[] = {&VALUE_1, &VALUE_2, &VALUE_3, &VALUE_4};

没有必要将指针存储到EEPROM中,你应该只存储数据值(但是以结构化的方式,这样你就知道哪个字节属于哪个数据项,并且可以将它们正确地读入目标变量)。

如果您想使用单个结构体,请执行struct EXAMPLE value_table[] = {VALUE_1, VALUE_2, VALUE_3, VALUE_4};。但是这将把VALUE_1复制到value_table中,所以它将消耗两倍于只存在一个VALUE_1的内存。

顺便说一句,文档只是说"EEPROM。获取(地址,数据)"没有类型…这还是C/c++吗?:/*皱眉*

文档链接:get, put,还有struct的例子

BTW: int的地址只用作官方文档的副本,我个人永远不会使用int的地址,当然,突然我的计划在某个遥远的未来点检查Arduino变得更加遥远。


使用for变体书写:

constexpr size_t VALUES_N = 4;
struct EXAMPLE *value_table[] = {&VALUE_1, &VALUE_2, &VALUE_3, &VALUE_4};
// writing (starting at some "eeprom_address" address)
int eeprom_address = 0;
for (size_t i = 0; i < VALUES_N; ++i) {
    EEPROM.put(eeprom_address + i*sizeof(EXAMPLE), *(value_table[i]));
}
// reading
for (size_t i = 0; i < VALUES_N; ++i) {
    EEPROM.get(eeprom_address + i*sizeof(EXAMPLE), *(value_table[i]));
}

下载Arduino并查看getput。正如预期的那样,它们被模板化了

template< typename T > T &get( int idx, T &t )
template< typename T > const T &put( int idx, const T &t )

因为它们有对模板定义类型的参数的引用,所以它们知道在EEPROM上执行读写操作所需的大小和几乎所有其他内容。

希望put在写失败时抛出异常,因为我没有看到任何throw或其他错误通知方法,但这不是这里的问题。

所以…

struct EXAMPLE *value_table[] = {&VALUE_1, &VALUE_2, &VALUE_3, &VALUE_4};

是一个包含4个指向结构体的指针的数组,而不是结构体本身。这意味着

sizeof(value_table); 

将是指针大小的四倍,在Arduino上可能是16字节。但

EEPROM.put(0, &value_table);

甚至不会写这个。因为它传递了一个指向value_table的指针,所有写入的都是一个指针,根据数组的工作方式,它将是指向第一个条目的指针,即指向要存储的数据的指针。

getput通过引用获取数据,因此不需要显式地获取指针。不幸的是,因为模板将接受任何东西,所以编译器没有警告或错误来捕捉这个错误。

对于put,您有两个选择:

EEPROM.put(0, VALUE_1 );
EEPROM.put(sizeof(VALUE_1), VALUE_2);
EEPROM.put(sizeof(VALUE_1)*2, VALUE_3);
...
EEPROM.put(sizeof(VALUE_1)*(N-1), VALUE_N);

或执行相同操作的循环,或将指向EXAMPLE结构体的指针表替换为EXAMPLE结构体的表。

struct EXAMPLE value_table[] = 
{
    {
        {
            {1, 8},  
            {2, 9}, 
            {3, 10}, 
            {4, 11}, 
            {5, 12}, 
            {6, 13},  
            {7, 14} 
        },
        {15, 16, 17} 
    },
    {
        // contents of VALUE_2
    },
    {
        // contents of VALUE_3
    },
    ...
    {
        // contents of VALUE_N
    }
}

VALUE_1等…被丢弃。

可以使用value_table[x],其中x的值为-1,或者定义

enum VALUES
{
    VALUE_1 = 0,
    VALUE_2,
    VALUE_3,
    ...
    VALUE_N
}

,并作为value_table[VALUE_1]访问表。这种方法有点冗长,但更容易阅读。

put的调用与当前使用的类似,只是丢失了操作符的地址。

EEPROM.put(0, value_table);

使用get将非常相似

EEPROM.get(0, VALUE_1 );
EEPROM.get(sizeof(VALUE_1), VALUE_2);
EEPROM.get(sizeof(VALUE_1)*2, VALUE_3);
...
EEPROM.get(sizeof(VALUE_1)*(N-1), VALUE_N);

EEPROM.get(0, value_table);

取决于选择处理put的方法