小さな組み込みデバイスの再設計(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データストレージが無駄にならなかったので効率的でしたが、バグを導入せずに拡張することは困難でした。
コードの他の部分(つまり、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
...
次に、これらのパラメーターを使用するコードで、たとえば、以下に示すユーザーメニュー構造で、独自の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ビット構成を使用することをお勧めします)
質問:
これを行うためのよりエレガントな方法はありますか?いくつかのハッシュテーブル、よく知られているパターン、同様の問題の標準的な解決策?EEPROMのサイズは現在はるかに大きくなっています。より洗練されたソリューションと引き換えに、固定パラメーターサイズ(ブールパラメーターに32ビットを浪費)を使用してもかまいません。固定サイズのパラメータのように見えますが、パラメータIDをアドレスとして使用できます。この方法には、私には見えない明らかな欠点がありますか?
現在、分散型HW(HMI、I / O、メインコントローラーが分離されている)を使用していますが、すべてのデバイスがこのパラメーター構造を認識している構造を使用して、たとえばリモートI/Oがスケーリング方法を認識できるようにします。入力値、およびHMIは、すべてパラメーターIDのみに基づいてデータを表示およびフォーマットする方法を知っています。つまり、すべてのパラメーターが定義される単一の場所が必要です。
私はGoogleの調査を行いましたが、一部のデータベースを含まない小型デバイスではほとんど見つかりませんでした。データ構造のCコードを生成するXML定義についても考えていましたが、小さなデバイス(最大512 Kフラッシュ、32 K RAM)に適した洗練されたソリューションがあったのではないでしょうか。