こんにちは、Reveです。
このところtwitterでのつぶやき連携ばかりだったのですが、今日はちゃんとブログ記事を書こうかと思い、
久々のArduinoネタでつらつらと書いていきます。
(仕事しててちょうどネタが見つかったので)
【ArduinoとSDカード】
このブログをご覧いただいている皆様はおおよそ承知かと思いますが、
Arduinoというのは電子回路の試作開発などに大変便利なマイコンボードで、世界で最も普及しているプロトタイピングツールといっても過言ではないでしょう。
そんなArduinoはSDカードの読み書きも標準のライブラリから可能で、まさに至れり尽くせりなツールなのですが、
今日はSDカードの読み込みで、特定のファイルの名前だけを一覧で取り出す方法を記事にしたいと思います。
【ファイル名の一覧を作成】
ArduinoのSDカード用ライブラリではファイル名の取得も当然できるのですが、
例えばSDカード内にあるファイルを一定時間ごとにランダムで開きたい時などは、わざわざ毎回SDカードにアクセスして調べると処理が重くなる可能性もあります。
かといって、事前にファイル名をArduinoのプログラム側に書いておくのも実装は楽ですが、頻繁にファイルを入れ替える場合は毎回わざわざ書き換えるのも面倒です。
そこで、SDカードに入っているファイルをいったん調べ、そのファイル名を配列のようにリスト化してしまえば動的に処理できるし、アクセス速度や負荷の心配もまずありません。
【実装手法とサンプル】
早速、サンプルを見てみましょう。
ここではルートフォルダ、つまりSDカードの一番上のフォルダにあるファイルをすべて読み込む処理になっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
; title="SDfilelist"] //SDカードライブラリの読み込み #include <SD.h> //SDライブラリで、SPI通信のライブラリも使うので、一緒に読み込む #include <SPI.h> //ファイル名を記憶しておくリスト変数 char** nameList; //リスト内に含まれるファイル数 int numList; void setup(){ //シリアル通信の設定 Serial.begin(9600); while(!Serial){ //シリアル通信が準備できるまでの待機。Leonardoなどでのみ必須 } //SDカードの読み込み if(!SD.begin(4)){ //4番ピンをアクセス制御ピンとして使う //SDカードの初期読み込みができない場合はエラー Serial.println("initialization failed!"); return; } //内部のファイルにアクセス File root = SD.open("/"); //SDカードのルートフォルダ String listTemp = ""; while (true) { File entry = root.openNextFile(); if (!entry) { //これ以上ファイルがない場合 break; } //ディレクトリ名ではない場合 if (!entry.isDirectory()) { String fileName = entry.name(); listTemp += String(fileName); listTemp += ","; /* //特定の種類のファイルだけを選び出すことも可能(ここでは音楽ファイルを抽出) //ファイルの拡張子を取り出す //一番後ろのピリオドから後の文字を抽出 String ext = fileName.substring(fileName.lastIndexOf('.')); //拡張子が指定のものだけを入れていく if (ext.equalsIgnoreCase(".wav") || ext.equalsIgnoreCase(".mp3")) { //大文字か小文字かを無視する listTemp += String(fileName); listTemp += ","; } */ } else{ //ディレクトリ内部を 検索する場合は、再起関数として同じ処理を呼び出す } } if (listTemp.length() > 0) { //Serial.println(listTemp); //リストの要素数を数え上げる for (int i = 0; i < listTemp.length(); i++) { i = listTemp.indexOf(',', i); //コンマの位置を探す numList++; } //リストの初期化 nameList = new char*[numList]; for (int i = 0; i < numList; i++) { //カンマの位置を見つけ、 int index = listTemp.indexOf(','); String temp = String(listTemp.substring(0, index)); nameList[i] = new char[temp.length() + 1]; temp.toCharArray(nameList[i], temp.length() + 1); Serial.println(nameList[i]); listTemp.remove(0, index + 1); } Serial.println(numList); } else { //ファイルが見つからなかった場合は強制終了 return; } } void loop(){ //リストを利用する } |
今回のポイントは主に2つ。
1) ライブラリSDのFileクラスによるフォルダ検索とファイル名取得
2) ポインタのポインタによる文字列のリストの動的生成
これらを順番に見ていきましょう。
1) ライブラリSDのFileクラスによるフォルダ検索とファイル名取得
SDカードのライブラリでは、Fileクラスというものでファイル情報を管理します。
参照する親元を指定した後は、中のファイル情報を順番にFileクラスで取得していく流れになっています。
順序としては、以下のようになっています。
(a) SDカードの初期化: SD.begin(4);
(b) 参照するフォルダ(ルートフォルダ)を指定: File root = SD.open(“/”);
(c) フォルダ内のファイル名を順番に見ていく: File entry = root.openNextFile();
(d) ファイルがディレクトリでなければ、ファイル名を取得: if(!entry.isDirectory()){String filename = entry.name();}
なお、SDカードとArduinoのつなぎ方についてはこちらのリンク先を参照。
http://arms22.blog91.fc2.com/blog-entry-502.html
2) ポインタによる文字列のリストの動的生成
Arduinoは基本的にC++ベースですが、動的配列のテンプレートライブラリであるvector等は入っていないため、可変長の配列を実現するにはポインタなどのメモリ操作が必要になってきます。
ここでの処理は以下のようになります。
(a) グローバル変数として配列(ポインタ)を確保: char** nameList;
(b) ファイルの数をもとに配列の初期化: nameList = new char*[numList];
(c) 配列の中にそれぞれ値をコピーしていく
値のコピーについては色々と手法がありますが、今回はファイル名をStringクラスで取得しているため、toCharArrayメソッドで配列の要素へと値を入れています。
ちなみに、今回は文字列配列のため、要素それぞれの長さが別々になっています。
(C#でいうところのジャグ配列に近いイメージ)。
そのため、要素数を配列から直接求めるのは難しいので、要素数は別の変数で記憶しておきましょう。
と、このような形でファイル名のリストが作れるので、メインの処理などでファイルを参照するときにこのリストでファイル名を取得して操作するということが可能になります。
ぜひ試してみてください。
今回のプログラムでは、(業務の関係で)ファイル名をchar配列で取得していますが、Stringとして記憶しておくことも可能です。
その際はグローバル変数をStringのポインタに置き換え、String配列として初期化して処理すれば良いのですが、具体的に記述していくのも面倒なのでw、あえて課題としておきます。
SDカードのファイル名自体はStringとして取得しているため、配列には直接代入するだけでコピーできる分、むしろchar配列より実装は楽になります。
なお、Stringとchar配列と二つの場合で使用するメモリの容量を比べてみたのですが、メモリの使用量は、char配列で最初に確保するメモリをいくら小さくしてもStringの場合とほぼ同じでした。
どうしてもchar配列でなければいけない理由がなければ、Stringのポインタを利用するほうが良いでしょう
(が、実装は考えてみてね(・∀・))
コメント