🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
M5Stack

M5Stackは、小型のマイコンモジュールです。拡張モジュールが豊富に用意されており、センサと組み合わせることで測定機能を自由に追加することができます。

Q&A

解決済

1回答

5808閲覧

AtomLiteのフラッシュメモリへのセンサー値の格納方法について

退会済みユーザー

退会済みユーザー

総合スコア0

M5Stack

M5Stackは、小型のマイコンモジュールです。拡張モジュールが豊富に用意されており、センサと組み合わせることで測定機能を自由に追加することができます。

0グッド

0クリップ

投稿2020/11/25 04:42

編集2020/11/25 04:53

前提・実現したいこと

AtomLiteとセンサーを接続し、センサー(温湿度センサーなど)で読み取ったデータをAtomLite内のフラッシュメモリに保存したいです。SDカードなどでのデータ保存先の増設はしたくないです。

理想では、
「パソコン(Arduino IDE)からAtomLiteにプログラムを書き込む → AtomLiteとセンサーを接続し乾電池駆動させ、センサーを用いてデータを取得しAtomLite内のフラッシュメモリに保存する → AtomLiteをパソコンに接続し、フラッシュメモリ内のデータをCSVファイルなどに出力する」
です。

フラッシュメモリにEEPROMとSPIFFSが分かったので、現時点ではEEPROM.hを使用しています。
以下のプログラムはEEPROMのサンプルスケッチ"eeprpm_class"にMHZ19(CO2センサ)のプログラムを組み合わせたものです。
数秒ごとに温度データが増えていくと思っていましたが、シリアルモニタを見ていてもデータが蓄積されません。

お教えいただきたいことは、
・動的なデータをAtomLite内のフラッシュメモリに保存する方法・プログラム
・その後のデータの取り出し方・プログラム
です。
センサーを複数使用する予定のため、SPIFFSの方がよいなど、アドバイスがありましたら、そちらもご教授ください。
よろしくお願いいたします。

該当のソースコード

/* ESP32 eeprom_class example with EEPROM library This simple example demonstrates using EEPROM library to store different data in ESP32 Flash memory in a multiple user-defined EEPROM class objects. Created for arduino-esp32 on 25 Dec, 2017 by Elochukwu Ifediora (fedy0) converted to nvs by lbernstone - 06/22/2019 */ #include <M5Atom.h> #include "EEPROM.h" // Instantiate eeprom objects with parameter/argument names and sizes //EEPROMClass NAMES("eeprom0", 0x500); EEPROMClass TEMP("eeprom1", 0x200); //EEPROMClass AGE("eeprom2", 0x100); #include <MHZ19_uart.h> MHZ19_uart mhz19; void setup() { Serial.begin(115200); mhz19.begin(25, 21); mhz19.setAutoCalibration(false); Serial.print("MH-Z19 now warming up... status:"); Serial.println(mhz19.getStatus()); delay(500); } void loop() { //int co2ppm = mhz19.getPPM(); Serial.println("Testing EEPROMClass\n"); /* if (!NAMES.begin(NAMES.length())) { Serial.println("Failed to initialise NAMES"); Serial.println("Restarting..."); delay(1000); ESP.restart(); } */ if (!TEMP.begin(TEMP.length())) { Serial.println("Failed to initialise TEMP"); Serial.println("Restarting..."); delay(1000); ESP.restart(); } /* if (!AGE.begin(AGE.length())) { Serial.println("Failed to initialise AGE"); Serial.println("Restarting..."); delay(1000); ESP.restart(); } */ int temp = mhz19.getTemperature(); //char* name = "Teo Swee Ann"; //double height = 5.8; //uint32_t age = 47; // Write: Variables ---> EEPROM stores //NAMES.put(0, name); TEMP.put(0, temp); //AGE.put(0, age); //Serial.print("name: "); Serial.println(name); Serial.print("temp: "); Serial.println(temp); //Serial.print("age: "); Serial.println(age); Serial.println("------------------------------------\n"); // Clear variables //name = '\0'; //height = 0; //age = 0; //Serial.print("name: "); Serial.println(name); Serial.print("temp: "); Serial.println(temp); //Serial.print("age: "); Serial.println(age); Serial.println("------------------------------------\n"); // Read: Variables <--- EEPROM stores //NAMES.get(0, name); TEMP.get(0, temp); //AGE.get(0, age); //Serial.print("name: "); Serial.println(name); Serial.print("temp: "); Serial.println(temp); //Serial.print("age: "); Serial.println(age); Serial.println("Done!"); delay(0xFFFFFFFF); }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

以下のプログラムはEEPROMのサンプルスケッチ"eeprpm_class"にMHZ19(CO2センサ)のプログラムを組み合わせたものです。

<略>
数秒ごとに温度データが増えていくと思っていましたが、シリアルモニタを見ていてもデータが蓄積されません。

そもそものeeprom_classが一度(疑似)EEPROMに読み書きしたら0xffffffff=約42億ミリ秒=49日間動作を停止するものだから、じゃないですか? 49日待ってみたら?

・動的なデータをAtomLite内のフラッシュメモリに保存する方法・プログラム

・その後のデータの取り出し方・プログラム

についてはそのプログラムで出来ているのではないですか? なにか問題がありましたか?


EEPROMには書き換えの寿命があります。ESP32のフラッシュについてはぱっと見つけられませんでしたが、普通は10万回~100万回くらい。多いと思いますか? 1秒に一回書き換えていたら、100000/3600=27.8時間、です。もちろん、同じ場所を毎回書き換えるわけじゃないでしょうけれど、フラッシュでは大きな単位で消去/書き込みを行うのでその辺も考えないといけません。書き込み場所をどの様に管理しているかはライブラリの中を調べないとわかりません。(フラッシュメモリを使っていても、SDカードやSSDなんかは内部のコントローラがこの辺をよろしくやってくれているので簡単にはへこたれないのですが)
これが多いか少ないかはどういう使い方をするかによるでしょう。
十分検討してください。


なんかもう、よくわからないまま適当にいじくってエラーと格闘するのに付き合わされるのも...
フラッシュメモリの寿命についても何度も言ったので、特に考慮されないということは問題ないのですね。

以下、M5Stackでの試作ですので、BtnAとかは適当に置き換えて参考にして下さい。ファイル関連は質問者提示の関数をほぼそのまま使っています。
短押しで読み出し、長押しで書き込み。

Arduino

1#include <M5Stack.h> 2 3#include <FS.h> 4#include <SPIFFS.h> 5#define FORMAT_SPIFFS_IF_FAILED true 6 7String Buffer ; 8bool isWriteMode; 9 10//==================SPIFFS=================================--- 11void writeFile(fs::FS &fs, const char * path, const char * message) { 12 Serial.printf("Writing file: %s\r\n", path); 13 14 File file = fs.open(path, FILE_WRITE); 15 if (!file) { 16 Serial.println("- failed to open file for writing"); 17 return; 18 } 19 if (file.print(message)) { 20 Serial.println("- file written"); 21 } else { 22 Serial.println("- write failed"); 23 } 24 file.close(); 25} 26 27void appendFile(fs::FS &fs, const char * path, const char * message) { 28 //Serial.printf("Appending to file: %s\r\n", path); 29 30 File file = fs.open(path, FILE_APPEND); 31 if (!file) { 32 Serial.println("- failed to open file for appending"); 33 return; 34 } 35 if (file.print(message)) { 36 //Serial.println("- message appended"); 37 } else { 38 Serial.println("- append failed"); 39 } 40 file.close(); 41} 42void readFile(fs::FS &fs, const char * path) { 43 Serial.printf("Reading file: %s\r\n", path); 44 45 File file = fs.open(path); 46 if (!file || file.isDirectory()) { 47 Serial.println("- failed to open file for reading"); 48 return; 49 } 50 51 Serial.println("- read from file:"); 52 while (file.available()) { 53 Serial.write(file.read()); 54 } 55 file.close(); 56} 57void deleteFile(fs::FS &fs, const char * path) { 58 Serial.printf("Deleting file: %s\r\n", path); 59 if (fs.remove(path)) { 60 Serial.println("- file deleted"); 61 } else { 62 Serial.println("- delete failed"); 63 } 64} 65//=========================================================================== 66 67 68void setup() { 69 Serial.begin(115200); 70 //====SPIFFS Init============================= 71 if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) { 72 Serial.println("SPIFFS Mount Failed"); 73 while (1); 74 } 75 Serial.println("SPIFFS Ready."); 76 //============================================= 77 Serial.println("Waiting for push Button(A)"); 78 do { //ボタンを押すまで待つ 79 M5.BtnA.read(); 80 } while (M5.BtnA.isReleased()); 81 delay(100); 82 isWriteMode = false; //とりあえず読み出しモードに設定 83 //ボタンがどれだけ押されたかによってモード切り替え 84 do { 85 M5.BtnA.read(); 86 if (M5.BtnA.pressedFor(900)) { 87 isWriteMode = true; //1秒以上長押しなら書き込みモードに入れる 88 } 89 } while (M5.BtnA.isPressed()); 90 if (isWriteMode) { 91 Serial.println("WRITE MODE"); 92 //ファイル準備 93 writeFile(SPIFFS, "/hello.txt", "START\n"); 94 } else { 95 Serial.println("READ MODE"); 96 //読み出しモード 97 readFile(SPIFFS, "/hello.txt"); 98 Serial.println("READ DONE."); 99 ESP.restart(); //再起動 100 } 101} 102 103void loop() { 104 int a = 1; 105 float b = 2.1; 106 String c = "Test"; 107 M5.update(); 108 Buffer = String(millis()) + ", " + String(a) + ", " + String(b) + ", " + c + '\n'; //データ生成 109 Serial.print("Writing : " + Buffer); 110 appendFile( SPIFFS, "/hello.txt", Buffer.c_str()); //書き込み 111 for ( int wait = 0; wait < 50; wait++) { 112 //書き込み中にいきなりリセットしたりするとFileSystemが壊れるかも。 113 //安全に止められる停止状態を作る 114 M5.BtnA.read(); 115 if ( M5.BtnA.isPressed()) { 116 Serial.println("Stop..."); 117 ESP.restart(); //再起動 118 } 119 delay(10); 120 } 121}

投稿2020/11/25 23:36

編集2020/12/08 03:01
thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/11/27 22:46

ご回答いただきありがとうございます。 ご指摘いただいた通りでした。 delayの変更で希望通りに表示できました。 また、現在ではシリアルモニタに表示することしかできないのですが、CSVファイル等で取り出す方法はありますでしょうか。 ご教授いただければ幸いです。よろしくお願いいたします。
thkana

2020/11/27 23:17

シリアルモニタに表示出来ているのなら、シリアルへの表示をカンマ/改行区切りにしてteraterm等でログを記録するのが一番簡単かと思います。 というか、SDカード等を使いたくないということであれば、シリアル(WiFiでもBluetoothでもいいですけど)からデータを読み出して、それをファイルとして記録するのはPC側のプログラムの仕事としてやるしかないでしょう。
退会済みユーザー

退会済みユーザー

2020/12/02 03:46 編集

それについてもう少し詳しく教えていただきたいです。 ご教示いただいたとおりteratermを使用し試しました。 https://shinshu-makers.net/shinshu_makers/2020/08/14/%E3%80%90m5%E3%80%91m5stickc%E3%81%A7spiffs%E3%81%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%83%AD%E3%82%B0%EF%BC%9C%E4%BB%A5%E5%A4%96%E3%81%A8%E4%BE%BF%E5%88%A9%EF%BC%9E/ この方の操作1のようにしたく、SPIFFSに変更しプログラムを以下のように書き換えました。 (センサーをGPSに変え分かりやすいように時刻表示するようにしています。) #include "M5Atom.h" //Search $GPGSV for ESP32 DEVKIT V1-DOIT // https://makeradvisor.com/esp32-vs-esp8266/ // https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/ HardwareSerial GPSRaw(2); // ESP32 UART2 GPIO-16 ( RXD2 ) --- GPS TXD static const uint32_t GPSBaud = 9600; char GPSRc; int GPSRi; String Buffer; #include "FS.h" #include "SPIFFS.h" /* You only need to format SPIFFS the first time you run a test or else use the SPIFFS plugin to create a partition https://github.com/me-no-dev/arduino-esp32fs-plugin */ #define FORMAT_SPIFFS_IF_FAILED true //==================SPIFFS=================================--- String dataStr; String dataStr_1; char char_array[]={}; int datalen; int timing; void writeFile(fs::FS &fs, const char * path, const char * message){ Serial.printf("Writing file: %s\r\n", path); File file = fs.open(path, FILE_WRITE); if(!file){ Serial.println("- failed to open file for writing"); return; } if(file.print(message)){ Serial.println("- file written"); } else { Serial.println("- write failed"); } file.close(); } void appendFile(fs::FS &fs, const char * path, const char * message){ //Serial.printf("Appending to file: %s\r\n", path); File file = fs.open(path, FILE_APPEND); if(!file){ Serial.println("- failed to open file for appending"); return; } if(file.print(message)){ //Serial.println("- message appended"); } else { Serial.println("- append failed"); } file.close(); } void readFile(fs::FS &fs, const char * path){ Serial.printf("Reading file: %s\r\n", path); File file = fs.open(path); if(!file || file.isDirectory()){ Serial.println("- failed to open file for reading"); return; } Serial.println("- read from file:"); while(file.available()){ Serial.write(file.read()); } file.close(); } void deleteFile(fs::FS &fs, const char * path){ Serial.printf("Deleting file: %s\r\n", path); if(fs.remove(path)){ Serial.println("- file deleted"); } else { Serial.println("- delete failed"); } } //=========================================================================== void setup() { Serial.begin(115200); // GPS TXD-pin should be connected to Lolin32 Pin-16 GPSRaw.begin(GPSBaud, SERIAL_8N1, 23, 19); //====SPIFFS Init============================= if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){ Serial.println("SPIFFS Mount Failed"); return; } writeFile(SPIFFS, "/hello.txt", "sec,rssi,address,devNum\n\r "); //============================================= } void searchZDA(){ GPSRc = GPSRaw.read(); // read 1 character GPSRi = int(GPSRc); if ( GPSRi == 36 ) { // <= if the 1st character read is '$' Buffer = "$"; while ( GPSRi != 42 ) { char GPSRc = GPSRaw.read(); GPSRi = int(GPSRc); if( GPSRi < 128 ) Buffer += GPSRc; // add one character to the buffer } // if the buffer includes "GPZDA" at the beginning it will be zero // check the first six character of the buffer // Serial.print does not display anything until "$GPGSV" is found if ( Buffer.indexOf("$GPZDA") == 0 ) Serial.println(Buffer); } } void loop() { M5.update(); if (GPSRaw.available()) searchZDA(); if ( M5.Btn.wasPressed() ) { readFile(SPIFFS, "/hello.txt"); } } 今、teraterm上には現在受信しているセンサーのデータ(日時)が表示され、ボタンを押すと Reading file: /hello.txt - read from file: sec,rssi,address,devNum が表示されまた、現在時刻が表示されるだけになります。 センサー値自体はhello.txtに入っていると思っているのですが、それを見えるようにするにはどのようにすればよろしいでしょうか。 初心者で分からないことが多いので詳しく教えていただけますと幸いです。よろしくお願いいたします。
thkana

2020/12/02 12:51

> センサー値自体はhello.txtに入っていると思っているのですが どこでその処理をしていますか?
thkana

2020/12/03 12:40

searchZDA()関数の最後の方を if ( Buffer.indexOf("$GPZDA") == 0 ){ Serial.println(Buffer); appendFile(SPIFFS, "/hello.txt",buffer); } } } とすればNMEAが記録されると思います。SPIFFSの作りがどうなっているかにもよりますが、先に述べたように数十時間で寿命(FLASHの書き込み時間が長くなったり書けなくなる)になるようなことがあっても構わないのならそれで頑張ってください。 ちょっと調べてみるとWear Levellingとかいうフラッシュの寿命を考慮した?ファイルシステムもあるみたいですね。
退会済みユーザー

退会済みユーザー

2020/12/07 15:17

ご回答いただきありがとうございます。 「appendFile(SPIFFS, "/hello.txt",buffer);」を付け足したしたのですが、エラーが出ます。 数日悩み、おそらくセンサー値を配列に変えなければならない?ようで、toCharArrayを使用するのですが、 while ( GPSRi != 42 ) { に invalid conversion from 'int' to 'const char*' [-fpermissive] といったエラーが出ています。 色々いじってしまったため、おかしな点が他にあるのかもしれませんが、現状のプログラムを添付いたします。 可能でしたら、どこを直すべきであるのかご教授いただければ幸いです。 よろしくお願いいたします。 #include "M5Atom.h" //Search $GPGSV for ESP32 DEVKIT V1-DOIT // https://makeradvisor.com/esp32-vs-esp8266/ // https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/ HardwareSerial GPSRaw(2); // ESP32 UART2 GPIO-16 ( RXD2 ) --- GPS TXD static const uint32_t GPSBaud = 9600; //char GPSRc; String GPSRi; String Buffer; char char_array[]={}; #include "FS.h" #include "SPIFFS.h" /* You only need to format SPIFFS the first time you run a test or else use the SPIFFS plugin to create a partition https://github.com/me-no-dev/arduino-esp32fs-plugin */ #define FORMAT_SPIFFS_IF_FAILED true //==================SPIFFS=================================--- void writeFile(fs::FS &fs, const char * path, const char * message){ Serial.printf("Writing file: %s\r\n", path); File file = fs.open(path, FILE_WRITE); if(!file){ Serial.println("- failed to open file for writing"); return; } if(file.print(message)){ Serial.println("- file written"); } else { Serial.println("- write failed"); } file.close(); } void appendFile(fs::FS &fs, const char * path, const char * message){ //Serial.printf("Appending to file: %s\r\n", path); File file = fs.open(path, FILE_APPEND); if(!file){ Serial.println("- failed to open file for appending"); return; } if(file.print(message)){ //Serial.println("- message appended"); } else { Serial.println("- append failed"); } file.close(); } void readFile(fs::FS &fs, const char * path){ Serial.printf("Reading file: %s\r\n", path); File file = fs.open(path); if(!file || file.isDirectory()){ Serial.println("- failed to open file for reading"); return; } Serial.println("- read from file:"); while(file.available()){ Serial.write(file.read()); } file.close(); } void deleteFile(fs::FS &fs, const char * path){ Serial.printf("Deleting file: %s\r\n", path); if(fs.remove(path)){ Serial.println("- file deleted"); } else { Serial.println("- delete failed"); } } //=========================================================================== void setup() { Serial.begin(115200); // GPS TXD-pin should be connected to Lolin32 Pin-16 GPSRaw.begin(GPSBaud, SERIAL_8N1, 23, 19); //====SPIFFS Init============================= if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){ Serial.println("SPIFFS Mount Failed"); return; } writeFile(SPIFFS, "/hello.txt", "sec,rssi,address,devNum\n\r "); //============================================= } void searchZDA(){ char GPSRc = GPSRaw.read(); // read 1 character GPSRi = String(GPSRc); if ( GPSRi == 36 ) { // <= if the 1st character read is '$' Buffer = "$"; while ( GPSRi != 42 ) { char GPSRc = GPSRaw.read(); GPSRi = String(GPSRc); if( GPSRi < 128 ) Buffer += GPSRc; // add one character to the buffer } // if the buffer includes "GPZDA" at the beginning it will be zero // check the first six character of the buffer // Serial.print does not display anything until "$GPGSV" is found if ( Buffer.indexOf("$GPZDA") == 0 ) Serial.println(Buffer); Serial.print("GPSRi="); Serial.println(GPSRi); int GPSRi_len=GPSRi.length()+1; char char_array[GPSRi_len]; dataStr.toCharArray(char_array,GPSRi_len); Serial.print("char_array="); Serial.println(char_array); appendFile(SPIFFS, "/hello.txt" ,char_array); } } void loop() { M5.update(); if (GPSRaw.available()) searchZDA(); if ( M5.Btn.wasPressed() ) { readFile(SPIFFS, "/hello.txt"); } }
thkana

2020/12/08 01:43

> 「appendFile(SPIFFS, "/hello.txt",buffer);」を付け足したしたのですが、エラーが出ます。 appendFile(SPIFFS, "/hello.txt",Buffer.c_str()); でどうでしょう。M5Atomは持っていないので確認はしません。もっと最小のプログラムにして、素のESP32で動くようにしてファイルシステムだけの話に限定するなら動かしてみますけれど。 で。 チェックをしていなかった点は謝りますが、私はあなたのプログラムのデバッグを請け負った覚えはありません。「プログラム書いたからチェックしろ」はないでしょう?
退会済みユーザー

退会済みユーザー

2020/12/08 03:15

申し訳ございません。 初心者でどのように質問して答えを見つけるべきか分からず、このような書き方をしてしまいました。 教えていただいたものを試し、難しい場合は他の方法を考えようと思います。
thkana

2020/12/08 04:38

> 初心者でどのように質問して答えを見つけるべきか分からず 「王道」はありませんが、Arduinoである程度自在にプログラムを作れるようになりたいのなら、少なくともC++の入門書には一通り目を通して下さい。(まぁ、さすがにテンプレートとかはなかなか使いませんが) 今回であれば、ArduinoのString型はC++標準のstd::string型のサブセットであり、c_str()メンバー関数はどちらにもあります。C++の入門書などでstd::stringに一度触れていればc_str()を思い出すこともあったでしょう。 そして、'Arduino String'あたりで検索して(出来るだけ公式から)確認すれば、Stringでもc_str()が使える、なんてことはわかるわけです。 決して無闇矢鱈に試行錯誤ばかりすることはお勧めしません。
退会済みユーザー

退会済みユーザー

2021/01/09 13:37

もう一度勉強しなおし、文字配列にする文などを入れることで解決しました。 ご教授いただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問