こんにちは、ENGかぴです。
ZigBeeモジュールであるトワイライト(TWELITE)はEEPROMを搭載しているため電源が切れてもデータを保持できます。クラスオブジェクトであるEEPROMを使用することで簡単にEEPEOMの書き込みと読み込みができます。
EEPROMに関するAPIを使用してEEPROMへの書き込みを行いリセット後にEEPROMから読み出した値を確認してEEPROMの動作確認を行いました。
トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。
トワイライト(TWELITE)のソフト開発と無線通信でできること
EEPROMを使用する
TWELITEの内蔵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に保存した値の読み込みは対象のアドレスを指定して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の確認のためSW1を押した回数をシリアルモニタに表示します。SW1を複数回押してカウント値を更新しSW1を長押し(2秒)するとEEPROMへ押した回数を書き込みます。SW1に接続するDIはプルアップを有効にしています。
EEPROMに書き込んだ後はトワイライトを再起動するため電源をOFFします。再起動すると初期設定によってEEPROMの値を読み込んでシリアルモニタに表示します。シリアルモニタを使用するためトワイライターをUSB接続したまま動作確認を行います。
動作結果
トライライターをブレッドボードに挿入して配線していますが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)のソフト開発と無線通信でできること
最後まで、読んでいただきありがとうございました。