Build an SD Card Data Logger
StorageSensorsIoT
A real, offline data logger -- no Wi-Fi required, no cloud account, just accurate timestamped readings saved straight to a card.
7 real parts included
Total for this kit: 1,679.00 ฿
Doesn't include any order discount you may get at checkout.
What you'll need
ESP32-C3 SuperMini Development Board — Wi-Fi & Bluetooth, USB-C
670.00 ฿
AHT20 Temperature & Humidity Sensor Module — I2C
260.00 ฿
Micro SD Card Module — SPI, 3.3V/5V Compatible
75.00 ฿
DS3231 Real-Time Clock Module — Battery-Backed
149.00 ฿
830-Point Solderless Breadboard
125.00 ฿
Jumper Wire Kit — Male-Male, Male-Female, Female-Female
220.00 ฿
USB-C Data & Charging Cable — 1m
180.00 ฿
Wiring Diagram
Starter Code
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <RTClib.h>
#include <Adafruit_AHTX0.h>
#define SDA_PIN 8 // ESP32-C3 default I2C SDA - adjust if your board differs
#define SCL_PIN 9 // ESP32-C3 default I2C SCL - adjust if your board differs
#define SPI_SCK_PIN 4 // ESP32-C3 default hardware SPI pins - adjust to match your board's silkscreen if different
#define SPI_MISO_PIN 5
#define SPI_MOSI_PIN 6
#define SD_CS_PIN 7 // SD module chip select - any free digital GPIO
const char* LOG_FILENAME = "/datalog.csv";
const unsigned long LOG_INTERVAL_MS = 5000; // log every 5 seconds
Adafruit_AHTX0 aht;
RTC_DS3231 rtc;
unsigned long lastLog = 0;
void setup() {
Serial.begin(115200);
delay(500);
Wire.begin(SDA_PIN, SCL_PIN);
if (!aht.begin()) {
Serial.println("AHT20 not found - check I2C wiring");
while (true) delay(1000);
}
if (!rtc.begin()) {
Serial.println("DS3231 not found - check I2C wiring");
while (true) delay(1000);
}
if (rtc.lostPower()) {
// Sets the RTC to the sketch's compile time. Only needed once after the
// coin cell has been out / on first power-up - remove after the RTC is set.
Serial.println("RTC lost power, setting time to compile time");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
SPI.begin(SPI_SCK_PIN, SPI_MISO_PIN, SPI_MOSI_PIN, SD_CS_PIN);
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD card init failed - check wiring/card");
while (true) delay(1000);
}
if (!SD.exists(LOG_FILENAME)) {
File f = SD.open(LOG_FILENAME, FILE_WRITE);
if (f) {
f.println("timestamp,temperature_C,humidity_percent");
f.close();
}
}
Serial.println("Logger ready");
}
void loop() {
if (millis() - lastLog < LOG_INTERVAL_MS) return;
lastLog = millis();
sensors_event_t humidity, temp;
aht.getEvent(&humidity, &temp);
DateTime now = rtc.now();
char timestamp[20];
snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d",
now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
File f = SD.open(LOG_FILENAME, FILE_WRITE);
if (f) {
f.printf("%s,%.2f,%.2f\n", timestamp, temp.temperature, humidity.relative_humidity);
f.close();
Serial.printf("Logged: %s, %.2f C, %.2f %%\n", timestamp, temp.temperature, humidity.relative_humidity);
} else {
Serial.println("Failed to open log file for append");
}
}Not sure about a step? Ask us