【SDカード入門】M5StackでSD読み書きをやってみた♪

今回もM5StakのSDカードの使い方をすすめました。
これで書き込みした数値データを、数値データとして利用出来るようになります。
前回までで、SDの読み書きは一応出来ていました。
通常は以下の参考・にあげたようなところまでのようです。これでデータをPCなどでは解析できます。
しかし、リアルタイムに処理する場合は不十分です。
つまり前回の段階では、読み込んで書き出しは出来ますが、数値としてではなくCharとして実施していました。
以下の参考①はSDに書き込まれた数値が単独であればずばりです。
しかし、実際には数値列だったりします。
そこで、参考②のように関数化する必要が出てきます。
そして、数値列を読む関数が、参考③にありました。
そこで、これらの参考を合体させてみると無事にM5StackのIMUで読み込んだ、pitich, roll, yaw, temperatureのデータを塊ごとに数値として取り扱うことが出きるようになリました。
今回、これを簡単にまとめようと思います。
【参考】
・[Logging data on MicroSD Cards with Arduino](http://www.manelsoft.com/projects/arduino_microsd_data_logging.aspx)
①[任意の浮動小数点数を文字列に変換、逆変換して元に戻せるか](https://teratail.com/questions/22355)
②[【C言語】文字列を数値に変換する方法（atoi・strtol など）](https://daeudaeu.com/strto/)
③[Loading Data from SD Card & Sending via Bluetooth to Android](https://forum.arduino.cc/t/loading-data-from-sd-card-sending-via-bluetooth-to-android/449972)
###コード解説
コード全体は、おまけに記載しました。
主要な部分のコード解説します。
####Sampling
計測は、今までと同様な関数sampling()で実施します。
※setup()で`myFile = SD.open("/temp.txt", FILE_WRITE);`しています。
１０回計測し、save_temp()関数で書き込みします。

```c
void setup() {
  M5.begin();
  M5.IMU.Init();
　。。。
  myFile = SD.open("/temp.txt", FILE_WRITE); 
  sampling();
  output2();
  Serial.print("Finished");
}


void sampling() {
  for(int i=0; i <10; i++) {
      M5.IMU.getAhrsData(&pitch,&roll,&yaw);
      M5.IMU.getTempData(&temp);
      
      M5.Lcd.printf(" %5.2f   %5.2f   %5.2f  %5.2f \n", pitch, roll, yaw, temp);
      Serial.printf(" %5.2f   %5.2f   %5.2f  %5.2f \n ", pitch, roll, yaw, temp);
      save_temp();
      delay(100);
    }
  }
  myFile.close();
}
```
####save_temp
書き込みも以下のとおり簡単です。
※ここで書式を決めて書き込んでいることが割と重要です

```c
void save_temp(){
  if (myFile) {
    myFile.printf("%5.2f, %5.2f, %5.2f, %5.2f \n", pitch, roll, yaw,temp);
  } else {
    Serial.println("error opening temp.txt");
  }
}
```
####output
ながれは一緒なので、まず読み出して簡単な表示から。
`myFile = SD.open("/temp.txt");`して、あとは
`Serial.write(myFile.read());`でSerialモニターに出力できます。
しかし、これはcharを出力しているだけで、数値として使えません。

```c
void output(){
  myFile = SD.open("/temp.txt");  //add "/"
  delay(1);
  if (myFile) {
    Serial.println("temp.txt:");
    M5.Lcd.println("temp.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
      delay(10);
    }
  }
  // close the file:
  myFile.close();
}
```
####output2
散々悩んで以下のコードにまとめました。
ほぼ参考③を踏襲ですが、char配列readingを関数conv_str2d(reading);で変換しています。
関数書式が分からなかったので、取得した数値配列をglobal変数としました。
一度、変換してしまえば、M5Stackのディスプレイにも綺麗に表示できました。

```c
double num_[4];

void output2(){
  // re-open the file for reading:
  myFile = SD.open("/temp.txt");
  if (myFile) {
    Serial.println("temp.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      char reading[30] = "";
      char temp = myFile.read();
      int idx = 0;
      bool somethingWasRead = false;
      while (temp != -1 && temp != 13 && temp != 10){
        reading[idx] = temp;
        temp = myFile.read();
        idx++;
        somethingWasRead = true;
      }
      reading[idx++]='\0';
      //reading[idx] = 10;
      if (somethingWasRead){
       Serial.println(reading);
       delayMicroseconds(500);
      }
      conv_str2d(reading);
      Serial.printf("pitch %5.2f roll %5.2f yaw %5.2f temp %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
      M5.Lcd.printf(" %5.2f %5.2f %5.2f %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
     }
。。。
}
```
####conv_str2d関数
問題の変換関数は以下のようにべたに記載しています。
※一行にまとめられますが、わかりやすいので展開して表示しています。

```c
void conv_str2d(char reading[30]){
  char a[6];
  a[0]=reading[0];a[1]=reading[1];a[2]=reading[2];a[3]=reading[3];a[4]=reading[4];a[5]=reading[5];
  num_[0] = strtod(a, NULL);
  char b[6];
  b[0]=reading[7];b[1]=reading[8];b[2]=reading[9];b[3]=reading[10];b[4]=reading[11];b[5]=reading[12];
  num_[1] = strtod(b, NULL);
  char c[6];
  c[0]=reading[14];c[1]=reading[15];c[2]=reading[16];c[3]=reading[17];c[4]=reading[18];c[5]=reading[19];
  num_[2] = strtod(c, NULL);
  char d[6];
  d[0]=reading[21];d[1]=reading[22];d[2]=reading[23];d[3]=reading[24];d[4]=reading[25];d[5]=reading[26];
  num_[3] = strtod(d, NULL);
}
```
###結果
よくできした！

```
Initializing SD card...initialization done.
  0.45   -0.05   -8.32  51.09 
   0.94   -0.14   -8.13  51.24 
   1.33   -0.21   -7.97  50.97 
   1.70   -0.25   -7.81  52.29 
   2.07   -0.31   -7.63  50.99 
   2.46   -0.36   -7.46  48.03 
   2.86   -0.43   -7.28  51.89 
   3.14   -0.43   -7.12  49.99 
   3.48   -0.46   -6.93  50.76 
   3.80   -0.49   -6.77  50.26 
 temp.txt:
 0.45, -0.05, -8.32, 51.09 
pitch  0.45 roll -0.05 yaw -8.32 temp 51.09 
 0.94, -0.14, -8.13, 51.24 
pitch  0.94 roll -0.14 yaw -8.13 temp 51.24 
 1.33, -0.21, -7.97, 50.97 
pitch  1.33 roll -0.21 yaw -7.97 temp 50.97 
 1.70, -0.25, -7.81, 52.29 
pitch  1.70 roll -0.25 yaw -7.81 temp 52.29 
 2.07, -0.31, -7.63, 50.99 
pitch  2.07 roll -0.31 yaw -7.63 temp 50.99 
 2.46, -0.36, -7.46, 48.03 
pitch  2.46 roll -0.36 yaw -7.46 temp 48.03 
 2.86, -0.43, -7.28, 51.89 
pitch  2.86 roll -0.43 yaw -7.28 temp 51.89 
 3.14, -0.43, -7.12, 49.99 
pitch  3.14 roll -0.43 yaw -7.12 temp 49.99 
 3.48, -0.46, -6.93, 50.76 
pitch  3.48 roll -0.46 yaw -6.93 temp 50.76 
 3.80, -0.49, -6.77, 50.26 
pitch  3.80 roll -0.49 yaw -6.77 temp 50.26 
Finished
```
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">押すだけ🎵<br><br>SD入出力出来ました‼️<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://t.co/26J0K675i8">pic.twitter.com/26J0K675i8</a></p>&mdash; ウワン (@MuAuan) <a href="https://twitter.com/MuAuan/status/1417736594715332612?ref_src=twsrc%5Etfw">July 21, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
###まとめ
・M5StackでSD書き込み読込みが出きるようになった

・数値データを描画したいと思う

###おまけ
```c
#include <SPI.h>
#include <SD.h>
//#define M5STACK_MPU6886 
//#include <M5Stack.h>
#include <M5Core2.h> //core2


float pitch = 0.0F;
float roll  = 0.0F;
float yaw   = 0.0F;
float temp = 0.0F;
int start;
File myFile;

void setup() {
  // Open serial communications and wait for port to open:
  //Serial.begin(115200);
  M5.begin();
  M5.IMU.Init();

  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(GREEN , BLACK);
  M5.Lcd.setTextSize(2);
  start = micros();
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  myFile = SD.open("/temp.txt", FILE_WRITE);  //add "/"
  sampling();
  output2();
  Serial.print("Finished");
}

double num_[4];

void save_temp(){
  if (myFile) {
    myFile.printf("%5.2f, %5.2f, %5.2f, %5.2f \n", pitch, roll, yaw,temp);
  } else {
    Serial.println("error opening temp.txt");
  }
}

void sampling() {
  for(int i=0; i <10; i++) {
    M5.update(); // need to call update()
    M5.Lcd.setCursor(0, 0);
    if (M5.BtnB.isPressed()) {
      M5.Lcd.printf("B button is pressed.");
    } else {
      M5.Lcd.printf("B button is released.");
    }
    if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000, 200)) {
      Serial.println("Stop the measure");
      break;     
    }else{
      M5.IMU.getAhrsData(&pitch,&roll,&yaw);
      M5.IMU.getTempData(&temp);
      
      M5.Lcd.printf(" %5.2f   %5.2f   %5.2f  %5.2f \n", pitch, roll, yaw, temp);
      Serial.printf(" %5.2f   %5.2f   %5.2f  %5.2f \n ", pitch, roll, yaw, temp);
      save_temp();
      delay(100);
    }
  }
  myFile.close();
}

void output2(){
  // re-open the file for reading:
  myFile = SD.open("/temp.txt");
  if (myFile) {
    Serial.println("temp.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      char reading[30] = "";
      char temp = myFile.read();
      int idx = 0;
      bool somethingWasRead = false;
      while (temp != -1 && temp != 13 && temp != 10){
        reading[idx] = temp;
        temp = myFile.read();
        idx++;
        somethingWasRead = true;
      }
      reading[idx++]='\0';
      //reading[idx] = 10;
      if (somethingWasRead){
       Serial.println(reading);
       delayMicroseconds(500);
      }
      conv_str2d(reading);
      Serial.printf("pitch %5.2f roll %5.2f yaw %5.2f temp %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
      M5.Lcd.printf(" %5.2f %5.2f %5.2f %5.2f \n",num_[0],num_[1],num_[2],num_[3]);
     }
    
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening temp.txt");
  }
}

void conv_str2d(char reading[30]){
  char a[6];
  a[0]=reading[0];a[1]=reading[1];a[2]=reading[2];a[3]=reading[3];a[4]=reading[4];a[5]=reading[5];
  num_[0] = strtod(a, NULL);
  char b[6];
  b[0]=reading[7];b[1]=reading[8];b[2]=reading[9];b[3]=reading[10];b[4]=reading[11];b[5]=reading[12];
  num_[1] = strtod(b, NULL);
  char c[6];
  c[0]=reading[14];c[1]=reading[15];c[2]=reading[16];c[3]=reading[17];c[4]=reading[18];c[5]=reading[19];
  num_[2] = strtod(c, NULL);
  char d[6];
  d[0]=reading[21];d[1]=reading[22];d[2]=reading[23];d[3]=reading[24];d[4]=reading[25];d[5]=reading[26];
  num_[3] = strtod(d, NULL);
}

void output(){
  myFile = SD.open("/temp.txt");  //add "/"
  delay(1);
  if (myFile) {
    Serial.println("temp.txt:");
    M5.Lcd.println("temp.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
      delay(10);
    }
  }
  // close the file:
  myFile.close();
}

void loop(){
  //nothing
}
```