Готовый проект: логгер температуры на SD-карту с часами DS3231
Постановка задачи
Частая задача: измерять температуру в теплице, гараже или серверном шкафу с записью на карту, чтобы потом строить графики. Вариант «считать в Serial Monitor и переписывать руками» не живёт дольше вечера. Правильное решение стоит около 500 рублей: DS18B20, модуль MicroSD-карты и часы реального времени DS3231. Ниже — вся конструкция: таблица характеристик по паспортам, распиновка, рабочий код и ошибки, на которых новички его губят.
Часы здесь обязательны. Если писать только температуру, после чтения лога получится ломаная без оси времени, а после перезагрузки millis() обнулится. DS3231 хранит точное время на батарейке годами: точность ±2 ppm при 0…+40 °C — примерно минута ошибки за год.
Железо и характеристики по паспортам
В проекте три модуля, все разобраны на сайте по отдельности, ниже — только цифры, которые влияют на сборку.
| Параметр | Значение |
|---|---|
| DS18B20 — диапазон измерений | −55…+125 °C |
| DS18B20 — точность | ±0,5 °C (−10…+85 °C) |
| DS18B20 — разрешение / время преобразования | 12 бит, 0,0625 °C / до 750 мс |
| DS18B20 — питание | 3,0–5,5 В, подтяжка DQ 4,7 кОм |
| DS3231 — точность хода | ±2 ppm при 0…+40 °C (≈1 мин/год) |
| DS3231 — питание | VCC 2,3–5,5 В; батарейка CR2032 тип. 3,0 В |
| DS3231 — ток от батарейки | тип. 0,84 мкА (ход часов при отсутствии питания) |
| DS3231 — интерфейс | I2C до 400 кГц, адрес 0x68 |
| MicroSD-модуль — карты и файловая система | microSD до 2 ГБ, microSDHC до 32 ГБ; FAT16/FAT32 |
| MicroSD-модуль — питание и логика | 4,5–5,5 В (буфер 74LVC125A, стабилизатор AMS1117-3.3) |
| MicroSD-модуль — ток | от 0,2 мА в покое до 200 мА пик записи |
| Питание всей конструкции | 5 В от блока питания или powerbank |
Схема подключения
Плата — Arduino Uno. SD-модуль сидит на аппаратной SPI (MOSI D11, MISO D12, SCK D13, CS D4), DS3231 — на I2C (A4/A5), DS18B20 — на D2. С ESP32 схема та же по смыслу, различия ниже.
| Модуль / вывод | Arduino Uno | ESP32 |
|---|---|---|
| DS18B20 DQ (+ 4,7 кОм к питанию) | D2 | GPIO4 |
| DS3231 SDA / SCL | A4 / A5 | GPIO21 / GPIO22 |
| MicroSD CS | D4 | GPIO5 |
| MicroSD MOSI / MISO / SCK | D11 / D12 / D13 | GPIO23 / GPIO19 / GPIO18 |
| VCC SD-модуля | 5V | 5V (VIN) или 3V3-версия |
| VCC DS3231 | 5 В | 3,3 В |
| VCC DS18B20 | 5 В | 3,3 В |
У SD-модуля с буфером 74LVC125A на вход подаётся 5 В. Для ESP32 берут версию модуля без буфера или питают VCC от 3V3. Часы и датчик у ESP32 питаются от 3,3 В. У Uno всё питается от 5 В.
Код: логгер с расписанием
Библиотеки: SD (штатная), OneWire и DallasTemperature (Paul Stoffregen), RTClib (Adafruit). Код одинаков для Uno и ESP32, меняются только номера пинов.
#include <SPI.h>
#include <SD.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <RTClib.h>
const int PIN_DQ = 2; // DS18B20 (ESP32: 4)
const int PIN_CS = 4; // SD (ESP32: 5)
// Uno: SPI на D11/D12/D13; ESP32: GPIO23/19/18
OneWire oneWire(PIN_DQ);
DallasTemperature sensors(&oneWire);
RTC_DS3231 rtc;
const unsigned long PERIOD = 60000UL; // период записи, 60 с
unsigned long lastWrite = 0;
void setup() {
Serial.begin(9600); // ESP32: 115200
sensors.begin();
sensors.setResolution(12); // 0,0625 °C, до 750 мс
if (!SD.begin(PIN_CS)) { // карта не вставлена или CS не тот
Serial.println("SD error");
while (true) delay(1000);
}
if (!rtc.begin()) { // DS3231 не отвечает
Serial.println("RTC error");
while (true) delay(1000);
}
if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
File f = SD.open("LOG001.CSV", FILE_WRITE);
if (f) {
f.println("date;time;tempC");
f.close();
}
}
void loop() {
if (millis() - lastWrite < PERIOD) return;
lastWrite = millis();
sensors.requestTemperatures();
float t = sensors.getTempCByIndex(0); // первый датчик на шине
DateTime now = rtc.now(); // дата и время одним вызовом
char line[32];
snprintf(line, sizeof(line), "%04u-%02u-%02u;%02u:%02u:%02u;%.2f",
now.year(), now.month(), now.day(),
now.hour(), now.minute(), now.second(), t);
File f = SD.open("LOG001.CSV", FILE_WRITE); // дозапись в конец
if (!f) {
Serial.println("open failed");
return;
}
f.println(line);
f.close();
Serial.println(line);
}
Пары «считать-записать» у Arduino долгие: SD-запись до 200 мА, преобразование DS18B20 до 750 мс. В ESP32 то же делается через deep sleep: проснулся, прочитал, записал, уснул — средний ток падает до десятков микроампер, от powerbank логгер живёт неделями.
Частые ошибки
- Подают на SD-модуль 3,3 В от Uno. Стабилизатор AMS1117-3.3 требует входа выше выхода примерно на 1,1 В; с 3,3 В на входе карта получает меньше 3,3 В и не инициализируется. На Uno модуль кормят 5 В, на ESP32 — либо 3V3-версия, либо 5 В на VIN.
- Пишут с SD.begin() без проверки. Если карта не вставлена, CS в скетче не тот или карта больше 32 ГБ (exFAT), SD.begin() вернёт false, а код продолжит писать в никуда. Всегда проверяй возврат и выводи ошибку в Serial.
- Вешают на шину I2C DS3231 и другие модули без учёта адресов. DS3231 сидит на 0x68, EEPROM AT24C32 на плате — на 0x57, OLED SSD1306 — 0x3C: OLED-дисплей к этому логгеру подключается на ту же шину без конфликтов.
- Забывают rtc.adjust() при первом запуске. Без батарейки или после первого включения lostPower() вернёт true, и в лог пойдут 2000-01-01 00:00:00. Проверяй lostPower() в setup() и выставляй время сборки скетча.
- Имя файла 8.3 или слишком длинное. SD-библиотека понимает короткие имена, LOG001.CSV — безопасно; длинные имена на некоторых картах не открываются.
- Не закрывают файл. Файл закрывается f.close() после каждой строки, иначе данные из буфера не попадут на карту при сбое питания. Не используй журнал долгоживущим: открыл — записал — закрыл.
- Ждут от батарейки CR2032 питания логгера. Она держит только часы: 0,84 мкА на ход. Температуру и запись карты кормит основной источник 5 В.
Что дальше
Базовый вариант готов за вечер. Развитие: второй DS18B20 на ту же шину 1-Wire, запись через deep sleep для батарейного режима, выгрузка лога по Bluetooth HC-05. Для улицы берите водонепроницаемую версию DS18B20 — она разобрана в обзоре DS18B20.
Информация собрана из открытых источников и паспортов производителей и не является истиной в последней инстанции. Характеристики, распиновку и совместимость проверяйте по документации конкретной партии модуля перед покупкой и подключением.