在小型嵌入式设备重新设计(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每个地址都是硬编码的,下一个地址是根据以前的数据大小定义的(注意地址之间的间隔不均匀)。它是有效的,因为没有EEPROM数据存储被浪费,但是很难在不引入but的情况下扩展。
在代码的其他部分(即人机界面菜单、数据存储.)代码将使用与刚才给定的地址相匹配的参数列表,如下所示:
// 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
... 然后,在使用这些参数的代码中,例如在下面给出的用户菜单结构中,我使用自己的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;现在,参数列表构建为结构数组:
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},..。
本质上,每个参数都有其唯一的ID,并且这个ID必须匹配硬编码的EEPROM地址。由于参数大小不固定,所以不能将参数ID本身用作EEPROM (或其他媒体)地址。在上面的例子中,EEPROM的组织是16位字,但原则上并不重要(更多的空间浪费在字符上,所以我还是倾向于未来的8位组织)。
问题:
有什么更优雅的方法吗?一些哈希表,众所周知的模式,类似问题的标准解决方案?EEPROMS现在的大小要大得多,我不介意使用固定的参数大小(布尔参数浪费32位)来换取更优雅的解决方案。它看起来像固定大小的参数,我可以使用参数ID作为地址。这种方法有一个我看不到的明显的缺点吗?
我现在使用的是分布式HW (HMI、I/O和主控制器分离),我想使用所有设备都知道这个参数结构的结构,以便例如远程I/O知道如何缩放输入值,而HMI知道如何显示和格式化数据,这些都是基于参数ID的。换句话说,我需要定义所有参数的单一位置。
我做了我的谷歌研究,很少能找到一些小型设备,没有一些数据库。我甚至在考虑一些XML定义,这会为我的数据结构生成一些C代码,但也许有一些更适合于小型设备的优雅解决方案(最高可达512 K Flash,32 K RAM)?
发布于 2013-03-13 15:28:19
我不确定这是否真的比你拥有的更好,但这里有一个想法。为了便于维护,请考虑将EEPROM地址的知识封装到“eeprom”对象中。现在,您有一个参数对象,每个实例都知道其数据存储在物理EEPROM中的位置。如果参数对象不了解EEPROM,则可能更容易维护。相反,一个单独的eeprom对象负责物理EEPROM和参数对象实例之间的接口。
此外,考虑将EEPROM数据的版本号添加到保存在EEPROM中的数据中。如果设备固件被更新,EEPROM数据的格式发生变化,那么这个版本号允许新固件识别和转换EEPROM数据的旧版本。
发布于 2013-03-12 16:16:06
如果您不担心跨更改或处理器的兼容性,您可以简单地在RAM和EEPROM之间复制结构,并且只访问RAM副本的单个成员。
如果您想直接访问EEPROM中的单个成员,您也可以相对容易地创建一个工具,该工具可以从编译器的结构和已知打包规则编译一个定义列表。
发布于 2013-04-01 16:09:22
这就是我会做的事。
我将创建一个带有EEPROM中您希望拥有的变量的结构的ty清晰度。
使用您的示例,它应该如下所示:
typedef struct eeprom_st
{
float process_biass;
float setpoint_value;
char setpoint_bias;
....
} eeprom_st_t;而不是创建一个偏移量定义来标记结构将存储在EEPROM中的位置。
我将添加一个指向该类型的指针,将其用作一个虚拟对象:
#define EEPROM_OFFSET 0
eeprom_st_t *dummy;而不是使用偏移量来获得我需要的特定变量的偏移量,如下所示:
eeprom_write( my_setpoint_bias, EEPROM_OFFSET + offsetof(eeprom_st_t,setpoint_bias),
sizeoff(dummy->setpoint_bias));为了使它更优雅,我也会将eeprom写入例程转换成宏。
https://stackoverflow.com/questions/15365581
复制相似问题