ESP32とSDカードでCSV保存!センサデータロガーの作り方

ESP32

ESP32でセンサの値を読み取れるようになったら、次は測定データをSDカードに保存するデータロガーを作ってみましょう。

データロガーとは、温度や湿度などの測定データを一定間隔で自動的に記録する装置です。

今回は、ESP32-C3を搭載した「KUMITATE-C3」と、温湿度センサSHT40を搭載した「KUMITATE-SENSOR」を組み合わせ、60秒ごとに温度と湿度を取得して、SDカードにCSV形式で保存するプログラムを作成します。

保存したCSVファイルはExcelなどで開くことができ、温度や湿度の変化をグラフにして確認できます。

前回はESP32とSDカードの接続方法や、テキストファイルの読み書きを解説しました。まだ試していない方は、こちらの記事から始めると理解しやすくなります。

関連記事:ESP32とSDカードをSPI接続!配線方法と読み書きプログラムを解説

1. ESP32で温湿度データロガーを作ろう

今回作成するデータロガーは、次の処理を繰り返します。

  1. SHT40から温度と湿度を取得する
  2. 取得した数値をCSV形式に変換する
  3. SDカードのファイルへ追記する
  4. 60秒待って、再び測定する

プログラムの実行中は、USBで接続したパソコンのシリアルモニタにも測定結果を表示します。

SDカードへ保存するので、測定データを記録するためにWi-Fiやインターネットへ接続する必要はありません。

2. 使用する部品

今回使用する部品は次のとおりです。

  • KUMITATE-C3(ESP32-C3搭載開発ボード)
  • KUMITATE-SENSOR(SHT40搭載)
  • SPI対応microSDカードスロットモジュール
  • microSDカード(FAT32形式を推奨)
  • 接続ケーブル
  • USBケーブル

KUMITATE-SENSORとは?

KUMITATE-SENSORは、複数のI2Cセンサを1枚にまとめたセンサボードです。

次の3種類のセンサを搭載しています。

センサ測定内容I2Cアドレス
SHT40-A温度・湿度0x44
BH1750照度0x23
MSA3S023軸加速度0x62

今回は、この中からSHT40-Aを使用して温度と湿度を測定します。

SHT40は温度と相対湿度をデジタル値として取得できるセンサで、ESP32とはI2C通信で接続します。

関連記事:SHT40とは?Arduino・ESP32で温度・湿度を測定する方法を解説

KUMITATE-SENSORの商品詳細はこちら

3. ESP32とSHT40、SDカードの接続方法

今回のポイントは、I2C通信とSPI通信を同時に使用することです。

SHT40との通信にはI2C、SDカードとの通信にはSPIを使用します。

KUMITATE-SENSORのI2C接続

KUMITATE-C3では、I2C通信にGPIO8とGPIO9を使用します。

KUMITATE-SENSORKUMITATE-C3
SDAGPIO8
SCLGPIO9
3V33.3V
GNDGND

センサボード側にはSHT40以外にもBH1750やMSA3S02が搭載されていますが、すべて同じSDAとSCLを共有しています。

今回はSHT40だけをプログラムから読み取ります。

SDカードのSPI接続

SDカードには、前回の記事と同じGPIO4~GPIO7を使用します。

SDカードモジュールKUMITATE-C3
CSGPIO4
MOSIGPIO5
SCKGPIO6
MISOGPIO7
VCC3.3V
GNDGND

SDカードモジュールは3.3V電源・3.3Vロジックに対応したものを使用してください。モジュールによって電源仕様や端子表記が異なるため、製品仕様も確認しましょう。

また、センサとSDカードはどちらも3.3V電源を使用し、GNDを共通にします。配線の接続や変更は、電源を切った状態で行ってください。

4. Arduino IDEの準備

今回はArduino IDEとArduino-ESP32環境を使用します。

温湿度センサSHT40の制御には、Adafruitのライブラリを使用します。

Arduino IDEの「ライブラリを管理」から、次のライブラリを検索してインストールしてください。

  • Adafruit SHT4x Library
  • Adafruit BusIO
  • Adafruit Unified Sensor

依存ライブラリのインストールを求められた場合は、まとめてインストールしてください。

SDカードの制御には、Arduino-ESP32に付属するSPI.hとSD.hを使用します。

5. 温度と湿度を60秒ごとにCSV保存するプログラム

それでは、プログラムを作成してみましょう。

今回は以下の仕様とします。

項目仕様
センサSHT40-A
測定間隔60秒
保存先SDカード
ファイル名temperature.csv
保存する値経過秒数、温度、湿度
ファイル形式CSV

サンプルプログラム

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_SHT4x.h>

// I2C接続ピン
const int I2C_SDA = 8;
const int I2C_SCL = 9;

// SDカードのSPI接続ピン
const int SD_CS   = 4;
const int SD_MOSI = 5;
const int SD_SCK  = 6;
const int SD_MISO = 7;

// CSVファイル名
const char* CSV_FILE = "/temperature.csv";

// 測定間隔:60秒
const unsigned long LOG_INTERVAL_MS = 60000;

// SHT40オブジェクト
Adafruit_SHT4x sht4;

// 測定周期の管理
unsigned long lastLogMs = 0;
bool hasLogged = false;

void setup() {
  Serial.begin(115200);
  delay(2000);

  Serial.println("温湿度データロガー開始");

  // I2C初期化
  Wire.begin(I2C_SDA, I2C_SCL);

  // SHT40初期化
  if (!sht4.begin(&Wire)) {
    Serial.println("SHT40が見つかりません");
    while (true) {
      delay(1000);
    }
  }

  sht4.setPrecision(SHT4X_HIGH_PRECISION);
  sht4.setHeater(SHT4X_NO_HEATER);

  Serial.println("SHT40初期化成功");

  // SPI初期化
  SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);

  // SDカード初期化
  if (!SD.begin(SD_CS, SPI, 4000000)) {
    Serial.println("SDカード初期化失敗");
    while (true) {
      delay(1000);
    }
  }

  if (SD.cardType() == CARD_NONE) {
    Serial.println("SDカードがありません");
    while (true) {
      delay(1000);
    }
  }

  Serial.println("SDカード初期化成功");

  // CSVファイルが存在しなければ作成
  if (!SD.exists(CSV_FILE)) {
    File file = SD.open(CSV_FILE, FILE_WRITE);

    if (!file) {
      Serial.println("CSVファイル作成失敗");
      while (true) {
        delay(1000);
      }
    }

    // CSVの見出し行
    file.println("elapsed_s,temperature_c,humidity_percent");
    file.close();

    Serial.println("CSVファイル作成成功");
  }
}

void loop() {
  unsigned long now = millis();

  // 初回は即測定、2回目から60秒間隔
  if (hasLogged &&
      (now - lastLogMs < LOG_INTERVAL_MS)) {
    delay(10);
    return;
  }

  lastLogMs = now;
  hasLogged = true;

  // SHT40から温度・湿度を取得
  sensors_event_t humidityEvent;
  sensors_event_t tempEvent;

  if (!sht4.getEvent(&humidityEvent, &tempEvent)) {
    Serial.println("SHT40読み取り失敗");
    return;
  }

  // 起動後の経過秒数
  unsigned long elapsedSec = millis() / 1000UL;

  // シリアルモニタへ表示
  Serial.print("Time: ");
  Serial.print(elapsedSec);
  Serial.print(" s, Temperature: ");
  Serial.print(tempEvent.temperature, 2);
  Serial.print(" C, Humidity: ");
  Serial.print(humidityEvent.relative_humidity, 2);
  Serial.println(" %RH");

  // CSVファイルを追記モードで開く
  File file = SD.open(CSV_FILE, FILE_APPEND);

  if (!file) {
    Serial.println("CSVファイルを開けません");
    return;
  }

  // CSV形式で保存
  file.print(elapsedSec);
  file.print(",");
  file.print(tempEvent.temperature, 2);
  file.print(",");
  size_t written =
    file.println(humidityEvent.relative_humidity, 2);

  file.close();

  if (written == 0) {
    Serial.println("SDカードへの書き込み失敗");
  } else {
    Serial.println("CSV保存完了");
  }
}

このプログラムでは、最初の測定を起動直後に行い、その後は約60秒ごとに温湿度を測定します。

SDカード内にtemperature.csvが存在する場合は、既存データの末尾に新しい測定結果を追記します。

※上記はArduino-ESP32とAdafruit SHT4xライブラリを使用したサンプルです。実際の動作は使用する基板・ライブラリのバージョン・SDカードモジュールで確認してください。

6. プログラムの実行結果

プログラムをKUMITATE-C3へ書き込んだら、Arduino IDEのシリアルモニタを115200bpsで開きます。

正常に動作すると、以下のようなメッセージが表示されます。

温湿度データロガー開始
SHT40初期化成功
SDカード初期化成功
CSVファイル作成成功

Time: 2 s, Temperature: 25.12 C, Humidity: 52.30 %RH
CSV保存完了

Time: 62 s, Temperature: 25.20 C, Humidity: 52.10 %RH
CSV保存完了

Time: 122 s, Temperature: 25.35 C, Humidity: 51.80 %RH
CSV保存完了

※上記は表示例です。実際の温湿度や測定開始時刻は動作環境によって異なります。

測定を繰り返すことで、SDカードにはデータが追加されていきます。

7. SDカードに保存されたCSVファイルを確認する

電源を切ってからSDカードを取り外し、パソコンでファイルを開いてみましょう。

SDカード内には「temperature.csv」というファイルが作成されています。

内容は次のようになります。

elapsed_s,temperature_c,humidity_percent
2,25.12,52.30
62,25.20,52.10
122,25.35,51.80
182,25.41,51.72
242,25.38,51.65

CSV(Comma-Separated Values)は、値をカンマで区切って保存するテキスト形式です。

1行目は項目名を表しています。

項目名意味
elapsed_s起動後の経過秒数
temperature_c温度(℃)
humidity_percent相対湿度(%RH)

ExcelやGoogleスプレッドシートで開けば、表として表示したり、グラフを作成したりできます。

8. プログラムの仕組みを解説

① I2CとSPIを初期化する

今回のプログラムでは、2種類の通信方式を使用します。

Wire.begin(I2C_SDA, I2C_SCL);

SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);

Wire.begin()はI2C、SPI.begin()はSPIの初期化処理です。

マイコンが複数の通信方式を使って周辺機器を制御することは、組み込み開発ではよくあります。

今回の場合、温湿度データの取得にはI2C、取得したデータの保存にはSPIを使っています。

② SHT40から温度・湿度を取得する

sensors_event_t humidityEvent;
sensors_event_t tempEvent;

if (!sht4.getEvent(&humidityEvent, &tempEvent)) {
  Serial.println("SHT40読み取り失敗");
  return;
}

Adafruit SHT4xライブラリのgetEvent()を使用して、温度と湿度を取得しています。

温度はtempEvent.temperature、湿度はhumidityEvent.relative_humidityから参照できます。

通信エラーが発生した場合は、その回の保存処理を行わず、次の測定周期まで待ちます。

③ millis()で60秒ごとに測定する

const unsigned long LOG_INTERVAL_MS = 60000;

60000ミリ秒は60秒です。

Arduinoのmillis()は、プログラム実行開始からの経過時間をミリ秒単位で取得する関数です。

今回のプログラムでは、前回の測定開始時刻から60秒経過したかどうかを判定しています。

delay(60000)を使って単純に待つこともできますが、millis()を使用すると、将来ほかの処理を追加しやすくなります。

なお、millis()は現在日時を取得する関数ではありません。起動後の経過時間を扱うもので、再起動すると基準がリセットされます。

④ SDカードのファイルへ追記する

File file = SD.open(CSV_FILE, FILE_APPEND);

FILE_APPENDは、ファイルの末尾へデータを追加するモードです。

すでに記録した測定データを残したまま、新しい測定結果を追記できます。

file.print(elapsedSec);
file.print(",");
file.print(tempEvent.temperature, 2);
file.print(",");
file.println(humidityEvent.relative_humidity, 2);

この部分で、経過秒数、温度、湿度をカンマで区切って書き込んでいます。

print()は改行せずに書き込み、println()は最後に改行するため、測定1回分がCSVファイルの1行になります。

⑤ ファイルを閉じてデータを保存する

file.close();

測定するたびにファイルを開き、書き込みが終わったら閉じています。

ファイルを開いたままにするより、測定のたびにクローズした方が、長時間の記録時に未反映データを減らしやすくなります。

ただし、書き込み中の突然の電源断などでデータやファイルが破損する可能性は残ります。SDカードを取り外す場合は、電源を切ってから行いましょう。

9. CSVファイルをExcelでグラフ化する

SDカードに保存したCSVファイルは、Excelを使って簡単にグラフにできます。

  1. SDカードをパソコンに接続する
  2. temperature.csvをExcelで開く
  3. 経過秒数と温度の列を選択する
  4. 挿入メニューから散布図や折れ線グラフを作成する
  5. 必要に応じて湿度も別のグラフにする

これにより、時間の経過に伴う温度や湿度の変化を視覚的に確認できます。

例えば、窓を開けたときの室温の変化や、加湿器を動かしたときの湿度の推移を記録すると、センサを利用した測定の面白さが実感できます。

10. SDカードやSHT40が認識されない場合

SHT40が見つからない場合

「SHT40が見つかりません」と表示された場合は、次の項目を確認してください。

  • SDAがGPIO8、SCLがGPIO9へ接続されているか
  • 電源が3.3Vで供給されているか
  • GNDが共通になっているか
  • I2Cアドレス0x44のデバイスが認識されているか

I2Cスキャナを使えば、接続したデバイスのアドレスを確認できます。

関連記事:Arduino・ESP32でI2Cスキャナを使う方法

SDカードが初期化できない場合

SDカードが初期化できない場合は、CS・MOSI・MISO・SCKの配線、モジュールの電源仕様、SDカードのフォーマットを確認してください。

通信が不安定な場合は、SPIの動作速度を下げて試す方法もあります。

SD.begin(SD_CS, SPI, 1000000);

SDカードの接続方法や初期化については、前回の記事でも詳しく解説しています。

ESP32とSDカードをSPI接続する方法はこちら

11. 応用:さらに実用的なデータロガーへ発展させる

今回のプログラムでは、起動後の経過秒数を記録しています。

しかし、実際の用途では「何月何日の何時に測定したデータなのか」を記録したいこともあるでしょう。

その場合は、ESP32のWi-Fi機能を利用してNTPサーバから時刻を取得したり、RTCモジュールを追加したりする方法があります。

また、KUMITATE-SENSORには温湿度以外にも照度センサBH1750が搭載されているため、次のようなCSVファイルへ拡張できます。

elapsed_s,temperature_c,humidity_percent,lux
2,25.12,52.30,420
62,25.20,52.10,435
122,25.35,51.80,410

温度・湿度・照度をまとめて保存すれば、室内環境の変化をより詳しく観察できます。

さらに、取得したデータをWi-Fi経由で送信したり、OLEDへ表示したりすることも可能です。

12. まとめ

今回はKUMITATE-C3とKUMITATE-SENSORを使用して、温度と湿度をSDカードにCSV保存するデータロガーを作成しました。

今回のポイントは次のとおりです。

  • SHT40をI2C通信で制御し、温度・湿度を取得する
  • SDカードをSPI通信で制御する
  • millis()を使って60秒ごとに測定する
  • CSV形式でSDカードへ測定結果を追記する
  • 保存したCSVファイルをExcelでグラフ化できる

今回のように、センサでデータを取得し、別の通信方式を使ってストレージへ保存する処理は、組み込み開発の基本的な要素の一つです。

単にセンサの値を表示するだけでなく、データを蓄積・分析するところまで体験することで、組み込みプログラミングの理解をさらに深めることができます。

KUMITATE-C3とKUMITATE-SENSORで電子工作を学ぼう

クミタテでは、ESP32-C3を使用してGPIO、I2C、SPI、センサ制御などを実際に体験できる学習教材を公開しています。

KUMITATE-SENSORを組み合わせることで、温湿度だけでなく照度や加速度の測定にも挑戦できます。

KUMITATE-SENSORの商品詳細を見る

クミタテ|組み込みプログラミング学習サイト

参考資料

KUMITATE

読むだけでなく、
実際に動かして学びませんか?

クミタテは、組み込み開発や電子工作を 実践しながら学べる学習プラットフォームです。 ESP32を使ったプログラミングから、電子回路、センサー、 通信、基板設計まで、自分のペースで学習できます。

  • 無料で学べる実践的な教材を掲載
  • すぐに試せるサンプルプログラム付き
  • Googleアカウントですぐに登録可能
クミタテに無料登録する
ESP32
スポンサーリンク