前提
Arduino を使って SDカードのデータをコピーしたいと考えてします。
ATmega328にSDカードモジュールを2台並列接続しています。
各モジュールとの通信は正常にできています。
実現したいこと
SDカードモジュール2台を使い、片方のカードにあるデータをもう一方のカードにコピーしたいと考えています。
まず、ディレクトリ構造(ファイル階層)をコピーするスケッチを書いています。
発生している問題・エラーメッセージ
SDカード1にあるデータをコピーします。カード内1つ目のディレクトリの中にあるファイルはSDカード2にコピーできました。
その後、2つ目のディレクトリ内では、ファイルは、階層が少し深くなっています。関数を入れ子にして、ディレクトリを深く掘っていくのですが、ファイルのある階層でファイルを見つけるかと思いきや、ファイルを見つけることができません。ちなみに、このスケッチはスケッチ例の「filelist」を参考にして書きました。
該当のソースコード
Arduino
1/* 2 Listfiles 3 4 This example shows how print out the files in a 5 directory on a SD card 6 7 The circuit: 8 SD card attached to SPI bus as follows: 9 ** MOSI - pin 11 10 ** MISO - pin 12 11 ** CLK - pin 13 12 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN) 13 14 created Nov 2010 15 by David A. Mellis 16 modified 9 Apr 2012 17 by Tom Igoe 18 modified 2 Feb 2014 19 by Scott Fitzgerald 20 21 This example code is in the public domain. 22 23*/ 24#include <SPI.h> 25#include <SD.h> 26#include <LiquidCrystal_I2C.h> // 液晶表示用 27LiquidCrystal_I2C lcd(0x27, 20, 4);// set the LCD address to 0x27 for a 16 28 29const char nameTitle[] = "copyFile"; 30const char nameVer[] = "20221130 working"; 31const char SD1pin = 8; 32const char SD2pin = 9; 33File root; 34String dName; 35 36void setup() { 37 // --------- LCD にツール名称とバージョンを表示 --------- // 38 lcd.init(); // initialize the lcd 39 lcd.backlight(); 40 lcd.setCursor(0,0); 41 lcd.print(nameTitle); // タイトルを表示する 42 lcd.setCursor(0,1); 43 lcd.print(nameVer); // バージョンを表示する 44 delay(2000); 45 lcd.clear(); 46 47 pinMode(SD1pin, OUTPUT); 48 pinMode(SD2pin, OUTPUT); 49 digitalWrite(SD1pin, HIGH); 50 digitalWrite(SD2pin, HIGH); 51 pinMode(10, OUTPUT); // 10pin 以外を用いる場合は、10pin は 52 //digitalWrite(10, HIGH); // output に設定するけど使用しない。 53 54 lcd.setCursor(0,0); 55 lcd.print("Starting"); 56 delay(2000); 57 lcd.clear(); 58 59 60 //Serial.begin(9600); 61 //while (!Serial) { 62 // ; // wait for serial port to connect. Needed for native USB port only 63 //} 64 65 //Serial.print(F("Initializing SD card...")); 66 lcd.setCursor(0,0); 67 lcd.print(F("SD1pin to start")); 68 lcd.setCursor(0,1); 69 lcd.print(F("Initializing SD card...")); 70 delay(2000); 71 72 if (!SD.begin(SD1pin)) { 73 //Serial.println(F("initialization failed!")); 74 lcd.setCursor(0,2); 75 lcd.print(F("initialization failed!")); 76 delay(2000); 77 while (1); 78 }else{ 79 //Serial.println(F("initialization done.")); 80 lcd.setCursor(0,2); 81 lcd.print(F("initialization done.")); 82 delay(2000); 83 } 84 85 root = SD.open("/"); 86 dName = "/"; 87 88 printDirectory(root, dName); 89 90 lcd.clear(); 91 lcd.setCursor(0,2); 92 lcd.print(F("done!")); 93 delay(2000); 94} 95 96void loop() { 97 // nothing happens after setup finishes. 98} 99 100void printDirectory(File& dir, String& dName) { 101 while (true) { 102 File entry = dir.openNextFile(); 103 lcd.setCursor(0,0); 104 lcd.clear(); 105 lcd.print(F("entry is ")); 106 lcd.print(entry.name()); 107 delay(2000); 108 if (!entry) { 109 // no more files 110 // break するとディレクトリ構造を1段上る。それに合わせて、dName も短くする。 111 // dName の最後尾にあるディレクトリ名を削除するために、/ を目印にする。 112 dName = dName.substring(0, dName.lastIndexOf('/', dName.length()-2)+1); 113 lcd.clear(); 114 lcd.setCursor(0, 0); 115 lcd.print(F("before break: ")); 116 delay(2000); 117 lcd.setCursor(0, 1); 118 lcd.print(dName); 119 delay(2000); 120 entry.close(); 121 break; 122 } 123 if (entry.isDirectory()) { 124 // entry がディレクトリなら、ディレクトリをもう1段下る 125 dName = dName + String(entry.name()) + '/'; 126 lcd.clear(); 127 lcd.setCursor(0,0); 128 lcd.print(F("before going to function: ")); 129 delay(2000); 130 lcd.setCursor(0,1); 131 lcd.print(dName); 132 delay(2000); 133 printDirectory(entry, dName); // 下のディレクトリへ入る 134 // 下のディレクトリから戻ってきた直後の dName の値を見る 135 lcd.clear(); 136 lcd.setCursor(0, 0); 137 lcd.print(F("after break: ")); 138 delay(2000); 139 lcd.setCursor(0, 1); 140 lcd.print(dName); 141 delay(2000); 142 } else { 143 // entry がファイルなら、そのディレクトリを作ってファイルも作る 144 String fName = entry.name(); 145 fName = dName + fName; // ファイル名を後ろに追記 146 // entry がファイルであると判断した直後の fName を表示する 147 lcd.clear(); 148 lcd.setCursor(0,0); 149 lcd.print(F("entry is a file.")); 150 delay(2000); 151 lcd.setCursor(0,1); 152 lcd.print(F("fName: ")); 153 lcd.setCursor(0,2); 154 lcd.print(fName); 155 delay(2000); 156 // 書き込むためにSD2との通信を始める 157 lcd.clear(); 158 lcd.setCursor(0,0); 159 lcd.print(F("SD2pin to make")); 160 lcd.setCursor(0,1); 161 lcd.print(F("Initializing SD card...")); 162 delay(2000); 163 if (!SD.begin(SD2pin)) { 164 lcd.setCursor(0,2); 165 lcd.print(F("initialization failed!")); 166 delay(2000); 167 while (1); 168 }else{ 169 //Serial.println(F("initialization done.")); 170 lcd.setCursor(0,2); 171 lcd.print(F("initialization done.")); 172 delay(2000); 173 } 174 175 // 作ろうとしているファイルが存在するか判定 176 const bool fileExst = SD.exists(fName); 177 if(fileExst){ 178 lcd.clear(); 179 lcd.setCursor(0,0); 180 lcd.print(F("file exist.")); 181 lcd.setCursor(0,1); 182 lcd.print(fName); 183 delay(2000); 184 }else{ 185 // ディレクトリを作る 186 bool mydir = SD.mkdir(dName); 187 if(mydir){ 188 lcd.setCursor(0,0); 189 lcd.print(F("mkDir ok.")); 190 lcd.setCursor(0,1); 191 lcd.print(dName); 192 delay(2000); 193 }else{ 194 lcd.setCursor(0,0); 195 lcd.print(F("mkDir false.")); 196 lcd.setCursor(0,1); 197 lcd.print(dName); 198 delay(2000); 199 } 200 // ファイルを作る 201 202 File myfile = SD.open(fName, FILE_WRITE); 203 if( myfile ){ //ファイルが開けたら書き込む 204 myfile.println("push btn:"); 205 myfile.close(); //ファイルを閉じる 206 lcd.setCursor(0,2); 207 lcd.print(F("mkFile ok.")); 208 lcd.setCursor(0,3); 209 lcd.print(fName); 210 delay(2000); 211 }else{ 212 lcd.setCursor(0,2); 213 lcd.print(F("mkFile false.")); 214 lcd.setCursor(0,3); 215 lcd.print(fName); 216 delay(2000); 217 } 218 } // if(fileExst) else 219 220 //SD1 との通信に戻る 221 lcd.clear(); 222 lcd.setCursor(0,0); 223 lcd.print(F("SD1pin to return")); 224 lcd.setCursor(0,1); 225 lcd.print(F("Initializing SD card...")); 226 delay(2000); 227 228 lcd.clear(); 229 if (!SD.begin(SD1pin)) { 230 lcd.setCursor(0,2); 231 lcd.print(F("initialization failed!")); 232 delay(2000); 233 while (1); 234 }else{ 235 //Serial.println(F("initialization done.")); 236 lcd.setCursor(0,2); 237 lcd.print(F("initialization done.")); 238 delay(2000); 239 } 240 } // if (entry.SRisDirectory()) else 241 entry.close(); 242 } 243 return; 244}
試したこと
ディレクトリを掘っていくので、それに合わせてパス追加したり削除したりするString文字列 dName を設けています。関数から関数へ渡します。最初は要領を得ず普通に変数として渡していましたが、うまく動作しませんでした。もしかしたらRAMのメモリを使いすぎなのか?と考えて、関数へ渡すときは参照渡しを使ったり、LCDに表示する文字はF()で括ったりしました。
ネットで調べてみると、ヒープとスタックのせめぎあい?のような情報があるのですが、なかなか理解できておらず、今回のスケッチにおいてその確認はできておりません。
補足情報(FW/ツールのバージョンなど)
ArduinoIDE ver.2.02
あなたの回答
tips
プレビュー