ArduinoでSDカードにCSV保存する|配線とコードでデータロガーを作る
センサーの値をずっと記録し続けたいとき、シリアルモニタだけでは力不足です。パソコンとの接続を切った瞬間に、データが失われてしまうからです。本記事では、SDカードモジュールを使って、センサー値をCSVファイルとして保存する方法を解説します。配線の基本からコードの書き方まで、計測・研究用途を想定して順を追って紹介します。
01なぜSDカードにログを残すのか

シリアルモニタの限界
これまでの記事では、シリアルモニタを使ってきました。センサーの値を表示して確認する方法です。この方法は、動作確認には便利です。ただし、弱点もあります。シリアルモニタは、パソコンとArduinoをUSBケーブルでつないでいる間しか使えません。ウィンドウを閉じると、それまでの表示内容は失われます。長時間のデータを記録し、あとからじっくり分析したい場合には、この方式は不向きです。
SDカードなら電源が入っている間ずっと記録できる
SDカードモジュールを使うと、状況が変わります。パソコンとの接続を切っても構いません。Arduinoに電源さえ入っていれば、記録を続けられるのです。屋外での長時間計測や、パソコンから離れた場所での実験にも対応できます。記録したファイルは、あとでパソコンに挿してExcelなどで開いて分析できます。
理学療法士のIさんは、MPU6050で歩行時の動きを記録する試みをしていた。最初はシリアルモニタで値を確認するだけだった。しかし、ある制約に気づいた。パソコンにつないだ状態でしか歩けなかったのだ。SDカードにCSV保存する方法を取り入れると、状況は変わった。パソコンから離れて自由に歩きながらデータを記録できるようになった。用途に応じて記録方法を選ぶことが、研究の幅を広げます。
02基礎知識|SPI通信とCSVファイル形式

SDカードモジュールの通信方式
SDカードモジュールは、SPIという通信方式でArduinoとやり取りします。RC522のRFIDモジュールと同じ方式です。Arduino公式のSDガイドを確認してみましょう。SCK・MOSI・MISOという3本の信号線があります。これらは、ハードウェアSPIピン(多くのボードで13・11・12番)に固定されています。もう1本、カードを選択するためのCSピンが必要です。
CSVとは何か
CSVは「Comma-Separated Values」の略です。データをカンマで区切って並べる、シンプルなテキスト形式です。例えば「12:00:00,25.3,512」のように書きます。この形式のファイルには利点があります。Excelなどの表計算ソフトでそのまま開けるのです。開くと、自動的に列に分かれて表示されます。研究や分析の場面で扱いやすい、定番のデータ形式です。
03配線方法:Arduino UnoとSDカードモジュール

配線手順
SDカードモジュールには、複数のピンがあります。CS・MOSI・MISO・SCK・VCC・GNDです。Arduino Unoの場合、CSはD10に、MOSIはD11につなぎます。MISOはD12に、SCKはD13につなぎます。多くの市販モジュールには電圧レギュレータが搭載されています。そのため、VCCはArduinoの5Vに、GNDはArduinoのGNDにつなげば動作します。
SDカードのフォーマットに関する注意
配線の前に、確認しておきたいことがあります。SDカード自体のフォーマット形式です。Arduinoの標準SDライブラリが対応しているのは、FAT16またはFAT32のみです。32GBを超えるカードには注意が必要です。多くの場合、購入時exFATでフォーマットされています。この場合、パソコンで事前にFAT32へ再フォーマットしておく必要があります。
04基本のコード|ファイルを作成して書き込む
SD.begin()での初期化
SDライブラリはArduino IDEに標準搭載されています。追加のインストールは不要です。SD.begin()にCSピンの番号を渡してみましょう。SDカードが正しく認識できているか確認できます。初期化に失敗する場合は、フォーマット形式や配線を見直してください。
ファイルへの書き込みコード
// SDカードにファイルを作成して書き込む最小構成コード
#include <SPI.h>
#include <SD.h>
const int chipSelect = 10;
void setup() {
Serial.begin(9600);
Serial.print("SDカードを初期化しています...");
if (!SD.begin(chipSelect)) {
Serial.println("初期化に失敗しました");
while (1); // 失敗した場合はここで停止
}
Serial.println("初期化に成功しました");
File dataFile = SD.open("TEST.TXT", FILE_WRITE);
if (dataFile) {
dataFile.println("Hello, SD card!");
dataFile.close(); // 必ずcloseする
Serial.println("書き込みが完了しました");
} else {
Serial.println("ファイルを開けませんでした");
}
}
void loop() {
// 何もしない
}
close()を忘れてはいけない理由
このコードには重要な点があります。dataFile.close()を必ず呼び出すことです。書き込んだデータは、いったんメモリ上のバッファに蓄えられます。close()を呼ぶまで、SDカードには確定して保存されません。これを忘れると、書き込んだはずのデータが失われることがあります。
05センサー値をCSV形式で記録する
ヘッダー行を書き込む
CSVファイルの1行目には、工夫を加えておくと便利です。各列が何のデータかを示す「ヘッダー行」を入れておくのです。あとでファイルを開いたときに、内容がひと目で分かります。ファイルがまだ存在しない場合にだけヘッダーを書き込む、という処理にしてみましょう。
センサー値の記録コード
// 可変抵抗の値をCSV形式で記録するコード
#include <SPI.h>
#include <SD.h>
const int chipSelect = 10;
const int potPin = A0;
void setup() {
Serial.begin(9600);
if (!SD.begin(chipSelect)) {
Serial.println("SDカードの初期化に失敗しました");
while (1);
}
// ファイルがまだなければヘッダー行を書き込む
if (!SD.exists("DATA.CSV")) {
File dataFile = SD.open("DATA.CSV", FILE_WRITE);
if (dataFile) {
dataFile.println("time_ms,pot_value");
dataFile.close();
}
}
}
void loop() {
int value = analogRead(potPin);
File dataFile = SD.open("DATA.CSV", FILE_WRITE);
if (dataFile) {
dataFile.print(millis());
dataFile.print(",");
dataFile.println(value);
dataFile.close();
}
delay(500);
}
カンマ区切りがCSVのポイント
カンマ(,)で値を区切りながら書き込むのが、CSV形式のポイントです。可変抵抗の値の読み取り方については、下記の記事も参考にしてください。
06実践例:一定間隔で記録するデータロガー
millis()でタイミングを管理する
研究用途では、正確な間隔でデータを記録したい場面が多くあります。ここで工夫が必要です。delay()ではなくmillis()を使いましょう。他の処理を止めずに、一定間隔での記録が可能になります。ここでは、1秒ごとにセンサー値を記録する例を紹介します。
実装コード
// millis()を使って1秒ごとにデータを記録するコード
#include <SPI.h>
#include <SD.h>
const int chipSelect = 10;
const int potPin = A0;
unsigned long lastLogTime = 0;
const unsigned long logInterval = 1000; // 1000ミリ秒=1秒ごと
void setup() {
Serial.begin(9600);
if (!SD.begin(chipSelect)) {
Serial.println("SDカードの初期化に失敗しました");
while (1);
}
if (!SD.exists("LOG.CSV")) {
File dataFile = SD.open("LOG.CSV", FILE_WRITE);
if (dataFile) {
dataFile.println("time_ms,pot_value");
dataFile.close();
}
}
}
void loop() {
unsigned long currentTime = millis();
if (currentTime - lastLogTime >= logInterval) {
lastLogTime = currentTime;
int value = analogRead(potPin);
File dataFile = SD.open("LOG.CSV", FILE_WRITE);
if (dataFile) {
dataFile.print(currentTime);
dataFile.print(",");
dataFile.println(value);
dataFile.close();
Serial.println("記録しました");
}
}
// ここに他の処理を書いても、記録のタイミングは崩れない
}
他のセンサーへの応用
この構成をベースにすれば、応用が効きます。可変抵抗の値をMPU6050の加速度・角速度に置き換えるだけです。動作データを記録するロガーになります。記録したCSVファイルをPythonで可視化する方法については、下記の記事も参考にしてください。
07よくあるトラブルと対処法
症状別の対処早見表
| 症状 | 主な原因 | 対処法 |
|---|---|---|
| SD.begin()が失敗する | フォーマット形式の不一致、または配線ミス | FAT32での再フォーマットと配線を確認する(3章参照) |
| ファイルが作成されない | ファイル名が8.3形式を超えている | 8文字以内+拡張子3文字以内のファイル名に変更する |
| 書き込んだはずのデータが消えている | close()の呼び出し忘れ | 書き込み処理の最後に必ずclose()を入れる(4章参照) |
| 電源を切るとファイルが壊れることがある | 書き込み中の電源断 | close()を毎回確実に呼び、記録中は電源を切らない |
| カードの空き容量があるのに書き込めない | SDカード自体の故障、または接触不良 | 別のカードで試す、モジュールとの接触を確認する |
原因を素早く切り分けるコツ
Gさんは長時間の計測を終えたが、SDカードの中にファイルが見当たらなかった。配線にもコードにも問題はなさそうだった。そこで、ループの中の処理を見直してみた。どのタイミングでファイルを閉じているか、確認したのだ。すると、原因が分かった。電源を切る直前に記録していたデータのclose()処理が実行されていなかったのだ。ループのたびに開いて閉じる構成に変更した。すると、電源を切ってもデータが確実に残るようになった。
08よくある質問
基本のQ&A
応用のQ&A
関連記事・参考資料
基礎を学べる記事
- YOFUKASI LAB「Arduinoに必要な工具・部品リスト」2026年, https://yofukasi-lab-wp.com/2026/08/22/arduino-tools-parts/
- YOFUKASI LAB「Arduinoで可変抵抗を読む|配線と値の取得」2026年, https://yofukasi-lab-wp.com/2026/08/27/arduino-potentiometer-analogread/
- YOFUKASI LAB「Arduinoのmillis()でdelayを使わない書き方」2026年, https://yofukasi-lab-wp.com/2026/07/30/delay-millis/
応用・計測関連記事
- YOFUKASI LAB「ArduinoでMPU6050|加速度と角速度」2026年, https://yofukasi-lab-wp.com/2026/08/27/arduino-mpu6050-accel-gyro/
- YOFUKASI LAB「PythonによるDelsysの筋電図のCSVデータを可視化」2026年, https://yofukasi-lab-wp.com/2026/07/13/delays_emg/
- YOFUKASI LAB「Arduinoのコンパイルエラー一覧」2026年, https://yofukasi-lab-wp.com/2026/07/30/error/
参考資料(外部・一次情報)
- Arduino Documentation「Guide to Arduino & Secure Digital (SD) Storage」, https://docs.arduino.cc/learn/programming/sd-guide
- GitHub「arduino-libraries/SD」, https://github.com/arduino-libraries/SD
※本記事は個人の学習・電子工作用途を対象にしています。実際の製品や医療機器へ組み込む場合は、電気安全・製品規格の専門家に別途ご相談ください。
コメント