もよいめも

不定期更新ものづくりブログ

【M5Stack】SDカード内のCSVファイルを読み出す!

現在鋭意制作中のM5 core2で貸出管理をするシステム、その名も「KASHIDASHI」ですが、
貸出のデータはSDカード内にCSV形式で保存・読み出しをするようにしています。
youtube.com


C言語ならfscanfが使えるので、CSV形式のデータを読み出すのはそこまで大変じゃないでしょうが、
Arduino言語だとそんな便利なものはありません。
そこで今回は、M5Stack(Core2)でArduino言語を使って、CSV形式のデータを要素ごとに読み出す方法についてまとめていこうと思います!

データの形

今回扱うデータの形は以下の通りです。

f:id:moyoi:20220329122404p:plain
データの形

ちなみに、行と列の関係は以下の通りです

0行・列 2列 3列
1行 - -
2行 - -

プログラム

M5 core2用に組みましたが、コアとなる部分は純粋なArduino言語で作りました。

#include "M5Core2.h"

void setup()
{
  M5.begin(); //もろもろ初期化する

  if (!SD.begin()) // SDカードと通信できるか確認
  {
    M5.Lcd.println("no sdcard"); //通信できなければエラーを表示
    while (1)
      ;
  }

  File fp = SD.open("/test.csv", FILE_WRITE); //テスト用のファイルを新規作成する
  fp.println("characters,figures,booleans");  //ヘッダーを入力
  fp.println("abcdef,12345,1");               //値を','で区切って入力
  fp.println("ghijkl,67890,0");
  fp.println("mnopqr,12345,1");
  fp.close(); //ファイルを閉じる

  char characters[100][10]; //要素記憶用の配列を作成
  int figures[100];
  bool booleans[100];
  int row;

  File f = SD.open("/test.csv", FILE_READ);

  String line;          //行を一時的に記憶する変数
  int row_inheader = 0; //ヘッダーも含めた行数を記憶する変数
  while (f.available()) //データが有ればループ
  {
    char ch = f.read(); //データを1byteずつ読み取り
    line += String(ch); // 1byteずつ繋げていく
    if (ch == '\n')     //'\n'が読み込まれた所で一旦読み取りをやめる
    {
      M5.Lcd.print(line); //行全体を画面に表示
      line.trim();        //行に含まれる不要な空白を取り除く

      int column = 0;    //行に含まれる要素番号カウントする変数
      int num_end = 0;   //要素の終わりの列番号を記憶する変数
      int num_start = 0; //要素の始まりの列番号を記憶する変数

      if (0 < row_inheader) //ヘッダーを読み込まないように除外する
      {
        while (num_end != -1) //範囲内に','がなくなるまで繰り返し
        {
          num_end = line.indexOf(',', num_start); // num_strから','がないか確認。あれば列番号をnum_endに記憶
          // M5.Lcd.print('[' + String(num_end) + ']');//正しく認識できているか確認用
          String part = line.substring(num_start, num_end); //','で区切られた要素を行から切り出す
          // M5.Lcd.print('(' + part + ')');//正しく認識できているか確認用
          if (column == 0) //行の最初の要素
          {
            part.toCharArray(characters[row_inheader - 1], num_end + 1 - num_start); //配列の"ヘッダーを除いた行数"番目にデータをchar型に変換して代入
          }
          else if (column == 1) //行の2番目の要素
          {
            figures[row_inheader - 1] = part.toInt(); //配列の"ヘッダーを除いた行数"番目にデータをint型に変換して代入
          }
          else if (column == 2) //行の3番目の要素
          {
            booleans[row_inheader - 1] = boolean(part.toInt()); //配列の"ヘッダーを除いた行数"番目にデータをbool型に変換して代入
          }
          num_start = num_end + 1; //','分で1を足して、次の要素を区切る','を探し始めるスタート地点を代入
          column++;                //要素数に1を加算
        }
      }
      line = "\0";    //変数を初期化
      row_inheader++; //行数に1を加算
    }
    row = row_inheader - 1; //ヘッダーを除いた行数をrowに代入
  }
  f.close();                    //ファイルを閉じる
  M5.Lcd.print('\n');           //改行
  for (int i = 0; i < row; i++) //整理したデータを'/'で区切って表示
  {
    M5.Lcd.println(String(characters[i]) + '/' + String(figures[i]) + '/' + String(booleans[i]));
  }
}

void loop()
{
}

実行結果

f:id:moyoi:20220329123400j:plain
M5 Core2の画面

こんな感じで表示されます。

まとめ

ということで、いい感じに読めました。
ちなみに、最初は以下のようなライブラリーを使用してデータを読んでいたのですが、読んだデータがバグるときがちょこちょこあり、どうせならということで作ってみることにしました。
github.com
データ管理は面倒くさいですね☆
以上、終わり!