2010年11月25日木曜日

定点観測データロガー -4 : SDカードにデータを保存する


フィールド設置型の定点観測ロガーを作成する。

< 定点観測器の仕様 >
  1. 計測内容は、計測時刻・気温・湿度・温度・照度とする。
  2. Arduino Pro 328 3.3V 8MHz をスタンドアロンで動作させる。
  3. 単三乾電池4個を電源とし、最低一週間は稼働する省電力設計とする。
  4. 設定した間隔で持続的にデータを記録できるものとする。
  5. 定期的に記録データ媒体と乾電池を交換できる設計とする。
  6. 計測データの保存はSDカードを使用する。

< SDカードへの書き込み >



カードスロットは秋月電子で購入。
このほかに、SDカード(2GBで十分)、SDカードリーダーも必要。

SDカードの書き込みについては、そのままずばりやりたいことの記事があったので活用させて頂きました。
下記のリンクを参考にさせていただきました。ありがとうございます。
エレキジャック・フィジカルコンピューティング Arduinoで何でも制御 SDカードを接続するアーカイブ


ログファイルは"LOG_DATA.CSV"という名前で保存している。
今回はタイムスタンプ情報のみだけど、温度や湿度などの各種データは、
","(カンマ)区切りで1列に並べて保存することを想定している。
その上で拡張子を「.csv」で保存すると、カンマ区切りのデータをエクセルやopenOfficeで開いた時に
セルの中に各種データがきれいにおさまる。

SD関連のエラー処理だけが困った。
リンク先のスケッチではエラーが起こったらシリアル出力するようにしているけど、
本番の定点観測データロガーではシリアル出力はしない。
かといって、エラーログを保存しようにもSDカード自体のエラーなのだから保存先がない。
EEPROMはタイムスタンプ保存専用なので論外。
本番ではエラーは起こらないという想定で無理矢理やることにする。
確認なので、以下のスケッチではエラーをシリアル出力している。



/*
 * sketch name   : timestamp_write_sd
 * summary       : SDカードへの書き込み
 */

#include <DateTime.h>
#include <Fat16.h>
#include <Fat16util.h>

/* 時刻関連 */
unsigned int year   = 2010;
unsigned int month  = 11;
unsigned int day    = 20;
unsigned int hour   = 21;
unsigned int minute = 15;
unsigned int second = 0;
unsigned long log_timestamp;         // 計測時刻タイムスタンプ
#define TIMESTAMP_JST_DEF_SEC 32400  // 日本標準時(JST)への修正秒数(9時間固定)

/* SDカード関連 */
#define SD_ERROR_OK         0
#define SD_ERROR_CARD_INIT  1
#define SD_ERROR_FAT16_INIT 2
#define SD_ERROR_OPEN       3
#define SD_ERROR_WRITE      4
#define SD_ERROR_CLOSE      5
unsigned int sd_error_no;  // SDエラー番号格納
// エラー文字列
char *sd_error[] = {
       "no error.",
       "error about sd card init.",
       "error about sd fat16 init.",
       "error about sd open.",
       "error about sd write.",
       "error about sd close.",
     };
#define LOG_FILE_NAME "log_data.csv"  // 記録ファイル名

/* ライブラリのインスタンス化 */
SdCard obj_card;
Fat16  obj_file;

void setup()
{
  Serial.begin(9600);
  DateTime.sync(DateTime.makeTime(second, minute, hour, day, month, year));  // DateTime初期化
}

void loop()
{
  log_timestamp = DateTime.now() - TIMESTAMP_JST_DEF_SEC;  // 日本標準時(JST) = グリニッジ標準時(GMT) - 9時間
  
  sd_error_no = dataToSdFileWrite (log_timestamp);
  if (sd_error_no != SD_ERROR_OK) {
    Serial.println(sd_error[sd_error_no]);
  }
  
  delay(5000);
}

/*
 * func name  : dataToSdFileWrite
 * processing : SDカード記録
 * param      : log_timestamp  / タイムスタンプ
 * return     : エラー番号
 */
int dataToSdFileWrite (unsigned long log_timestamp)
{
  if (!obj_card.init()) return SD_ERROR_CARD_INIT;
  if (!Fat16::init(&obj_card)) return SD_ERROR_FAT16_INIT;
  // O_CREAT  : ファイルが存在しなかったら作成する
  // O_APPEND : 書き込み前に、ファイル内のデータの最後尾を探す(追記)
  // O_WRITE  : 書き込みのためにファイルを開く
  if (!obj_file.open(LOG_FILE_NAME, O_CREAT | O_APPEND | O_WRITE)) return SD_ERROR_OPEN;
  obj_file.writeError = false;
  
  // タイムスタンプ記録
  obj_file.print(log_timestamp);
  obj_file.println();
  if (obj_file.writeError) return SD_ERROR_WRITE;
  if (!obj_file.close()) return SD_ERROR_CLOSE;
  
  return SD_ERROR_OK;
}



適当なタイミングでプログラムを止めて、SDカードの内容をリーダーで見てみる。


delay()関数で5秒おきのタイムスタンプ情報が記録されている。

0 コメント:

コメントを投稿