PR

トワイライト(TWELITE)のEEPROMを使い方

組み込みエンジニア
本記事はプロモーションが含まれています。

こんにちは、ENGかぴです。

ZigBeeモジュールであるトワイライト(TWELITE)はEEPROMを搭載しているため電源が切れてもデータを保持できます。クラスオブジェクトであるEEPROMを使用することで簡単にEEPEOMの書き込みと読み込みができます。

EEPROMに関するAPIを使用してEEPROMへの書き込みを行いリセット後にEEPROMから読み出した値を確認してEEPROMの動作確認を行いました。

トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。

トワイライト(TWELITE)のソフト開発と無線通信でできること

EEPROMを使用する

TWELITEの内蔵EEPROMに対して読み書きを行うライブラリについては下記リンクに詳細が説明されています。

モノワイヤレス社HPーMWX Library EEPROM

内蔵EEPROMは256バイトごとにブロックが分かれているため0x000~0xEFFまでの3840バイトが使用可能となります。メーカのHPによると先頭から256バイトまではインタラクティブモードで使用される可能性があるため0x00~0x100までは使用しない方が良いでしょう。

使用する関数

#define EEP_ADRS_START 0x300
#define EEP_ADRS_START_CHK 0x380 //チェック用のアドレス

//EEPROM.write(EEP_ADRS_START, btncnt[0]);
EEPROM.update(EEP_ADRS_START, btncnt[0]); //btncnt[0]の値を書き込む
EEPROM.update(EEP_ADRS_START_CHK, btncnt[0]);

mst = EEPROM.read(EEP_ADRS_START); //EEPROMの値を読み込み

EEPROMに書き込む際に使用する関数はwrite()とupdate()ですがudtateを使用することで同じ値であれば書き込みをしないためEEPROMの不要な書き込みを防ぐことができます。

EEPROMは書き込み回数に限りがあるため基本的にはupdateを使用した方が良いでしょう。

EEPROMに保存した値の読み込みは対象のアドレスを指定してread()関数をコールします。読み込んだEEPROMの値が戻り値として返されるため変数に格納します。

広告
PR:わからないを放置せず、あなたにあったスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!

ヘルパーオブジェクトを使用する

EEPROMの読み書きが簡単に実装できるようにstream_helperオブジェクトが実装されています。

auto&& strm = EEPROM.get_stream_helper();
strm.seek(EEP_ADRS_START);
strm >> btncnt[0]; //EEPROMの読み込み

strm.seek(EEP_ADRS_START);
strm << btncnt[0]; //EEPROMへの書き込み

ヘルパーオブジェクトはサイズの違う整数型やformatで変換した値の読み書きが簡単にできます。1バイトずつ書き込む場合はupdate()関数を使用し、1バイト以上の値を書き込む場合はヘルパーオブジェクトを使用するなど用途に応じて使い分けることができます。

EEPROMデータの読み出しとチェック

void InitEepSetting(void){
    uint8_t i;
    uint8_t mst[sizeof(inittbl)];
    uint8_t chk[sizeof(inittbl)];
    bool boo = true;

    for( i =0; i < sizeof(inittbl);i++){
        mst[i] = EEPROM.read(EEP_ADRS_START + i);
        chk[i] = EEPROM.read(EEP_ADRS_START_CHK + i);

        if(mst[i] != chk[i]){ //値が一致するか
            btncnt[i] = inittbl[i]; //初期化テーブルの値を使用
            boo = false;
        }
        else{
            btncnt[i] = mst[i]; //EEPROMの値を使用
        }
    }
}

上の例ではbtncntにEEPROMの値もしくは初期化テーブルの値を展開して使用する例を示しています。EEPROMの値は初期化時に展開して使用します。

EEP_ADRS_STARTとEEP_ADRS_START_CHKのアドレスに書き込んだEEPROMデータを読み込み、値が一致するかの確認を行います。

読み込んだ値が一致する場合はEEPROMが健全であると判断してEEPROMから読み出した値を採用します。一致しなかった場合はEEPROMの値を使用せずに初期化テーブルの値を使用します。

スポンサーリンク

動作確認

トワイライトのEEPROMの動作を確認するためにボタンを押した回数をEEPROMに書き込みリスタート後にEEPROMから読み込んだ値をモニタに表示して動作確認を行います。

動作確認用の回路

EEPROMの動作確認の回路図
EEPROMの動作確認の回路図

EEPROMの確認のためSW1を押した回数をシリアルモニタに表示します。SW1を複数回押してカウント値を更新しSW1を長押し(2秒)するとEEPROMへ押した回数を書き込みます。SW1に接続するDIはプルアップを有効にしています。

EEPROMに書き込んだ後はトワイライトを再起動するため電源をOFFします。再起動すると初期設定によってEEPROMの値を読み込んでシリアルモニタに表示します。シリアルモニタを使用するためトワイライターをUSB接続したまま動作確認を行います。

動作結果

EEPROMの動作確認
EEPROMの動作確認

トライライターをブレッドボードに挿入して配線していますがVCCはピン端子で出ていないためTWELITE-DIPの28ピンのICソケットからDC3.3Vを供給しています。

Tera Termを使って動作確認を行うとシリアルモニタにbtn1:5、btn1:8と長押しを除くカウント数が表示されておりEEPROMからデータが読み出せていることが分かります。電源をOFF(トワイライターのRSTボタンを押す)しても、データが消えることなく読み出せていることが確認できました。

スポンサーリンク

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

#include <TWELITE>

#define EEP_ADRS_START 0x300
#define EEP_ADRS_START_CHK 0x380
#define EEP_WRITE_WAIT 2000
#define BTN_CNT_MAX 30
#define HELPER_USE //ヘルパーオブジェクトを使用

#define PIN_DI1 5
#define FILTER_MAX 5
#define TIME_UP 0
#define TIME_OFF -1

const uint8_t inittbl[] ={0xFF,0xFF}; //btn1, btn2の初期値
/* 変数宣言*/
uint8_t btncnt[sizeof(inittbl)];
int16_t timWriteStart = TIME_OFF;

/* プロトタイプ宣言*/
void InitEepSetting(void);
void mainApp(void);
void mainTimer(void);

/*** the setup procedure (called on boot) */
void setup() {

    pinMode(PIN_DI1,INPUT_PULLUP);
    Buttons.setup(FILTER_MAX);
    Buttons.begin( 1UL << PIN_DI1, FILTER_MAX ,10);
    Serial.begin();
    InitEepSetting(); //EEPROMの初期展開
}
/*** the loop procedure (called every event) */
void loop() {

    mainTimer();

    if( Buttons.available() ){
        uint32_t  bm,cm;
      
        if( Buttons.read(bm,cm) ){
            if( ( bm & (1UL << PIN_DI1)) == 0 ){
                if( ++btncnt[0] >= BTN_CNT_MAX ){
                    btncnt[0] = 0;
                }
                timWriteStart = EEP_WRITE_WAIT;
                Serial << "TIME_SET" << crlf << mwx::flush;
            }else{
                timWriteStart = TIME_OFF;
                //Serial << "TIME_OFF" << crlf << mwx::flush;
            }
        }
    }

    if(timWriteStart == TIME_UP){
        timWriteStart = TIME_OFF;
        mainApp();
    }
}
/* EEPROMの値を展開(初期化時)*/
void InitEepSetting(void){
    uint8_t i;
    uint8_t mst[sizeof(inittbl)];
    uint8_t chk[sizeof(inittbl)];
    bool boo = true;

    #ifdef HELPER_USE
        auto&& strm = EEPROM.get_stream_helper();
        strm.seek(EEP_ADRS_START);
        strm >> mst[0] >> mst[1];
        strm.seek(EEP_ADRS_START_CHK);
        strm >> chk[0] >> chk[1];
    #else
        for( i =0; i < sizeof(inittbl);i++){
            mst[i] = EEPROM.read(EEP_ADRS_START + i);
            chk[i] = EEPROM.read(EEP_ADRS_START_CHK + i);
        }
    #endif

    for( i =0; i < sizeof(inittbl);i++){
        if(mst[i] != chk[i]){
            btncnt[i] = inittbl[i];
            boo = false;
        }
        else{
            btncnt[i] = mst[i];
        }
    }

    if( boo){
        Serial << "EEP_CHK_OK" << crlf << mwx::flush;
        Serial << "btn1:" << int(btncnt[0]) << crlf << mwx::flush;
    }else{
        Serial << "EEP_CHK_NG" << crlf << mwx::flush;
    }
}
/* メイン処理 */
void mainApp(void){

    if( btncnt[0] == 0 ){
        btncnt[0] = BTN_CNT_MAX;
    }
    else{
        --btncnt[0];
    }

    #ifdef HELPER_USE
        auto&&  strm = EEPROM.get_stream_helper();
        strm.seek(EEP_ADRS_START);
        strm << btncnt[0] << btncnt[1];
        strm.seek(EEP_ADRS_START_CHK);
        strm << btncnt[0] << btncnt[1];
    #else
        for( uint8_t i; i <  sizeof(inittbl); i++){
            EEPROM.update(EEP_ADRS_START + i , btncnt[i]);
            EEPROM.update(EEP_ADRS_START_CHK + i, btncnt[i]);
        }
    #endif

    Serial << "EEP_WRITE_OK" << crlf << mwx::flush;
}
/* タイマ管理 */
void mainTimer(void){

    if( TickTimer.available()){
        if(timWriteStart > TIME_UP ){
            --timWriteStart;
        }
    }
}

関連リンク

トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。

トワイライト(TWELITE)のソフト開発と無線通信でできること

PR:テックキャンプエンジニア転職

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました