Arduinoを USB/HIDデバイス(仮想キーボード)として活用する(第六回)ロギングとプロット②


本記事について

 Arduinoを USB/HIDデバイスとして活用する第六回②です。第六回①はここ。①で実現した制御結果をロギングするところを紹介します。

第六回)「赤外線によるエアコンのON/OFFと結果のロギングとプロット②」

①で紹介した、赤外線によるエアコンのON/OFFと温度調整制御を行いながら、周期毎のセンサー値や制御結果をEEPROMにロギングします。
 ロギングは、周期的に発生するデータ一式を繰り返し回数分保持し、実行後にデータを指定して時系列順に取り出すなどして利用します。個々のデータのことをチャンネル(ch)と呼びます。
 実現方法として特筆すべきは、アプリとデータの独立性を高めデータの追加/変更を容易とするため、EEPROM上のデータを読み書きする仕組みとして、INFOという考え方を導入したことです。これは、さまざまなアプリに適用することができます。
 データの発生頻度が高くなければ、より大量にデータを保存できる方法として、ファイルをSDカードに保存する方法もあります。が、今回はエアコンのON/OFF制御のロギングということで、1日程度、データを保管する仕組みとしてEEPROMを使って実現しました。

機能概要

  下図にあるように、初期化時に蓄積するデータにラベル名(ch名)を付与してEEPROMアドレスと紐付けをします。これをINFO情報と呼びます。データは個別データと周期データを格納することができます。個別データはアプリ間のデータ共有として利用します。周期データはロギング/ビューワーで利用します。
 制御実行時には、ロガーにより、ch名を指定して(EEPROMのアドレスを指定することなく)EEPROMに書き込みます。制御実行後動かすビューアーでは、 ch名と周期を指定してデータを読み出すことができます。また、アクセスをサポートするライブラリーも用意しました。ライブラリーでは、INFO情報を使ってchを読み書きすることができます。
 この仕組みを使えば、データの追加/変更が簡単にでき、複数のアプリが共通のINFOを介してEEPROM上のデータにアクセスすることもできます。

・データの追加/変更が簡単にでき、EEPROMの物理アドレスを気にすることなくアプリ実装ができる。
・今回はマイコン1つだが、マイコンが複数であってもEEPROMを共有する仕組みが実現できる。
・INFOの提供元としてSDカードがあれば、ファイル渡しもできる。

<INFO を使ってEEPROMをアクセスするイメージ>

info情報

info情報の変数定義
//info 情報定義構造体
typedef struct _INFO {
   char label[8];       //ch
   uint16_t  address;   //EEPROM保存時のアドレス
   uint16_t  len;       //1,2,4byte
} INFO;
//個別データ
#define INFOMAX 5
int tableInfoCount = INFOMAX;
INFO tableInfo[INFOMAX];
//周期データ(ヘッダー)
#define HEADERMAX 20
INFO tableHeaderInfo[HEADERMAX];
//周期データ(データ)
#define LOGRMAX 8
INFO tableLogInfo[LOGRMAX];
info情報
//初期化にて、設定する情報の例
//BME280で取得した温度、湿度、気圧を共有する
#define MAPDT     0x0040
#define MAPDH     0x0042
#define MAPDP     0x0044
#define MAPDC     0x0046
#define MAPDY     0x0047
//周期データは、温度、湿度、制御値
#define MAPLOGK     0x0000
#define MAPLOGL     0x0002
#define MAPLOGC     0x0003
//個別データのchごとの情報
  strcpy(tableInfo[0].label , "Dtemp");
  tableInfo[0].address = MAPDT;
  tableInfo[0].len = 2;
  strcpy(tableInfo[1].label , "Dhum");
  tableInfo[1].address = MAPDH;
  tableInfo[1].len = 2;
  strcpy(tableInfo[2].label , "Dpress");
  tableInfo[2].address = MAPDP;
  tableInfo[2].len = 2;
  strcpy(tableInfo[3].label , "Dctl");
  tableInfo[3].address = MAPDC;
  tableInfo[3].len = 1;
  strcpy(tableInfo[4].label , "Dyobi");
  tableInfo[4].address = MAPDY;
  tableInfo[4].len = 1;
  tableInfoCount = 5;
//周期データのchごとの情報
  strcpy(tableLogInfo[0].label , "LK");
  tableLogInfo[0].address = MAPLOGK;
  tableLogInfo[0].len = 2;
  strcpy(tableLogInfo[1].label , "LL");
  tableLogInfo[1].address = MAPLOGL;
  tableLogInfo[1].len = 1;
  strcpy(tableLogInfo[2].label , "LC");  //controll値 エアコン on/off
  tableLogInfo[2].address = MAPLOGC;
  tableLogInfo[2].len = 1;  // int8_t とする 
  tableLogInfoCount = 4
//周期データの管理情報
  tableLogRepeat[0] = 2048; //最大個数
  tableLogRepeat[1] = 2048;
  tableLogRepeat[2] = 2048;
  tableLogStartAddr[0] = 0x4000; //先頭アドレス
  tableLogStartAddr[1] = 0x8000;
  tableLogStartAddr[2] = 0xc000;

INFO構造体が、ch名とEEPROM物理アドレスを変換する主要な情報となる。
この例では、個別データを5つ、周期データを4つ定義している。周期データの最大個数を2048 としている。これだけのことを初期化で行っておけば、実際のEEPROM読み書き時は、ch名でアクセスできる。

提供されるライブラリ

ログヘッダーの読み書き
//Logヘッダーを読む  
bool sub_EEPROM512_ReadLogHeader(int8_t p_lognum, unsigned long* p_s, unsigned long* p_e, int16_t* p_c, int16_t* p_n)
//
//Logヘッダーを書く 
void sub_EEPROM512_WriteLogHeader(char p_se)

ロギングされたデータを管理するため、ログヘッダーの読み書き関数を提供する。

ラベルを指定してログを読み書き
//chデータを書く
  int16_t p_t;  //温度、 25.00度の場合は2500とする
  char* p = (char*)&p_t;
  sub_SetLogVal(gCount, "LK", p); //温度
//chデータを読む
    char p[8];
  int16_t* fp;
  sub_GetLogVal(pCount, "LK", p);
  fp = (int16_t*)(p);

周期データの読み書き関数を提供する。

実行時のログ蓄積

・個別データ用の例
 "Dtemp"というch名のデータを制御で書き、別アプリで読むイメージの図です。

・周期データ用の例
"LK"というch名の周期データをロガーで書き、ビューアーで読み出すイメージ図です。何番名のデータかを意味する、パラメータ=cがあることがわかります。

ログ管理機能

3セットのログを保持できるようにした。ログヘッダには、開始、終了、実行周期、データ点数を保持している。3セットのログのうち、次回書き込む番号(つまりログを残す番号)、次回読み取る番号(つまりプロットする番号)を指定することができる。
LLISTの例) LPLOT 0 / LNEXT 2 を実行した後の状態

ログに関する命令は以下の3種類
・LLIST 一覧表示
・LNEXT n 次回使用するログの指定 (書込番号)
・LPLOT n PLOTログの指示 (読込番号)

 使い方手順例)
1。LLIST でログの状況を確認する。次回のロギングはログ番号2を使うと決める
2。LNEXT 2 で書込番号を2に設定する
3。ロギング実行
4。ロギング終了後、LLISTでログが書き込まれたことを確認する(時間、点数など)
5。LPLOT 2 で読込番号を2に設定する
6。シリアルモニター画面に切り替えて、1を入力すると、1ページ目が描画される。
  点数が500点以上であれば、2を入力して、2ページ目を描画する、、、

まとめ

 実装上の工夫として、アプリとデータの独立性を高めデータの追加/変更を容易とする、INFOという考え方を実現できました。開発中にEEPROMを違うサイズに取り替えることが発生しましたが、アドレス依存部分が局所的で簡単に対応することができました。アプリの仕様変更にも柔軟に対応できると考えます。また、各種アプリで利用するために、ライブラリーとして提供することも考えられます。
 ③では、ロギングしたデータを取り出してIDEのシリアルプロッターにプロットする仕組みを紹介します。