パラメーターの管理 (Excelテンプレート付き) | 組み込み

組み込みソフトでは多くのパラメーター(設定)を管理することがあります。
本ページではこの様なパラメーターに関する仕様のまとめ方と、サンプルコードを紹介します。

目次

パラメーター仕様のまとめ方例

パラメーター仕様のまとめ方例を紹介します。下記は画像ですが、元となったExcelファイルを本ページの最後からダウンロードできるので、参考にどうぞ。

上記表の中からいくつかの詳細を説明します。

ID

パラメーターに割り当てられたユニークな(重複しない)番号です。メニューの番号に用いても良いですし、通信で読み書きする場合の識別子にも使えます。単純に連番を割り当てるのではなく、グループ単位で10番や100番単位で割り振るのが良いでしょう。

デフォルト値

記録媒体からのパラメーターの読み出しに失敗した場合や、範囲外などあり得ない値であった場合に使用します。

パラメーターの型であり、保持する変数の型でもあります。今回の例では浮動小数点数を用いませんが、必要ならいろいろと考えてみてください。

スクロールできます
内容備考
整数符号付き整数です。整数型として保持します。サイズが変数の型の大きさを表します。
また範囲の補足にある「×0.01」は倍率です。たとえば設定値が100で補足に「×0.01」の場合、「123×0.01 = 1.23」を示します。
+整数符号なし整数です。
英字ラテン文字(A~Z、a~z)の集合です。文字列型として保持します。
サイズが可変長の場合、NUL(00h)が終わりを示します。
記号記号(ASCIIの20h~7Eh)の集合です。
英数字英字とアラビア数字(0~9)の集合です。
文字列英数字と記号の集合です。
権限

パラメーターには簡単に書き換えられると困るものがあります。そのようなパラメーターを保護するために、権限を設定しておくと良いでしょう。メニュー操作をブロックするのはもちろん、通信による誤設定からも保護できる仕組みも合わせて検討してください。

権限内容
0権限なしで誰でも設定可能です。
1パスワード不要のロックを解除すると設定可能です。
誰でも設定は可能ですが、少し注意を促したい場合に使用します。
2パスワードでロックを解除すると設定可能です。
8メーカー用設定です。
メーカー内の調整検査で設定する、係数やしきい値などの情報です。
9メーカー用設定です。
型式やその型式固有の一度のみ書き込む固定情報です。
メモリーマップ

記録媒体のどの位置に、どれだけのサイズで記録するかを表します。詳細は次章を参照してください。

記録フォーマット例

各パラメーターの記録媒体への記録フォーマットは下表のとおりです。
なお1行目は項目、2行目は記録バイト数を表します。

IDパラメーターCRC
2バイト可変長(1~13バイト)1バイト
記録フォーマット

記録フォーマットの内容は次のとおりです。

ID

パラメーターのIDです。
IDまで記録するのは、誤って他のIDのパラメーターを上書きしてしまった場合に確認をとれるようにするためです。

パラメーター

パラメーターの値です。
パラメーターのサイズは内容によって1~13バイトの範囲で変わります。なお整数型のパラメーターのサイズは、使用する変数型のサイズに揃える必要があります。

CRC

IDとパラメーターを含むCRC値です。
記録データが不正に書き換わっていないことを確認するために必要です。

サンプルコード

一部だけですが、パラメーター管理のサンプルコードを掲載します。参考になれば幸いです。

[parameter.c]

/**
 * @file parameter.c
 * @brief パラメーター処理
 */

//------------------------------------------------------------------------------
// include
//------------------------------------------------------------------------------
#include "parameter.h"
#include "eeprom.h"

//------------------------------------------------------------------------------
// define
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// variable : public
//------------------------------------------------------------------------------
// パラメーター
//! 型式
char g_model_name[PARAM_SIZE_MAX + 1];

//! シリアル番号
char g_serial_number[PARAM_SIZE_MAX + 1];

//! 通信:ボーレート
uint32_t g_com_baudrate;

//! 通信:データ長
uint8_t g_com_data_bit;

//! 通信:ストップビット長
uint8_t g_com_stop_bit;

//! 通信:パリティ
uint8_t g_com_parity;

// パラメーター管理用構造体
// clang-format off
//! 型式
const PARAM_STRING g_pt_model_name = {
  {TYPE_CHARA, ID_MODEL_NAME, 16, 13},
  3, 13, "ABC", PERMISSION_IMMUTABLE, &g_model_name
};

//! シリアル番号
const PARAM_STRING g_pt_serial_number = {
  {TYPE_ALPHA_NUMBER, ID_SERIAL_NUMBER, 32, 10},
  10, 10, "0000000000", PERMISSION_IMMUTABLE, &g_serial_number
};

//! 通信:ボーレート
const PARAM_UINT g_pt_com_baudrate = {
  {TYPE_UINT32, ID_COM_BAUDRATE, 64, 4},
  9600, 115200, 9600, 0, PERMISSION_LOCK, &g_com_baudrate
};

//! 通信:データビット長
const PARAM_UINT g_pt_com_data_bit = {
  {TYPE_UINT8, ID_COM_DATA_BIT, 71, 1},
  7, 8, 8, 0, PERMISSION_LOCK, &g_com_data_bit
};

//! 通信:ストップビット長
const PARAM_UINT g_pt_com_stop_bit = {
  {TYPE_UINT8, ID_COM_STOP_BIT, 75, 1},
  1, 2, 1, 0, PERMISSION_LOCK, &g_com_stop_bit
};

//! 通信:パリティ
const PARAM_UINT g_pt_com_parity = {
  {TYPE_UINT8, ID_COM_PARITY, 80, 1},
  0, PARITY_NUMBER-1, 0, 0, PERMISSION_LOCK, &g_com_parity
};
// clang-format on

// パラメーター管理用構造体ポインター
// clang-format off
const PARAM_UINT *g_param_uint_table[PARAM_UINT_NUMBER] = {
  &g_pt_com_baudrate,
  &g_pt_com_data_bit,
  &g_pt_com_stop_bit,
  &g_pt_com_parity
};

const PARAM_STRING *g_param_string_table[PARAM_STRING_NUMBER] = {
  &g_pt_model_name,
  &g_pt_serial_number
};
// clang-format on

//------------------------------------------------------------------------------
// variable : private
//------------------------------------------------------------------------------
static uint8_t m_memdat[PARAM_SIZE_MAX + 1];

//------------------------------------------------------------------------------
// function : private
//------------------------------------------------------------------------------
static void Load_ParameterUInt(const PARAM_UINT *param);
static void Load_ParameterString(const PARAM_STRING *param);

static bool Load_MemoryData(const PARAM_COMMON *common, uint8_t memdat[]);

/** ----------------------------------------------------------------------------
 * @brief パラメーターの読み出し
 * @details 記録媒体からパラメーターを読み出す
 */
void Load_Parameter(void)
{
  for (uint8_t i = 0; i < PARAM_UINT_NUMBER; i++) {
    Load_ParameterUInt(g_param_uint_table[i]);
  }

  for (uint8_t i = 0; i < PARAM_STRING_NUMBER; i++) {
    Load_ParameterString(g_param_string_table[i]);
  }
}

/** ----------------------------------------------------------------------------
 * @brief パラメーターの書き込み
 * @details 記録媒体にパラメーターを書き込む
 */
void Save_Parameter(void)
{
  /* 省略 */
}

/** ----------------------------------------------------------------------------
 * @brief パラメーターの読み出し (符号なし整数)
 * @details 記録媒体からパラメーターを読み出す
 * @param [in] *param : パラメーター情報
 */
static void Load_ParameterUInt(const PARAM_UINT *param)
{
  bool     result;
  uint32_t var;

  // 記録媒体から読み出し
  result = Load_MemoryData(&param->common, m_memdat);
  if (result == true) {
    if (param->common.type == TYPE_UINT8) {
      var = m_memdat[0];
    } else if (param->common.type == TYPE_UINT16) {
      var = ((uint16_t)m_memdat[0] << 8) | (uint16_t)m_memdat[1];
    } else if (param->common.type == TYPE_UINT32) {
      var = ((uint32_t)m_memdat[0] << 24) | ((uint32_t)m_memdat[1] << 16) |
            ((uint32_t)m_memdat[2] << 8) | (uint32_t)m_memdat[3];

      // 読み書きが同じ環境なら下記でも良い (エンディアンに注意)
      // var = *(uint32_t *)m_memdat;
    } else {
      // 設定ミス
      return;
    }
  } else {
    var = param->def_val;
  }

  // 範囲確認
  if ((var < param->min_val) || (var > param->max_val)) {
    // 単純に最大・最小で縛れないパラメーターは別で処理する
    var = param->def_val;
  }

  // 変数に代入
  if (param->common.type == TYPE_UINT8) {
    *(uint8_t *)param->var_addr = var;
  } else if (param->common.type == TYPE_UINT16) {
    *(uint16_t *)param->var_addr = var;
  } else if (param->common.type == TYPE_UINT32) {
    *(uint32_t *)param->var_addr = var;
  } else {
    /* not reached */
  }
}

/** ----------------------------------------------------------------------------
 * @brief パラメーターの読み出し (文字列)
 * @details 記録媒体からパラメーターを読み出す
 * @param [in] *param : パラメーター情報
 */
static void Load_ParameterString(const PARAM_STRING *param)
{
  /* 省略 */
}

/** ----------------------------------------------------------------------------
 * @brief 記録媒体からパラメーターを読み出す
 * @param [in] *common : パラメーター情報
 * @param [out] memdat : 読み出したデータ
 * @retval true : OK
 * @retval false : NG (memdatは使えない)
 */
static bool Load_MemoryData(const PARAM_COMMON *common, uint8_t memdat[])
{
  bool result;

  result = Load_EEPROM(common->mem_addr, common->mem_size, memdat);

  /* IDとCRCの確認処理は省略 */

  return result;
}

[parameter.h]

#ifndef PARAMETERH
#define PARAMETERH

#ifdef __cplusplus
extern "C" {
#endif

//------------------------------------------------------------------------------
// include
//------------------------------------------------------------------------------
#include <stdbool.h>
#include <stdint.h>

//------------------------------------------------------------------------------
// define
//------------------------------------------------------------------------------
#define PARAM_SIZE_MAX (13U)  //!< パラメーターの最大サイズ

//! @enum COM_PARITY
//! @brief パリティ
typedef enum
{
  PARITY_NONE,  //!< なし
  PARITY_ODD,   //!< 奇数
  PARITY_EVEN,  //!< 偶数
  PARITY_NUMBER
} COM_PARITY;

//! @enum PARAM_ID
//! @brief パラメーターID
typedef enum
{
  ID_MODEL_NAME = 1,     //!< 型式
  ID_SERIAL_NUMBER,      //!< シリアル番号
  ID_COM_BAUDRATE = 10,  //!< 通信:ボーレート
  ID_COM_DATA_BIT,       //!< 通信:データ長
  ID_COM_STOP_BIT,       //!< 通信:ストップビット長
  ID_COM_PARITY,         //!< 通信:パリティ
} PARAM_ID;

//! @enum PARAM_TYPE
//! @brief 変数の型
typedef enum
{
  TYPE_INT8         = ((uint16_t)(1U << 0)),  //!< 符号付き8ビット整数
  TYPE_INT16        = ((uint16_t)(1U << 1)),  //!< 符号付き16ビット整数
  TYPE_INT32        = ((uint16_t)(1U << 2)),  //!< 符号付き32ビット整数
  TYPE_UINT8        = ((uint16_t)(1U << 3)),  //!< 符号なし8ビット整数
  TYPE_UINT16       = ((uint16_t)(1U << 4)),  //!< 符号なし16ビット整数
  TYPE_UINT32       = ((uint16_t)(1U << 5)),  //!< 符号なし32ビット整数
  TYPE_ALPHA        = ((uint16_t)(1U << 6)),  //!< 英字 (A-Z, a-z)
  TYPE_SYMBOL       = ((uint16_t)(1U << 7)),  //!< 記号 (20h-7Eh)
  TYPE_ALPHA_NUMBER = ((uint16_t)(1U << 8)),  //!< 英数字 (英字+数字)
  TYPE_CHARA        = ((uint16_t)(1U << 9))   //!< 文字列 (英字+数字+記号)
} PARAM_TYPE;

#define PARAM_TYPE_INT    (TYPE_INT8 | TYPE_INT16 | TYPE_INT32)
#define PARAM_TYPE_UINT   (TYPE_UINT8 | TYPE_UINT16 | TYPE_UINT32)
#define PARAM_TYPE_STRING (TYPE_ALPHA | TYPE_SYMBOL | TYPE_ALPHA_NUMBER | TYPE_CHARA)

//! @enum PARAM_PERMISSION
//! @brief パラメーターの権限
typedef enum
{
  PERMISSION_PUBLIC,       //!< 権限なしで誰でも設定可能
  PERMISSION_LOCK,         //!< パスワード不要のロック
  PERMISSION_PASSWORD,     //!< パスワードによるロック
  PERMISSION_FACTORY = 8,  //!< メーカー用 (調整検査)
  PERMISSION_IMMUTABLE     //!< メーカー用 (一度のみ書き込む固定情報)
} PARAM_PERMISSION;

//! @enum PARAM_UINT_LIST
//! @details パラメーターリスト (符号なし整数)
typedef enum
{
  PARAM_COM_BAUDRATE,  //!< ボーレート
  PARAM_COM_DATA_BIT,  //!< データ長
  PARAM_COM_STOP_BIT,  //!< ストップビット長
  PARAM_COM_PARITY,    //!< パリティ
  PARAM_UINT_NUMBER
} PARAM_UINT_LIST;

//! @enum PARAM_STRING_LIST
//! @details パラメーターリスト (文字列)
typedef enum
{
  PARAM_MODEL_NAME,     //!< 型式
  PARAM_SERIAL_NUMBER,  //!< シリアル番号
  PARAM_STRING_NUMBER
} PARAM_STRING_LIST;

//! @struct PARAMM_COMMON
//! @brief パラメーターの共通情報
typedef struct
{
  PARAM_TYPE type;      //!< 変数の型
  uint16_t   id;        //!< 変数のID
  uint32_t   mem_addr;  //!< 記録先アドレス
  uint8_t    mem_size;  //!< 記録サイズ
} PARAM_COMMON;

//! @struct PARAM_UINT
//! @brief 符号なし整数型のパラメーター情報
typedef struct
{
  PARAM_COMMON     common;
  uint32_t         min_val;         //!< 最小値
  uint32_t         max_val;         //!< 最大値
  uint32_t         def_val;         //!< デフォルト値
  uint8_t          decimal_places;  //!< 小数点以下桁数
  PARAM_PERMISSION permission;      //!< 権限
  void            *var_addr;        //!< 変数のアドレス
} PARAM_UINT;

//! @struct PARAM_STRING
//! @brief 文字列のパラメーター情報
typedef struct
{
  PARAM_COMMON     common;
  uint8_t          min_len;     //!< 最小文字数
  uint8_t          max_len;     //!< 最大文字数
  char            *def_string;  //!< デフォルト値
  PARAM_PERMISSION permission;  //!< 権限
  void            *var_addr;    //!< 変数のアドレス
} PARAM_STRING;

//------------------------------------------------------------------------------
// variable
//------------------------------------------------------------------------------
extern char g_model_name[PARAM_SIZE_MAX + 1];
extern char g_serial_number[PARAM_SIZE_MAX + 1];

extern uint32_t g_com_baudrate;
extern uint8_t  g_com_data_bit;
extern uint8_t  g_com_stop_bit;
extern uint8_t  g_com_parity;

extern const PARAM_UINT   *g_param_uint_table[PARAM_UINT_NUMBER];
extern const PARAM_STRING *g_param_string_table[PARAM_STRING_NUMBER];

//------------------------------------------------------------------------------
// function
//------------------------------------------------------------------------------
void Load_Parameter(void);
void Save_Parameter(void);

#ifdef __cplusplus
}
#endif

#endif

[eeprom.h]

#ifndef EEPROMH
#define EEPROMH

#ifdef __cplusplus
extern "C" {
#endif

//------------------------------------------------------------------------------
// include
//------------------------------------------------------------------------------
#include <stdbool.h>
#include <stdint.h>

//------------------------------------------------------------------------------
// function
//------------------------------------------------------------------------------
bool Load_EEPROM(uint16_t addr, uint8_t size, uint8_t memdat[]);

#ifdef __cplusplus
}
#endif

#endif

サンプルコードの使用例

使用例代わりに、CppUTestによるテストコードを掲載しておきます。

#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport_c.h"

#include "eeprom.h"
#include "parameter.h"

// clang-format off
TEST_GROUP(parameter){
  TEST_SETUP(){
  }

  TEST_TEARDOWN(){
	  mock_c()->clear();
  }
};
// clang-format on

TEST(parameter, Test_Load_Parameter)
{
  uint8_t cnt = 0;
  uint8_t memdat[4][14];

  // 通信:ボーレート = 115200 (ビッグエンディアン)
  memdat[cnt][0] = 0x00;
  memdat[cnt][1] = 0x01;
  memdat[cnt][2] = 0xC2;
  memdat[cnt][3] = 0x00;
  mock_c()
      ->expectOneCall("Load_EEPROM")
      ->withUnsignedIntParameters("addr", g_param_uint_table[cnt]->common.mem_addr)
      ->withUnsignedIntParameters("size", g_param_uint_table[cnt]->common.mem_size)
      ->withOutputParameterReturning("memdat", memdat[cnt], 4)
      ->andReturnBoolValue(true);
  cnt++;

  // 通信:データ長
  memdat[cnt][0] = 8;
  mock_c()
      ->expectOneCall("Load_EEPROM")
      ->withUnsignedIntParameters("addr", g_param_uint_table[cnt]->common.mem_addr)
      ->withUnsignedIntParameters("size", g_param_uint_table[cnt]->common.mem_size)
      ->withOutputParameterReturning("memdat", memdat[cnt], 1)
      ->andReturnBoolValue(true);
  cnt++;

  // 通信:ストップビット長
  memdat[cnt][0] = 1;
  mock_c()
      ->expectOneCall("Load_EEPROM")
      ->withUnsignedIntParameters("addr", g_param_uint_table[cnt]->common.mem_addr)
      ->withUnsignedIntParameters("size", g_param_uint_table[cnt]->common.mem_size)
      ->withOutputParameterReturning("memdat", memdat[cnt], 1)
      ->andReturnBoolValue(true);
  cnt++;

  // 通信:パリティ
  memdat[cnt][0] = 0;
  mock_c()
      ->expectOneCall("Load_EEPROM")
      ->withUnsignedIntParameters("addr", g_param_uint_table[cnt]->common.mem_addr)
      ->withUnsignedIntParameters("size", g_param_uint_table[cnt]->common.mem_size)
      ->withOutputParameterReturning("memdat", memdat[cnt], 1)
      ->andReturnBoolValue(true);

  Load_Parameter();
  LONGS_EQUAL(g_com_baudrate, 115200);
  LONGS_EQUAL(g_com_data_bit, 8);
  LONGS_EQUAL(g_com_stop_bit, 1);
  LONGS_EQUAL(g_com_parity, 0);

  // 結果検証
  mock_c()->checkExpectations();
}

/** ----------------------------------------------------------------------------
 * @brief モック関数
 */
bool Load_EEPROM(uint16_t addr, uint8_t size, uint8_t memdat[])
{
  mock_c()
      ->actualCall("Load_EEPROM")
      ->withUnsignedIntParameters("addr", addr)
      ->withUnsignedIntParameters("size", size)
      ->withOutputParameter("memdat", memdat);
  return mock_c()->boolReturnValue();
}

Excelファイルダウンロード

パラメーター管理例のExcelファイルデータです。
ZIP形式で圧縮してあり、解凍するとxlsx形式のExcelファイルが現れます。
個人・商用利用を問いませんので、ダウンロードしてご自由に使用してください。

ファイル名:KN0019-00.zip
ファイル容量:21KB

コメント

コメントする

CAPTCHA


目次