AdafruitのData Logger Shieldを使用して,ArduinoからSDカードへデータを保存した.
Arduinoで測定したデータはシリアル通信経由でPC上に保存できるが,長期間にわたり記録する際などPCを使わずArduino単体で保存したいこともある.このような場合,SDカードシールドを使用することでArduinoから直接SDカードへ保存することができる.
今回使用したSDカードシールドはAdafruitのData Logger Shieldで,RTC(Real Time Clock)機能が搭載されているのでデータの取得日時も保存できる.
SDカードスロットは標準サイズの大きさで,FAT16またはFAT32形式のフォーマットに対応している.RTCにはPCF8523が使用されており,対応電池はCR1220相当である.詳しい仕様はこちらを参照のこと.
パッケージのインストール
RTCを使用するにはRTClibというパッケージが必要なのでパッケージマネージャからインストールを行う.似たような名前がいくつかあるが,Adafruitが提供しているものをインストールする.
RTCの時刻合わせ
Arduinoのサイトの手順に従い,RTCLibのサンプルスケッチpcf8523を用いてPCの時刻をRTCに設定する.シリアルモニタに表示されている時刻がPCと同じであれば成功.うまくいかない場合はrtc.adjust(DateTime(F(__DATE__), F(__TIME__)));をif文の外に出せば成功するかもしれない.
SDカードへの書き込み
まず,SDカードが正常に認識されているかを確認するため,SDのサンプルスケッチにあるCardInfoを実行する.このとき,スケッチのコメントにあるように定数chipSelectを10に変更しておく.シリアルモニタに以下が表示されていれば成功.
次に,実際にSDカードに書き込みテストを行う.テストにはサンプルスケッチのDataloggerを使用する.このスケッチではanalogReadで取得したアナログ入力A0-A2の値を,カンマ区切りでDATALOG.TXTという名前のファイルに保存する.
CardInfoと同様にchipSelectの値を10に変更するのを忘れないこと.スケッチの実行は数秒間で十分.ArduinoからのSDカードの取り出しは本体の電源を切った後に行った方がいい.カードにDATALOG.TXTというファイルが存在すれば保存成功で,ファイルの中身は以下のようになっている.
このスケッチではSDカードへのデータ保存は追記モードとなっており,記録を再開すると既存のデータの次の行からデータが追加される.また,ファイル形式はCSVもいけるようだ.CSVであればExcelでの利用が非常に楽になる.
なお,SDカードへのデータ保存中はSDカード横の赤色LEDが点灯する.
センサデータを時刻と共にSDカードへ保存する
例として,CTセンサで測定した交流電流値を測定時刻と共にSDカードへ保存してみる.CTセンサはこちらで解説したものを3つ使用し,アナログ入力A0-A2に接続した.スケッチはサンプルスケッチのDataloggerとpcf8523を流用しながら下のように作成した.
//サンプルのSDにあるDataLoggerを流用して変更
#include < spi.h >
#include < sd .h >
#include "RTClib.h"
RTC_PCF8523 rtc;
const int chipSelect = 10;
//保存ファイル名
const String fileName = "data.csv";
//SDカードへの記録間隔[ms]
const long loggingInterval = 2000;
long nn;
//SDカードとRTC関連の初期化処理.
void setup() {
nn = 0;
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// initialize the SD card
Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
while (1);
}
Serial.println("card initialized.");
//以降はRTClibサンプルのpcf8523を流用
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
//RTCが初期化されていない場合は接続先のPCの時間を設定する
//うまく設定できない場合はrtc.adjust(DateTime(F(__DATE__), F(__TIME__)));をifの外に出す
if (! rtc.initialized() || rtc.lostPower()) {
Serial.println("RTC is NOT initialized, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
//
// Note: allow 2 seconds after inserting battery or applying external power
// without battery before calling adjust(). This gives the PCF8523's
// crystal oscillator time to stabilize. If you call adjust() very quickly
// after the RTC is powered, lostPower() may still return true.
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// When the RTC was stopped and stays connected to the battery, it has
// to be restarted by clearing the STOP bit. Let's do this to ensure
// the RTC is running.
rtc.start();
}
void loop() {
// make a string for assembling the data to log:
String dataString = "";
float sensor;
float vol;
float cur;
long n;
n = millis();
//delayの値が大きすぎると動かなくなるため,mills()とnn+loggingIntervalの差がloggingInterval以上か判定するif文で代用.
//nnはif文内を実行ごとにloggingIntervalを加算して更新.
if((n - nn) >= loggingInterval){
nn += loggingInterval;
//日付をyyyy/M/d h:m:s形式で取得
DateTime now = rtc.now();
dataString += String(now.year()) + "/" + String(now.month()) + "/" + String(now.day()) + " ";
dataString += String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second()) + ",";
//3つのCTセンサアンプ基板からA0-A2に入力された電圧を取得し,交流電流の実効値を計算.
for (int analogPin = 0; analogPin < 3; analogPin++) {
sensor = analogRead(analogPin);
vol = sensor*5.0/1024.0;
cur = vol*3000.0/(60.0*4.9);
dataString += String(cur);
if (analogPin < 2) {
dataString += ",";
}
}
//SDカードに記録
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open(fileName, FILE_WRITE);
// if the file is available, write to it:
if (dataFile) {
dataFile.println(dataString);
dataFile.close();
// print to the serial port too:
Serial.println(dataString);
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}
}
このスケッチでは2秒ごとにA0-A2の電圧を交流電流値に変換し,測定時刻と共にCSV形式のファイルに保存する.なお,測定間隔をdelay()で制御すると値が大きいとき処理が止まってしまう(40000ms以上で無理だった)ので,millis()とif文で代用した.
また,setupでシリアル通信の疎通確認をしておりPCとの通信が確立しない限り処理が進まないと思うのだが,USBアダプタから電源を取ってもなぜか動いた.
保存されたファイルをエクセルで開くと以下のようになる(BCD列が電流値)
0 件のコメント:
コメントを投稿