質問: 0; j < 50; j++) { Serial.print(c_buf[j]); Serial.print('\t'); Serial.println(t_buf[j]); } } void loop() { //何もしない } ``` ### 実行結果(シリアルモニター) 1 19468 513 2816 1025 2516 1537 2520 2049 2516 -----省略----- 23553 2536 24065 2532 24577 2548 25089 2544 ### 補足情報 ・Arduino Uno R3 ・Seeed Studio CAN-BUSシールドV2 ・SAMSUNG microSD HC 32GB ### 今後やりたいこと 400us間隔で受信するCAN信号のログ保存を考えています。ログデータは1信号辺り21byteです。質問にある書き込み遅延の影響でログの取得漏れが起こっています。ログ保存の方法は文字型配列(buf)にデータを入れてからまとめてfile.print(buf);する方法で行います。
回答: thkanaさんの回答でだいたいあっていると思いますが少々補足で。 SD(HC/XC含む)カードは、512バイトが読み書きの最小単位です。(初期には1バイト単位のものもあったようだが) これはFlashメモリの構造とは関係なく、Flashのブロックが数KBであっても内部でバッファして512バイト単位での読み書きを実現します。 ArduinoのSDライブラリが512バイト単位で実際の読み書きをするのはそのためです。 SDの読み書き自体は初期化時以外はいつでも中断してよいので、 2つのバッファを交互に使い、書くべき値を作る処理はタイマー割り込みで行い、メインでは512バイト溜まったらSDに書き出すという形でたぶんできると思います。 ArduinoのSDライブラリでは割り込みは使っていませんので、ライブラリ自体を書き換えなくてもいけるはずです。 気になったので試してみました。 割り込みを利用してのバックグラウンドでの書き込み自体はどうやら成功しました。 ・400us間隔のタイマー割り込みでバッファに値を溜める ・メインのコードでは「バッファを切り替え、書き込んでいない側のバッファをSDに書き出す」を繰り返す という処理で、SDには値が400us間隔で生成されているような書き込みがなされました。 (なお考えてみれば512バイト待つ必要も無かったのと容量を食うのでバッファは256バイトにした) ただ、プログラムの挙動は異常で、setup()がループしてしまっています。どこかで割り込みが使われていて干渉しているのかもしれません(SDライブラリ内か、あるいはSerialか、microsも怪しい)。あるいは何かつまらないミスがあるかもしれません。 とりあえず思っていた処理はできそうだと分かったので私は満足です。 ``` #include #include const byte SD_SS = 4; String fname = "SDwrite.txt"; File file; unsigned long time_last = 0; unsigned long time_now = 0; byte buf[2][256] = {0}; int count[2] = {0}; byte phase = 0; int i = 0; ISR(TIMER2_COMPA_vect) { time_now = micros(); i++; unsigned long time_diff = time_now-time_last; buf[phase][count[phase] ] = time_diff&0xFF; buf[phase][count[phase]+1] = (time_diff>> 8)&0xFF; buf[phase][count[phase]+2] = (time_diff>>16)&0xFF; buf[phase][count[phase]+3] = i&0xFF; count[phase]+=4; time_last = time_now; } void setup() { TCCR2A = 0b10000010; TCCR2B = 0b00000011; // clk/32 OCR2A = 199; // 400usで割り込み TIMSK2 = 0b00000010; Serial.begin(57600); unsigned long temp = 0L; if (!SD.begin(SD_SS)) { Serial.println("SD_FAIL"); return; } Serial.println("start"); file = SD.open(fname, FILE_WRITE); //ファイル新規作成、書き込みモード sei(); byte buf_x[100] = {0}; int num = 100; while (true) { if(micros() > 5000000L) { break; } phase ^= 1; temp += count[phase^1]; if(count[phase^1] != 0) { file.write(buf[phase^1], count[phase^1]); count[phase^1] = 0; } } file.close(); Serial.println("close"); Serial.println(i); Serial.println(temp); } void loop() { //何もしない } ``` 追記: 割り込みとSD出力の参考にしたページです。あとデータシートも。