【M5Stack入門】SD入出力と画像入力、そしてアニメーションで遊んでみた♪

M5Stack　Core2でなかなか出来なかったSDファイル入出力が出来たのでまとめておく。
副産物として、Gifアニメーション的な画像のペラペラ動画をやってみます。

###SDファイル取得
このコードはスケッチのまんま動きました。
しかし、この出力に以下のファイル入出力のヒントが書かれていました。
以下は、気象衛星画像を取り込んだSDです。
これは、ファイル名の前に”/”がついています。
また、他の画像表示用のSDも以下のように"/"がついています。

```出力例
/System Volume Information/
	/System Volume Information/WPSettings.dat		12
	/System Volume Information/IndexerVolumeGuid		76
/datalog.txt.txt		0
/jpn_trm_20210715061000.jpg		147774
/jpn_trm_20210715062000.jpg		148171
/jpn_b13_20210715062000.jpg		180546
/jpn_snd_20210715062000.jpg		230045
/jpn_trm_20210715063000.jpg		148581
/jpn_snd_20210715063000.jpg		227143
/jpn_trm_20210715091000.jpg		102250
/jpn_trm_20210715092000.jpg		95142
done!
。。。
/System Volume Information/
	/System Volume Information/WPSettings.dat		12
	/System Volume Information/IndexerVolumeGuid		76
/1.JPG		3589
/2.JPG		3140
done!

```

<details><summary>サンプルコード</summary><div>

```c
/*
  Listfiles

  This example shows how print out the files in a
  directory on a SD card

  The circuit:
   SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

  created   Nov 2010
  by David A. Mellis
  modified 9 Apr 2012
  by Tom Igoe
  modified 2 Feb 2014
  by Scott Fitzgerald

  This example code is in the public domain.

*/
#include <SPI.h>
#include <SD.h>

File root;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  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.");

  root = SD.open("/");

  printDirectory(root, 0);

  Serial.println("done!");
}

void loop() {
  // nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

```

</div></details>
###SDファイル入出力
以下のコードでファイルの読み書きが出来ました。
ここで、上記の"/"が役にたちました。
サンプルスケッチとからの変更点はそれだけです。
※一応、作者のコメントを記載しています

<details><summary>サンプルコード</summary><div>

```c
/*
  SD card read/write

  This example shows how to read and write data to and from an SD card file
  The circuit:
   SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

  created   Nov 2010
  by David A. Mellis
  modified 9 Apr 2012
  by Tom Igoe

  This example code is in the public domain.

*/

#include <SPI.h>
#include <SD.h>

File myFile;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  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.");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("/test.txt", FILE_WRITE);  //add "/"
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

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

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

void loop() {
  // nothing happens after setup
}
```

</div></details>
結果は以下のとおりです。

```ファイル入出力.
Initializing SD card...initialization done.
Writing to test.txt...done.
test.txt:
testing 1, 2, 3.
```

###画像入力
このコードはload-jpeg-coreのサンプルです(入手先を失念)。
しかし、オリジナルは上と同様"/"が無いので動きませんが、追加で動きます。

<details><summary>サンプルコード</summary><div>

```c
//#include <M5Stack.h>
#include <M5Core2.h>
#define PROGRESS_MAX 100

static unsigned char gucProgress = 0;
static unsigned char gucOpenFlg = 0;

void setup() {

  // M5Stackの初期化
  M5.begin();

  // テキストサイズ指定
  M5.Lcd.setTextSize(2);
  // OK
  M5.Lcd.setCursor(60, 80);
  M5.Lcd.printf("Now Loading...");
}

void loop() {
  gucOpenFlg = 0;
  // プログレスが100%まで表示を行う
  if( PROGRESS_MAX >= (gucProgress * 20) )
  {
    // プログレスバー表示完了
    M5.Lcd.progressBar(60, 110, 200, 20,(20 * gucProgress));
    gucProgress++;
  }
  else
  {
    //　ロゴ未表示
    if( 0 == gucOpenFlg)
    {
      // m5stackロゴ表示
      M5.Lcd.printf("Now drawing...");
      M5.Lcd.drawJpgFile(SD,"/1.jpg");
      M5.Lcd.printf("Finished...");
      //　ロゴ表示
      gucOpenFlg = 1;
    }
  }
  delay(1000);

  }
}
```
</div></details>
###複数画像
上記を改変すると以下のように簡単に複数画像の表示が出来ます。

<details><summary>サンプルコード</summary><div>

```c
//#include <M5Stack.h>
#include <M5Core2.h>
#define PROGRESS_MAX 100

static unsigned char gucProgress = 0;
static unsigned char gucOpenFlg = 0;

void setup() {

  // M5Stackの初期化
  M5.begin();

  // テキストサイズ指定
  M5.Lcd.setTextSize(2);
  // OK
  M5.Lcd.setCursor(60, 80);
  M5.Lcd.printf("Now Loading...");
}
int sk=0;
void loop() {
  gucOpenFlg = 0;
  // プログレスが100%まで表示を行う
  if( PROGRESS_MAX >= (gucProgress * 20) )
  {
    // プログレスバー表示完了
    M5.Lcd.progressBar(60, 110, 200, 20,(20 * gucProgress));
    gucProgress++;
  }
  else
  {
    //　ロゴ未表示
    if( 0 == gucOpenFlg)
    {
      // m5stackロゴ表示
      //M5.Lcd.printf("Now drawing...");
      if(sk%2>0){
        M5.Lcd.drawJpgFile(SD,"/1.jpg"); //"/jpn_trm_20210715061000.jpg"); //"/1.jpg");
      }else{
        M5.Lcd.drawJpgFile(SD,"/2.jpg"); //"/jpn_trm_20210715061000.jpg"); //"/1.jpg");
      }
      //M5.Lcd.printf("Finished...");
      //　ロゴ表示
      gucOpenFlg = 1;
    }
  }
  sk += 1;
  delay(int(1000/sk));
  if(sk>1000){
    sk = 0;
  }
}
```
</div></details>

結果は、以下の感じです。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">SDカード利用したペラペラ動画が出来ました‼️<br><br>今は画像二枚ですが、高速に動くので使えそうです<br><br>qiitaに本日まとめる予定です<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://twitter.com/hashtag/Core2?src=hash&amp;ref_src=twsrc%5Etfw">#Core2</a> <a href="https://t.co/PsvzeVVE09">pic.twitter.com/PsvzeVVE09</a></p>&mdash; ウワン (@MuAuan) <a href="https://twitter.com/MuAuan/status/1416916053964165120?ref_src=twsrc%5Etfw">July 19, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

###SD読込みアニメーション
上のコードはこのままではファイル名が単純な整数配列であっても単純な繰り返しを記述しないといけない。
Pythonでは、.formatが利用できてすぐに表現出来たが、C言語では簡単ではなさそう。
しかし、少し探してみると参考が見つかりました。
おかげでコードもシンプルになりました。
参考
[【C言語入門】文字列の連結・分割(strcat、strtok)](https://www.sejuku.net/blog/25878)

これを利用して以下でうまく出来ました。

<details><summary>サンプルコード</summary><div>

```c
//#include <M5Stack.h>
#include <M5Core2.h>
#define PROGRESS_MAX 100

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

static unsigned char gucProgress = 0;
static unsigned char gucOpenFlg = 0;
char *arr3[10] = {"0", "1","2","3","4","5","6","7","8","9"};
char *arr2=".jpg";// png
char str3[30];

void setup() {
  // M5Stackの初期化
  M5.begin();
  // テキストサイズ指定
  M5.Lcd.setTextSize(2);
  // OK
  M5.Lcd.setCursor(60, 80);
  M5.Lcd.printf("Now Loading...");
  printf("\n");
  
}
int sk=0;
void loop() {
  gucOpenFlg = 0;
  // プログレスが100%まで表示を行う
  if( PROGRESS_MAX >= (gucProgress * 20) )
  {
    // プログレスバー表示完了
    M5.Lcd.progressBar(60, 110, 200, 20,(20 * gucProgress));
    gucProgress++;
  }
  else
  {
    //　ロゴ未表示
    if( 0 == gucOpenFlg)
    {
      sprintf(str3, "/%s%s", arr3[sk%2], arr2);
      M5.Lcd.drawJpgFile(SD,str3); // M5.Lcd.drawPngFile(SD,str3); 
      gucOpenFlg = 1;
    }
  }
  sk += 1;
  delay(1);
}
```

</div></details>
<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">一応、動画と云えるかな🎵<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> SD読込み動画 <a href="https://t.co/pWqgq3u0Qd">pic.twitter.com/pWqgq3u0Qd</a></p>&mdash; ウワン (@MuAuan) <a href="https://twitter.com/MuAuan/status/1416954792174227457?ref_src=twsrc%5Etfw">July 19, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

表示の参考は、以下にありますが、引数がうまくいきませんでした。
[LCD@Core2](https://docs.m5stack.com/en/api/lcd)

###まとめ
・SD読み書きが出きるようになった
・SDの画像ファイルを読み込めるようになった
・ペラペラ動画をやってみた

・これとESPnow（近日まとめます）を合わせると、Stack兄弟の動作連携が出来る予定