SDカード
UNO

概要

EthernetシールドについているマイクロSDカードスロットを使って、SDカードにアクセスする実験です。

目的

SDカードライブラリの使い方を確認します。

実験

初期化

SDカードライブラリを利用するには、SD.begin()で初期化を行う必要があります。SDという変数(オブジェクト)は、SDカードライブラリの中で事前に定義されているSDClass型の変数です。この関数は引数としてCS(Chip Select)ピン番号をとることができます。CSピン番号を指定しない場合のデフォルトはSSピン(Arduino Unoの場合は10番ピン)です。CSピン番号は、利用するSDカード用のボード・シールドによって異なります。また、利用するボード・シールドが利用するCSピンがSSピンではない場合でも、SSピンをOUTPUTモードにしておく必要があります。ただし、ソースコードを読んだところ、SD.begin()の延長で呼ばれる、Sd2Card::init()の中に、以下のコードが入っていたので、SDカードを利用するスケッチの中で、SSピンのモードや出力を変更しなければいいだけと思われます。つまり、SDカードライブラリを利用する場合はSSピンは使ってはいけないということです。

1
2
3
  // set pin modes
  pinMode(chipSelectPin_, OUTPUT);
  digitalWrite(chipSelectPin_, HIGH);

SDClassは、SDデバイスを操作するためのSd2Card、ボリュームを操作するためのSdVolume、ファイルを操作するためのSdFileから構成されています。

SDオブジェクトは、Arduinoに接続したSDカードとそのカード上のボリューム、ボリュームの上に作成されているrootディレクトリを管理します。

ファイルをオープンする

SDカード上にファイルを作成したり、ファイルからデータを読み込む前には、SDClassのメソッドである、SDClass::open()を利用してファイルをオープンする必要があります。

この関数の第2引数によって、ファイルを読み取り専用でオープンするのか、書込み用にオープンするのかを制御します。第1引数に指定したファイルの有無と第2引数の組み合わせによる動作は以下の通りです。第2引数は省略することができ、省略した場合はFILE_READを指定するのと同じ動作となります。

FILE_WRITE FILE_READ
指定ファイルが存在する 指定したファイルをオープンする。書き込み位置はファイルの最後尾。 指定したファイルをオープンする。読み込み位置はファイルの先頭。
指定ファイルが存在しない 指定したファイルを作成してオープンする。 エラー

SDClass::open()の戻り値はFile型です。オープンしたファイルの操作は、このFile型のオブジェクトに対して実施します。

新規にファイルを作成した場合、そのファイルの作成日時は、2000年1月1日1時0分0秒となります。ファイルの作成日時を変更したい場合は、void dateTime(uint16_t* date, uint16_t* time)という関数を定義する必要があります。utility/SDFat.hに例として以下のようなコードが記述されています。year、month、day、hour、minute、secondは自分で設定する必要があります。この関数はファイルを作成したときと、ファイルをフラッシュしたとき(File::flush()もしくはFile::close()が呼ばれたとき)に呼ばれます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void dateTime(uint16_t* date, uint16_t* time) {
  uint16_t year;
  uint8_t month, day, hour, minute, second;
  
  // User gets date and time from GPS or real-time clock here
  
  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(year, month, day);
  
  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(hour, minute, second);
}

dateは16ビット内に以下の形式で格納されます。年は1980年始まりです(2013年の場合は33となります)。

timeは16ビット内に以下の形式で格納されます。秒に5ビットしか割り当てられていないので、秒を2で割った値が格納されます。

FAT_DATE()、FAT_TIME()は、上記のフォーマットに合わせるための関数です。

ファイルを作成したときのファイル名は小文字を指定しても大文字となります。

SDClass::open()はFileクラスのオブジェクトを返却します。ファイルへの読み書きはこのオブジェクトに対する操作として実現されています。FileクラスはStreamクラスを継承したクラスで、SdFileクラスが提供する機能をArduinoでよく利用する形式のAPIとして提供します。

ファイルを読み書きする

ファイルの読み書きは、SD.open()で返却されたFileクラスのオブジェクトを操作することで実現します。read()write()print()println()available()というおなじみの関数を使うことができます。ファイルにデータを書き込んだ後は、flush()もしくはclose()を実行する必要があります。これを実行しないと、SDカードにデータが書き込まれないので注意してください。

以下に、FILE1.TXTというファイルに、“Hello world!!“と書くスケッチを示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <SD.h>

const int cs = 4; // Ethernet Shield uses pin 4 as CS.

void setup() {
  File file;
 
  Serial.begin(9600);
  SD.begin(cs); 
  if (file = SD.open("file1.txt", FILE_WRITE)) {
    Serial.println("Opening File Succeeded.");
  } else {
    Serial.println("Opening File Failed.");
  }
  
  file.println("Hello world!!");
  
  file.close();
}

void loop() {
  
}

標準入出力関数を利用できるようにする

C言語をよく使う方は、fprintf()やgetc()を使ってファイルへの読み書きをしたくなるかもしれません。以下では標準入出力関数を利用するための方法を示します。スケッチのサイズが大きくなるので注意してください。

avr-libcにはfdev_setup_stream()という、ストリームを設定するための関数が用意されています。これを利用すれば標準入出力関数を使うための設定ができます。

出力

SDカードにprintf()/fprintf()を使って出力する例を示します。

 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
#include <SD.h>

const int cs = 4; // Ethernet Shield uses pin 4 as CS.
FILE sdio = {0};
File file;

int sd_putchar(char c, FILE *stream) {
  file.write(c);
  return 0;
}

void setup() {
  Serial.begin(9600);
  SD.begin(cs); 
  if (file = SD.open("file1.txt", FILE_WRITE)) {
    Serial.println("Opening File Succeeded.");
  } else {
    Serial.println("Opening File Failed.");
  }
  
  fdev_setup_stream(&sdio, sd_putchar, NULL, _FDEV_SETUP_WRITE);

  stdout = &sdio;

  printf("Hello world printf!!\n");  
  fprintf(&sdio, "Hello world fprintf\n");
  
  file.close();
}

void loop() {
  
}

入力

SDカードからgetc()を使って入力する例を示します。

 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
#include <SD.h>

const int cs = 4; // Ethernet Shield uses pin 4 as CS.
FILE sdio;
File file;

int sd_getchar(FILE *stream) {
  if (file.available() > 0) {
    return (int)file.read();
  } else {
    return _FDEV_EOF;
  }
}

void setup() {
  char c;
  
  Serial.begin(9600);
  SD.begin(cs); 
  if (file = SD.open("file1.txt", FILE_READ)) {
    Serial.println("Opening File Succeeded.");
  } else {
    Serial.println("Opening File Failed.");
  }
  
  fdev_setup_stream(&sdio, NULL, sd_getchar, _FDEV_SETUP_READ);

  while ((c = getc(&sdio)) > 0) {
    Serial.write(c);
  }

  file.close();
  Serial.println("File closed.");
}

void loop() {
  
}

バージョン

Hardware:Arduino Uno
Software:Arduino 1.0.4

最終更新日

January 28, 2024

inserted by FC2 system