プログラムと電子工作・不揮発性メモリ
不揮発性メモリは、M5StickC の電源をオフしても値を保持するメモリ領域です。
プログラムのパラメータなど、多数の小さな値を保存する場合は Preferences オブジェクトを使用すると便利です。
目標
不揮発性メモリの初期化と終了、値を読み出し/書き込みします。
不揮発性メモリの値を全部消去します。
部品・機材
使用する部品は次のとおりです。「Hello, World!」と全く同じです。
電子部品
M5StickC Plus 1台
開発用機材
PC(Windows10 または 11)、開発環境 Arduino-IDE 導入ずみ
USB-A・USB-C ケーブル
開発手順
PC と M5StickC Plus を USBケーブルで接続する。
Arduino-IDE でスケッチ preferences.ino を開く。
検証・コンパイルする。
M5StickC Plus に書き込む。
スケッチ
references.ino
#include <M5StickCPlus.h>
#include <nvs_flash.h>
#include <Preferences.h>
#define LHEIGHT 15 /*1行の高さ(px)TextSize(3):25、TextSize(2):15*/
#define MY_APP "my_app" /*名前空間 15文字以内*/
Preferences pref;
bool nvs_erased = false;
uint32_t time_to_wait = millis();
//------------------------------------------------------------------------------
// setup()
void setup() {
// 電源ON時に 1回だけ実行する処理をここに書く。
M5.begin(); /*M5を初期化する*/
M5.Lcd.setTextSize(2); /*文字サイズはちょっと小さめ*/
M5.Lcd.setRotation(3); /*上スイッチが左になる向き*/
M5.Lcd.print("preferences");
M5.Lcd.setCursor(0, LHEIGHT*2); /*3行目*/
M5.Lcd.print("btnA to clear nvs.");
Serial.begin(115200); /*デバッグ用のシリアル通信を初期化する*/
// Preference を Read/Write モードで開く。
pref.begin(MY_APP, false);
// アプリを開くたびに領域を消す。
// ※ 消したくないので、コメントにしている。
//pref.clear();
// パラメータ "counter" だけを消す。
// パラメータ名は 15文字以下。
// ※ 消したくないので、コメントにしている。
//pref.remove("counter");
// パラメータ "counter" の値を読む。パラメータがないときは 0になる。
uint16_t counter = pref.getUShort("counter", 0);
// パラメータ "counter" の値を LCD に表示する。
M5.Lcd.setCursor(0, LHEIGHT*1); /*2行目*/
M5.Lcd.printf("count: %6u", counter);
// counter をインクリメントする。
counter++;
Serial.printf("Current counter value: %u\n", counter);
// パラメータ "counter" の値を書く。電源を切っても消えない。
pref.putUShort("counter", counter);
// Preference を閉じる。
pref.end();
Serial.println("Restarting in 10 seconds...");
}
//------------------------------------------------------------------------------
// loop()
void loop() {
// 自動的に繰り返し実行する処理をここに書く。
// ボタンの状態を更新する。
M5.update();
// 上ボタン(ボタンA)をチェックする。
if (M5.BtnA.wasPressed() && !nvs_erased) {
// --- 上ボタンが押された。
// 不揮発性メモリの名前空間すべてのメモリを消去する。
nvs_flash_erase(); // erase the NVS partition and...
nvs_flash_init(); // initialize the NVS partition.
nvs_erased = true;
time_to_wait = millis();
M5.Lcd.setCursor(0, LHEIGHT*2); /*3行目*/
M5.Lcd.print("nvs all cleared. ");
Serial.print("nvs was all cleared.\n");
}
// 10秒待つ。
if (10 * 1000 < millis() - time_to_wait) {
// --- 10秒経った。
// リスタートする。
ESP.restart();
}
}
setup() 関数で、不揮発性メモリからカウンタの値を読み出し、液晶ディスプレイに値を表示した後、カウンタを +1し、不揮発性メモリに書き込んでいます。
loop() 関数で 10秒待ち、リスタートします。
上ボタン(押しボタンA)を押すと、不揮発性メモリの名前空間すべてのメモリを消去します。
結果
もし +1した値が保存されていなければ、リスタート後毎回「count: 0」と表示されるはずです。実際は、カウンタの値が前回の値から +1ずつ上がります。(写真1)
上ボタン(押しボタンA)を押すと、カウンタが 0クリアされます。不揮発性メモリのすべての名前空間が消去されます。
注意
不揮発性メモリは、電源をオフすると消えるメモリとは異なり、書き込み回数に制限があるので、頻繁に書換えるような使用は避けてください。(まあ少々のことでは制限を超えることはないでしょうが...)
参考
ArduinoーエSP32 ESPRESSIF Libraries--APIs--Preferences
/*
* Prefereces クラスの使用方法:
*
* 1. 初期化、終了
* #include <Preferences.h>
* Preferences pref;
*
* bool pref.begin(const char* my_namespace, bool readOnly = false, const char* partition_label = nullptr);
* // const char* my_namespace: 15文字以下、アプリケーションごとにユニークな名称。衝突しないように付ける。
* // bool readOnly: false 読書きモード、true 読出しのみ
* void pref.end();
*
* 2. 消去
* bool pref.clear(); //名前空間の中身をすべて消去する。名前空間は残る。
* bool pref.remove(const char* key_name); //キーと値のペアを削除する。
* // const char* key_name: 15文字以下、フラッシュメモリに格納するパラメータの名称、名前空間内でユニーク。
*
* 3. 読み書き
* size_t pref.putChar(const char* key_name, int8_t value);
* size_t pref.putUChar(const char* key_name, uint8_t value);
* size_t pref.putShort(const char* key_name, int16_t value);
* size_t pref.putUShort(const char* key_name, uint16_t value);
* size_t pref.putInt(const char* key_name, int32_t value);
* size_t pref.putUInt(const char* key_name, uint32_t value);
* size_t pref.putLong(const char* key_name, int32_t value);
* size_t pref.putULong(const char* key_name, uint32_t value);
* size_t pref.putLong64(const char* key_name, int64_t value);
* size_t pref.putULong64(const char* key_name, uint64_t value);
* size_t pref.putFloat(const char* key_name, float_t value);
* size_t pref.putDouble(const char* key_name, double_t value);
* size_t pref.putBool(const char* key_name, bool value);
* size_t pref.putString(const char* key_name, const char* value);
* size_t pref.putString(const char* key_name, String value);
* size_t pref.putBytes(const char* key_name, const void* value, size_t len);
*
* int8_t pref.getChar(const char* key_name, int8_t defaultValue = 0);
* uint8_t pref.getUChar(const char* key_name, uint8_t defaultValue = 0);
* int16_t pref.getShort(const char* key_name, int16_t defaultValue = 0);
* uint16_t pref.getUShort(const char* key_name, uint16_t defaultValue = 0);
* int32_t pref.getInt(const char* key_name, int32_t defaultValue = 0);
* uint32_t pref.getUInt(const char* key_name, uint32_t defaultValue = 0);
* int32_t pref.getLong(const char* key_name, int32_t defaultValue = 0);
* uint32_t pref.getULong(const char* key_name, uint32_t defaultValue = 0);
* int64_t pref.getLong64(const char* key_name, int64_t defaultValue = 0);
* uint64_t pref.getULong64(const char* key_name, uint64_t defaultValue = 0);
* float_t pref.getFloat(const char* key_name, float_t defaultValue = NAN);
* double_t pref.getDouble(const char* key_name, double_t defaultValue = NAN);
* bool pref.getBool(const char* key_name, bool defaultValue = false);
* size_t pref.getString(const char* key_name, char* value, size_t maxLen);
* String pref.getString(const char* key_name, String defaultValue = String());
* size_t pref.getBytesLength(const char* key_name);
* size_t pref.getBytes(const char* key_name, void * buf, size_t maxLen);
*
* 4. その他
* size_t pref.getBytesLength(const char* key_name); //キーに対する値のバイト数を取得する。
* PreferenceType pref.getType(const char* key_name); //キーに対する値のデータ型を取得する。
* // PreferenceType: PT_I8 Char; PT_U8 UChar, Bool; PT_I16 Short;
* // PT_U16 UShort; PT_I32 Int, Long; PT_U32 UInt, ULong;
* // PT_I64 Long64; PT_U64 ULong64; PT_STR String;
* // PT_BLOB Double, Float, Bytes; PT_INVALID エラー
* size_t pref.freeEntries(); //使用可能な空き数を取得する。
* bool pref.isKey(const char* key_name); //キーが存在するか確認する。
*/
不揮発性メモリの名前空間すべてのメモリを消去する
ライセンス
このページのソースコードは、複製・改変・配布が自由です。営利目的にも使用してかまいませんが、何ら責任を負いません。
この記事が気に入ったらサポートをしてみませんか?