
以前公開した「
Arduinoで遊ぼう - SDメモリカードを読み書きする」の内容が古くなっていたので、新しく書き直しました。今回はArduino IDE標準のSDライブラリを使ってSDメモリカードを読み書きする方法を解説します。
最近のSDメモリカードは1GBを超える容量のものが非常に安価に発売されています。SDライブラリを使えばArduinoからも簡単に読み書きできるので、大規模なデータロギングに最適なストレージと言えます。
注意すべきこと
SDメモリカードの動作電圧は2.7~3.6Vです。SDカードにもよりますが書き込み時に電流は、100mAを超えて流れるものがあります。SDカードの電源は十分な容量を確保してください。
また5V動作のArduinoでSDメモリカードを使用する場合、Arduinoの出力電圧を5Vから3.3Vに変換する必要があります。今回、抵抗による分圧回路を使っていますが、信号がナマってしまってうまく通信できない場合があります。このような場合、電圧の変換には5Vトレラント機能が付いたバッファIC(74LVX245または74VHC125)や専用IC(2電源レベルシフタ)を使うことをお勧めします。
SDメモリカードには次の3種類の規格があります。
- SD - 最大2GB。FAT12・FAT16ファイルシステムを使用。
- SDHC - 2GB〜32GBまで。FAT32ファイルシステムを使用。
- SDXC - 32GB〜2TBまで。exFATファイルシステムを使用。
SDライブラリはSDとSDHCのみ対応しており、SDXCの読み書きはできません。またファイルシステムはFAT16とFAT32に対応しています。FAT12やexFATでフォーマットされたカードの読み書きはできません。
ピン配列
次の図はSDメモリカードとmicroSDメモリカードのピン配列を表しています。

| SD端子 | microSD端子 | 機能 | 説明 |
| 9 | 1 | DAT2 | 未使用 |
| 1 | 2 | DAT3/CS | チップセレクト |
| 2 | 3 | CMD/DI | データ入力 |
| 3 | | VSS | グランド |
| 4 | 4 | VDD | 電源 |
| 5 | 5 | CLK | シリアルクロック |
| 6 | 6 | VSS | グランド |
| 7 | 7 | DAT0/D0 | データ出力 |
| 8 | 8 | DAT1 | 未使用 |
SDカードにはSDモードとSPIモードとよばれる2つのモードがあります。SDモードはSDカードの速度を最大限にいかした転送を行うモードです。SPIモードはCS/DI/CLK/DOの4つの端子を使った転送モードです。低速なマイコンとの通信に使われます。SDライブラリはSPIモードでSDカードにアクセスします。
Arduinoに接続する
SDメモリカードとの接続にはサンハヤトの
microSD変換基板を使いました。変換基板が手に入らない場合は、SDカードアダプタ(micorSD-SD)にヘッダピンやワイヤを直接半田付けすると良いでしょう。電圧変換には抵抗分圧回路を使いました。抵抗値は1.8KΩと3.3KΩ。

Arduino vs SDメモリカード
ピン11 - DI (MOSI)
ピン12 - DO (MISO)
ピン13 - CLK (SCK)
ピン4 - CS
シールドを使ってArduinoに接続する
もっとお手軽・簡単に使いたい場合は、SDメモリカードスロットを搭載したシールドを使うと良いでしょう。例えば、
イーサネットシールドや
ワイヤレスSDシールド、
マイクロSDシールドなどです。これらのシールドには電圧変換用にバッファICなどが使われています。
シールドによってSDカードのCSに接続されているピンが異なるので注意すること。
Arduino イーサネットシールド R3
CS -> 4
ワイヤレスSDシールド
CS -> 4
SparkFun マイクロSDシールド
CS -> 8SDライブラリのインポート
Arduino IDE標準のSDライブラリを使います。ファイルメニューから"スケッチ→ライブラリを使用→SD"を選ぶと自動的にインポートされます。
Arduino - SD Library
http://arduino.cc/en/Reference/SDArduino IDE 1.0.x以降では、複数ファイルの読み書きが同時に行えるようになりました。
SDライブラリにはいくつか制限があります。
- ファイル名は8文字+3文字までです。例えば「filename.txt」はOKですが、「filename_2013.text」はNGです。
- ファイルシステムはFAT16またはFAT32のみ対応しています。
- SDとSDHCのみ対応しています。SDXCは非対応です。
サンプルスケッチ(書き込み)
1秒間隔でアナログ入力0の値を読み取り、SDカードに書き込むサンプルです。
SD.open() の引数に FILE_WRITE を指定するとファイルを読み書きモードでオープンします。ファイルが存在しない場合は新しいファイルが作成され、すでにファイルが存在する場合は追記モードでオープンします。
print() や println() で数値や文字が書き込めます。バイナリデータを書き込む場合は、write() を使います。書き込み速度は一度に沢山のデータを書き込んだ方が速くなります。seek(0) でファイルの先頭からデータを書き込めます。
#include <SD.h>
// この値は使用しているシールドや基板に合わせて変更すること。たとえば、
// イーサーネットシールドは 4
// Adafruit のSDシールドは 10
// Sparkfun のSDシールドは 8
const int chipSelect = 4;
void setup()
{
// シリアルポート初期化
Serial.begin(9600);
while (!Serial) {
; // USBケーブルが接続されるのを待つ。この待ちループは Leonardo のみ必要。
}
Serial.print(F("Initializing SD card..."));
// SSピン(Unoは10番、Megaは53番)は使わない場合でも出力にする必要があります。
// そうしないと、SPIがスレーブモードに移行し、SDライブラリが動作しなくなります。
pinMode(SS, OUTPUT);
// SDライブラリを初期化
if (!SD.begin(chipSelect)) {
Serial.println(F("Card failed, or not present"));
// 失敗、何もしない
while(1);
}
Serial.println(F("ok."));
// 日付と時刻を返す関数を登録
SdFile::dateTimeCallback( &dateTime );
}
void loop()
{
// ファイルを開く
File dataFile = SD.open("datalog.txt", FILE_WRITE);
// もしファイルが開けたら値を書き込む
if (dataFile) {
int value = analogRead(0);
dataFile.println(value);
dataFile.close();
// シリアルポートにも出力
Serial.println(value);
}
// ファイルが開けなかったらエラーを出力
else {
Serial.println(F("error opening datalog.txt"));
}
// 一秒待つ
delay(1000);
}
void dateTime(uint16_t* date, uint16_t* time)
{
uint16_t year = 2013;
uint8_t month = 2, day = 3, hour = 9, minute = 0, second = 0;
// GPSやRTCから日付と時間を取得
// FAT_DATEマクロでフィールドを埋めて日付を返す
*date = FAT_DATE(year, month, day);
// FAT_TIMEマクロでフィールドを埋めて時間を返す
*time = FAT_TIME(hour, minute, second);
}
次のように日時を返す関数を登録することで、ファイルの作成日時や変更日時が記録できます。
// 日付と時刻を返す関数を登録
SdFile::dateTimeCallback( &dateTime );
サンプルスケッチ(読み込み)
ファイルに書き込まれている値をシリアルモニタに出力するサンプルスケッチです。
SD.open() の引数を省略すると読み込み専用モードでオープンします。引数を省略した場合は FILE_READ を指定したことと同じになります。
available() は現在の位置から何バイト読み込めるか返します。available() の戻り値は int 型で読み込めるバイト数が32767を超える場合、戻り値は常に32767になります。ファイルのサイズは size() で取得できます。
read() は1byte読み出します。read(buffer, length) とした場合、lengthバイト分のデータをbufferに読み込みます。
position() は現在の読み込み位置を返します。seek() で読み込み位置を移動できます。
#include <SD.h>
// この値は使用しているシールドや基板に合わせて変更すること。たとえば、
// イーサーネットシールドは 4
// Adafruit のSDシールドは 10
// Sparkfun のSDシールドは 8
const int chipSelect = 4;
void setup()
{
// シリアルポート初期化
Serial.begin(9600);
while (!Serial) {
; // USBケーブルが接続されるのを待つ。この待ちループは Leonardo のみ必要。
}
Serial.print(F("Initializing SD card..."));
// SSピン(Unoは10番、Megaは53番)は使わない場合でも出力にする必要があります。
// そうしないとSPIがスレーブモードに移行し、SDライブラリが動作しなくなります。
pinMode(SS, OUTPUT);
// SDライブラリを初期化
if (!SD.begin(chipSelect)) {
Serial.println(F("Card failed, or not present"));
// 失敗、何もしない
while(1);
}
Serial.println(F("ok."));
// ファイルを開く
File dataFile = SD.open("datalog.txt");
// もしファイルが開けたら値をシリアルポートに出力する
if (dataFile) {
// 64byte単位で読み出す
byte buffer[64];
while (dataFile.available()) {
int length = dataFile.available();
if(length > 64){
length = 64;
}
dataFile.read(buffer, length);
Serial.write(buffer, length);
}
// 1byte単位で読み出す
// while (dataFile.available()) {
// Serial.write(dataFile.read());
// }
dataFile.close();
}
// ファイルが開けなかったらエラーを出力する
else {
Serial.println(F("error opening datalog.txt"));
}
}
void loop()
{
}
参考リンク
SDメモリカード - Wikipedia
http://ja.wikipedia.org/wiki/SDSDメモリカードArduinoでマイクロSDカードを使う - ラジオペンチ
http://radiopench.blog96.fc2.com/blog-entry-332.html