🌟

【XIAO ESP32S3 Sense】microSDカードにデータを記録する

に公開

概要

Seeed Studio XIAO ESP32S3 Sense拡張ボード上のmicroSDカードスロットを使用して、
温湿度センサーDHT20のデータをmicroSDカードに保存します。

メモリ容量の上限について

ESP32S3 Senseでは公式にサポートされているmicroSDカードのサイズは32GBまでです。

https://wiki.seeedstudio.com/ja/xiao_esp32s3_sense_filesystem/

使用するmicroSDカード

https://www.amazon.co.jp/dp/B08PTNWQ6P

使用するピン・配線図

ボードをSenseに変更しただけで、それ以外のピン・配線はこちらから変更ありません。

ブレッドボードでの配線

ライブラリをインストール

追加ライブラリはありません。

スケッチ

スケッチ
#include <Wire.h>
#include <DHT20.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SD.h>
#include <SPI.h>

// --- 設定 ---
// OLED設定
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// DHT20設定
DHT20 dht20;

// SDカード設定
#define SD_CS_PIN 21 // Seeed Studio XIAO ESP32S3 Sense拡張ボード
// const int SD_CS_PIN = D2; // microSDカードスロットモジュール
#define LOG_FILENAME "/data_log_ms.csv"

// タイマー管理
const unsigned long displayInterval = 1000; // 1秒

unsigned long lastLogTime = 0;
const unsigned long logInterval = 60000; // 1分 (60秒)

// --- グローバル変数 ---
float temperature = 0.0;
float humidity = 0.0;

void setup() {
  Serial.begin(115200);
  // while (!Serial); // デバッグ時は有効化

  // Wire初期化 (I2C) - XIAO ESP32S3 Senseのデフォルトピンを使用
  Wire.begin();

  // --- OLED初期化 ---
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(F("Initializing..."));
  display.display();

  // --- DHT20初期化 ---
  dht20.begin();
  delay(1000); // センサー安定化待ち

  // --- SDカード初期化 ---
  Serial.print(F("Initializing SD card..."));
  // XIAO ESP32S3 SenseのオンボードSDスロット用SPIピン設定が必要な場合があるが、
  // 通常はデフォルトSPIでPin 21を指定すれば動作する
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println(F("Card Mount Failed"));
    display.println(F("SD Init Failed!"));
    display.display();
  } else {
    Serial.println(F("SD Card initialized."));
    // ログファイルのヘッダー書き込み (ファイルが存在しない場合のみ)
    if (!SD.exists(LOG_FILENAME)) {
      File file = SD.open(LOG_FILENAME, FILE_WRITE);
      if (file) {
        // Timestamp(ms)に変更
        file.println("Timestamp(ms),Temperature (C),Humidity (%RH)");
        file.close();
      }
    }
  }
  
  delay(2000);
  display.clearDisplay();
}

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

  // --- 1秒ごとにディスプレイ更新 ---
  if (currentMillis - dht20.lastRead() >= displayInterval) {
    updateDisplay();
  }

  // --- 1分ごとにSDカードへログ保存 ---
  if (currentMillis - lastLogTime >= logInterval) {
    lastLogTime = currentMillis;
    logDataToSD();
  }
}

// センサー読み取りとOLED表示
void updateDisplay() {
  int status = dht20.read();
  
  display.clearDisplay();
  display.setCursor(0, 0);

  if (status == DHT20_OK) {
    temperature = dht20.getTemperature();
    humidity = dht20.getHumidity();

    display.setTextSize(1);
    display.println(F("DHT20 Sensor (NoWiFi)"));
    display.println(F("----------------"));
    
    display.setTextSize(2); // 文字を大きく
    display.print(temperature, 1);
    display.println(F(" C"));
    display.print(humidity, 1);
    display.println(F(" %"));
  } else {
    display.setTextSize(1);
    display.println(F("Sensor Error"));
    display.print(F("Status: "));
    display.println(status);
  }

  // 起動時間の表示 (最下部)
  display.setTextSize(1);
  display.setCursor(0, 55); 
  display.print(F("Time: "));
  display.print(millis());
  display.print(F(" ms"));

  display.display();
}

// データログ保存
void logDataToSD() {
  unsigned long currentMillis = millis();

  // CSVフォーマット: Timestamp(ms),Temperature,Humidity
  String dataString = String(currentMillis) + "," + String(temperature, 2) + "," + String(humidity, 2);

  File file = SD.open(LOG_FILENAME, FILE_APPEND);
  if (file) {
    file.println(dataString);
    file.close();
    Serial.println("Logged: " + dataString);
  } else {
    Serial.println(F("Failed to open file for append"));
  }
}

動作確認

シリアルモニタ

OLEDディスプレイ

SDカードに書き込まれたファイル

Discussion