小型嵌入式设备的EEPROM参数结构

Dra*_*ika 6 embedded configuration microcontroller eeprom

我在小型嵌入式设备重新设计(PID控制器)中要解决的主要问题是设备参数存储。我在这里部分介绍的旧解决方案节省空间,但在添加新参数时维护起来很笨拙。它基于必须与 EEPROM 地址匹配的设备参数 ID,如下例所示:

// EEPROM variable addresses

#define EE_CRC                       0          // EEPROM CRC-16 value

#define EE_PROCESS_BIAS              1          // FLOAT, -100.00 - 100.00 U
#define EE_SETPOINT_VALUE            3          // FLOAT, -9999 - 9999.9
#define EE_SETPOINT_BIAS             5          // CHAR, -100 - 100 U
#define EE_PID_USED                  6          // BYTE, 1 - 3
#define EE_OUTPUT_ACTION             7          // LIST, DIRE/OBRNU
#define EE_OUTPUT_TYPE               8          // LIST, GRIJA/MOTOR

#define EE_PROCESS_BIAS2             9          // FLOAT, -100.00 - 100.00 U
#define EE_SETPOINT_VALUE2          11          // FLOAT, -9999 - 9999.9
#define EE_SETPOINT_BIAS2           13          // CHAR, -100 - 100 U
#define EE_PID_USED2                14          // BYTE, 1 - 3
#define EE_OUTPUT_ACTION2           15          // LIST, DIRE/OBRNU
#define EE_OUTPUT_TYPE2             16          // LIST, GRIJA/MOTOR

#define EE_LINOUT_CALIB_ZERO        17          // FLOAT, -100.0 - 100.0
#define EE_LINOUT_CALIB_GAIN        19          // FLOAT, -2.0 - 2.0
Run Code Online (Sandbox Code Playgroud)

每个地址都是硬编码的,下一个地址是根据先前的数据大小定义的(注意地址之间的间距不均匀)。它非常高效,因为不会浪费 EEPROM 数据存储,但很难在不引入错误的情况下进行扩展。

在代码的其他部分(即 HMI 菜单、数据存储...),代码将使用与刚刚给定的地址匹配的参数列表,如下所示:

// Parameter identification, NEVER USE 0 (zero) as ID since it's NULL
// Sequence is not important, but MUST be same as in setparam structure

#define ID_ENTER_PASSWORD_OPER             1 
#define ID_ENTER_PASSWORD_PROGRAM          2 
#define ID_ENTER_PASSWORD_CONFIG           3 
#define ID_ENTER_PASSWORD_CALIB            4 
#define ID_ENTER_PASSWORD_TEST             5 
#define ID_ENTER_PASSWORD_TREGU            6 

#define ID_PROCESS_BIAS                    7
#define ID_SETPOINT_VALUE                  8
#define ID_SETPOINT_BIAS                   9
#define ID_PID_USED                       10 
#define ID_OUTPUT_ACTION                  11
#define ID_OUTPUT_TYPE                    12

#define ID_PROCESS_BIAS2                  13

...                        
Run Code Online (Sandbox Code Playgroud)

然后在使用这些参数的代码中,例如在下面给出的用户菜单结构中,我使用自己的 PARAM 类型(结构)构建了项目:

struct param {                      // Parametar decription
   WORD   ParamID;                    // Unique parameter ID, never use zero value
   BYTE   ParamType;                  // Parametar type
   char   Lower[EDITSIZE];            // Lowest value string
   char   Upper[EDITSIZE];            // Highest value string
   char   Default[EDITSIZE];          // Default value string
   BYTE   ParamAddr;                  // Parametar address (in it's media)
};                                  

typedef struct param PARAM;
Run Code Online (Sandbox Code Playgroud)

现在参数列表被构建为结构数组:

PARAM code setparam[] = {
  {NULL, NULL, NULL, NULL, NULL, NULL},                   // ID 0 doesn't exist

  {ID_ENTER_PASSWORD_OPER, T_PASS, "0", "9999", "0", NULL},
  {ID_ENTER_PASSWORD_PROGRAM, T_PASS, "0", "9999", "0", NULL},
  {ID_ENTER_PASSWORD_CONFIG, T_PASS, "0", "9999", "0", NULL},
  {ID_ENTER_PASSWORD_CALIB, T_PASS, "0", "9999", "0", NULL},
  {ID_ENTER_PASSWORD_TEST, T_PASS, "0", "9999", "0", NULL},
  {ID_ENTER_PASSWORD_TREGU, T_PASS, "0", "9999", "0", NULL},  

  {ID_PROCESS_BIAS, T_FLOAT, "-100.0", "100.0", "0", EE_PROCESS_BIAS},
  {ID_SETPOINT_VALUE, T_FLOAT, "-999", "9999", "0.0", EE_SETPOINT_VALUE},
  {ID_SETPOINT_BIAS, T_CHAR, "-100", "100", "0", EE_SETPOINT_BIAS},
  {ID_PID_USED, T_BYTE, "1", "3", "1", EE_PID_USED},
  {ID_OUTPUT_ACTION, T_LIST, "0", "1", "dIrE", EE_OUTPUT_ACTION},
  {ID_OUTPUT_TYPE, T_LIST, "0", "1", "GrIJA", EE_OUTPUT_TYPE},

  {ID_PROCESS_BIAS2, T_FLOAT, "-100.0", "100.0", "0", EE_PROCESS_BIAS2},
Run Code Online (Sandbox Code Playgroud)

...

本质上,每个参数都有其唯一的 ID,并且该 ID 必须与硬编码的 EEPROM 地址相匹配。由于参数的大小不固定,因此我无法将参数 ID 本身用作 EEPROM(或其他介质)地址。上例中的 EEPROM 组织是 16 位字,但原则上并不重要(字符浪费了更多空间,所以无论如何我将来更喜欢 8 位组织)

问题:

有没有更优雅的方法来做到这一点?一些哈希表、众所周知的模式、类似问题的标准解决方案?现在 EEPROM 的大小要大得多,我不介意使用固定的参数大小(浪费 32 位布尔参数)来换取更优雅的解决方案。看起来对于固定大小的参数,我可以使用参数 ID 作为地址。这种方法是否有我没有看到的明显缺点?

我现在使用分布式硬件(HMI、I/O和主控制器是分开的),我想使用所有设备都知道这个参数结构的结构,以便例如远程I/O知道如何扩展输入值,HMI 知道如何显示和格式化数据,所有这些都仅基于参数 ID。换句话说,我需要一个地方来定义所有参数。

我做了谷歌研究,除了一些数据库之外,几乎找不到小型设备的信息。我什至在考虑一些 XML 定义,它可以为我的数据结构生成一些 C 代码,但也许有一些更适合小型设备(高达 512 K 闪存、32 K RAM)的优雅解决方案?

kkr*_*mbo 1

I\xe2\x80\x99m 不确定这是否真的比你拥有的更好,但这是一个想法。为了更容易维护,请考虑将 EEPROM 地址的知识封装到 \xe2\x80\x9ceeprom\xe2\x80\x9d 对象中。现在您有一个参数对象,并且每个实例都知道其数据存储在物理 EEPROM 中的位置。如果参数对象不了解 EEPROM,也许维护会更容易。相反,一个单独的 eeprom 对象负责物理 EEPROM 和参数对象实例之间的接口。

\n\n

另外,请考虑将 EEPROM 数据的版本号添加到 EEPROM 中保存的数据中。如果设备固件更新并且 EEPROM 数据的格式发生变化,则此版本号允许新固件识别并转换旧版本的 EEPROM 数据。

\n