ESP32: Логирование температуры на MicroSD карту
Этот проект показывает, как логировать данные с метками времени на microSD карту с помощью ESP32. В качестве примера мы будем записывать показания температуры с датчика DS18B20 каждые 10 минут. ESP32 будет находиться в режиме глубокого сна между каждым измерением, а дату и время будет запрашивать с помощью протокола сетевого времени (NTP).
Вам также может понравиться: ESP32: How to Log Data (10 Different Ways)
Обзор проекта
Прежде чем приступить, давайте выделим основные особенности проекта:
ESP32 считывает температуру с помощью датчика температуры DS18B20.
После получения температуры он отправляет запрос к NTP (Network Time Protocol) серверу для получения даты и времени. Поэтому ESP32 необходимо Wi-Fi соединение.
Данные (температура и метка времени) записываются на microSD карту. Для записи данных на microSD карту мы используем модуль microSD карт.
После выполнения этих задач ESP32 засыпает на 10 минут.
ESP32 просыпается и повторяет процесс.
Необходимые компоненты
Вот список компонентов, необходимых для сборки этого проекта (нажмите на ссылки ниже, чтобы найти лучшую цену на Maker Advisor):
Вы можете использовать ссылки выше или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Подготовка модуля MicroSD карт
Для сохранения данных на microSD карту с ESP32 мы используем следующий модуль microSD карт, который взаимодействует с ESP32 по протоколу связи SPI.
Связанный контент: ESP32: Guide for MicroSD Card Module using Arduino IDE
Форматирование microSD карты
При использовании microSD карты с ESP32 её необходимо сначала отформатировать. Следуйте приведённым ниже инструкциям для форматирования вашей microSD карты.
1. Вставьте microSD карту в компьютер. Перейдите в Мой компьютер и щёлкните правой кнопкой мыши по SD карте. Выберите Форматировать, как показано на рисунке ниже.
2. Появится новое окно. Выберите FAT32, нажмите Начать для запуска процесса форматирования и следуйте инструкциям на экране.
Схема подключения
Следуйте приведённой ниже принципиальной схеме для сборки цепи данного проекта.
Вы также можете использовать следующую таблицу в качестве справки для подключения модуля microSD карт:
Модуль MicroSD карт |
ESP32 |
|---|---|
3V3 |
3V3 |
CS |
GPIO 5 |
MOSI |
GPIO 23 |
CLK |
GPIO 18 |
MISO |
GPIO 19 |
GND |
GND |
На следующем изображении показано, как должна выглядеть ваша схема:
Подготовка Arduino IDE
Существует дополнение для Arduino IDE, которое позволяет программировать ESP32, используя Arduino IDE и его язык программирования. Следуйте приведённому ниже руководству, чтобы подготовить вашу Arduino IDE для работы с ESP32, если вы ещё этого не сделали.
Установка библиотек
Перед загрузкой кода вам необходимо установить несколько библиотек в Arduino IDE. Библиотеку OneWire от Paul Stoffregen и библиотеку Dallas Temperature, чтобы вы могли использовать датчик DS18B20. Вам также необходимо установить библиотеку NTPClient, форк от Taranais, для отправки запросов к NTP серверу.
Следуйте приведённым ниже шагам для установки этих библиотек в вашей Arduino IDE:
Библиотека OneWire
В Arduino IDE перейдите в Sketch > Include Library > Manage Libraries.
Найдите OneWire.
Установите библиотеку OneWire, как показано на рисунке ниже.
Библиотека Dallas Temperature
В Arduino IDE перейдите в Sketch > Include Library > Manage Libraries.
Найдите DallasTemperature.
Установите библиотеку DallasTemperature от Miles Burton.
Библиотека NTPClient
ВАЖНО: мы не используем стандартную библиотеку NTPClient. Для прохождения этого руководства вам необходимо установить библиотеку, которую мы рекомендуем, используя следующие шаги.
Мы будем использовать библиотеку NTPClient, форк от Taranais. Следуйте приведённым ниже шагам для установки этой библиотеки в вашей Arduino IDE:
Нажмите здесь, чтобы скачать библиотеку NTP Client. У вас должен появиться .zip файл в папке Downloads.
В вашей Arduino IDE перейдите в Sketch > Include Library > Add .ZIP library…
Выберите .ZIP файл библиотеки, которую вы только что скачали.
Библиотека будет установлена через несколько секунд.
Загрузка кода
Вот код, который вам нужно загрузить на ваш ESP32. Перед загрузкой вам необходимо изменить код, указав ваши сетевые учётные данные (SSID и пароль). Продолжайте чтение, чтобы узнать, как работает код.
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
// Libraries for SD card
#include "FS.h"
#include "SD.h"
#include <SPI.h>
//DS18B20 libraries
#include <OneWire.h>
#include <DallasTemperature.h>
// Libraries to get time from NTP Server
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// Define deep sleep options
uint64_t uS_TO_S_FACTOR = 1000000; // Conversion factor for micro seconds to seconds
// Sleep for 10 minutes = 600 seconds
uint64_t TIME_TO_SLEEP = 600;
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Define CS pin for the SD card module
#define SD_CS 5
// Save reading number on RTC memory
RTC_DATA_ATTR int readingID = 0;
String dataMessage;
// Data wire is connected to ESP32 GPIO 21
#define ONE_WIRE_BUS 21
// Setup a oneWire instance to communicate with a OneWire device
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
// Temperature Sensor variables
float temperature;
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables to save date and time
String formattedDate;
String dayStamp;
String timeStamp;
void setup() {
// Start serial communication for debugging purposes
Serial.begin(115200);
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
// Initialize a NTPClient to get time
timeClient.begin();
// Set offset time in seconds to adjust for your timezone, for example:
// GMT +1 = 3600
// GMT +8 = 28800
// GMT -1 = -3600
// GMT 0 = 0
timeClient.setTimeOffset(3600);
// Initialize SD card
SD.begin(SD_CS);
if(!SD.begin(SD_CS)) {
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE) {
Serial.println("No SD card attached");
return;
}
Serial.println("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("ERROR - SD card initialization failed!");
return; // init failed
}
// If the data.txt file doesn't exist
// Create a file on the SD card and write the data labels
File file = SD.open("/data.txt");
if(!file) {
Serial.println("File doens't exist");
Serial.println("Creating file...");
writeFile(SD, "/data.txt", "Reading ID, Date, Hour, Temperature \r\n");
}
else {
Serial.println("File already exists");
}
file.close();
// Enable Timer wake_up
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
// Start the DallasTemperature library
sensors.begin();
getReadings();
getTimeStamp();
logSDCard();
// Increment readingID on every new reading
readingID++;
// Start deep sleep
Serial.println("DONE! Going to sleep now.");
esp_deep_sleep_start();
}
void loop() {
// The ESP32 will be in deep sleep
// it never reaches the loop()
}
// Function to get temperature
void getReadings(){
sensors.requestTemperatures();
temperature = sensors.getTempCByIndex(0); // Temperature in Celsius
//temperature = sensors.getTempFByIndex(0); // Temperature in Fahrenheit
Serial.print("Temperature: ");
Serial.println(temperature);
}
// Function to get date and time from NTPClient
void getTimeStamp() {
while(!timeClient.update()) {
timeClient.forceUpdate();
}
// The formattedDate comes with the following format:
// 2018-05-28T16:00:13Z
// We need to extract date and time
formattedDate = timeClient.getFormattedDate();
Serial.println(formattedDate);
// Extract date
int splitT = formattedDate.indexOf("T");
dayStamp = formattedDate.substring(0, splitT);
Serial.println(dayStamp);
// Extract time
timeStamp = formattedDate.substring(splitT+1, formattedDate.length()-1);
Serial.println(timeStamp);
}
// Write the sensor readings on the SD card
void logSDCard() {
dataMessage = String(readingID) + "," + String(dayStamp) + "," + String(timeStamp) + "," +
String(temperature) + "\r\n";
Serial.print("Save data: ");
Serial.println(dataMessage);
appendFile(SD, "/data.txt", dataMessage.c_str());
}
// Write to the SD card (DON'T MODIFY THIS FUNCTION)
void writeFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file) {
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
// Append data to the SD card (DON'T MODIFY THIS FUNCTION)
void appendFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file) {
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
Как работает код
В этом примере ESP32 находится в режиме глубокого сна между каждым измерением. В режиме глубокого сна весь ваш код должен находиться в функции setup(), потому что ESP32 никогда не достигает loop().
Импорт библиотек
Сначала вы импортируете необходимые библиотеки для модуля microSD карт:
#include "FS.h"
#include "SD.h"
#include <SPI.h>
Импортируйте эти библиотеки для работы с датчиком температуры DS18B20.
#include <OneWire.h>
#include <DallasTemperature.h>
Следующие библиотеки позволяют запрашивать дату и время с NTP сервера.
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
Настройка времени глубокого сна
В этом примере используется коэффициент преобразования из микросекунд в секунды, чтобы вы могли задать время сна в переменной TIME_TO_SLEEP в секундах.
В данном случае мы настраиваем ESP32 на засыпание на 10 минут (600 секунд). Если вы хотите, чтобы ESP32 спал другой период времени, вам просто нужно ввести количество секунд глубокого сна в переменную TIME_TO_SLEEP.
// Define deep sleep options
uint64_t uS_TO_S_FACTOR = 1000000; // Conversion factor for micro seconds to seconds
// Sleep for 10 minutes = 600 seconds
uint64_t TIME_TO_SLEEP = 600;
Настройка сетевых учётных данных
Введите ваши сетевые учётные данные в следующих переменных, чтобы ESP32 мог подключиться к вашей локальной сети.
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Инициализация датчиков и переменных
Далее определите пин CS для модуля microSD карт. В данном случае он назначен на GPIO 5.
#define SD_CS 5
Создайте переменную readingID для хранения идентификатора измерения. Это способ упорядочить ваши показания. Чтобы сохранить значение переменной во время глубокого сна, мы можем сохранить его в RTC памяти. Для сохранения данных в RTC памяти вам просто нужно добавить RTC_DATA_ATTR перед определением переменной.
// Save reading number on RTC memory
RTC_DATA_ATTR int readingID = 0;
Создайте строковую переменную для хранения данных, которые будут сохранены на microSD карту.
String dataMessage;
Далее создайте экземпляры, необходимые для датчика температуры. Датчик температуры подключён к GPIO 21.
// Data wire is connected to ESP32 GPIO21
#define ONE_WIRE_BUS 21
// Setup a oneWire instance to communicate with a OneWire device
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
Затем создайте переменную типа float для хранения температуры, полученной от датчика DS18B20.
float temperature;
Следующие две строки определяют NTPClient для запроса даты и времени с NTP сервера.
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
Затем инициализируйте строковые переменные для сохранения даты и времени.
String formattedDate;
String dayStamp;
String timeStamp;
setup()
При использовании глубокого сна с ESP32 весь код должен находиться внутри функции setup(), потому что ESP32 никогда не достигает loop().
Подключение к Wi-Fi
Следующий фрагмент кода подключается к Wi-Fi сети. Вам необходимо подключиться к Wi-Fi для запроса даты и времени с NTP сервера.
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Инициализация NTP клиента
Далее инициализируйте NTP клиент для получения даты и времени с NTP сервера.
timeClient.begin();
Вы можете использовать метод setTimeOffset(<time>) для настройки времени под ваш часовой пояс.
timeClient.setTimeOffset(3600);
Вот несколько примеров для различных часовых поясов:
GMT +1 = 3600
GMT +8 = 28800
GMT -1 = -3600
GMT 0 = 0
Инициализация модуля microSD карт
Затем инициализируйте microSD карту. Следующие условия if проверяют, правильно ли подключена microSD карта.
SD.begin(SD_CS);
if(!SD.begin(SD_CS)) {
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE) {
Serial.println("No SD card attached");
return;
}
Serial.println("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("ERROR - SD card initialization failed!");
return; // init failed
}
Затем попробуйте открыть файл data.txt на microSD карте.
File file = SD.open("/data.txt");
Если этот файл не существует, нам нужно создать его и записать заголовок для файла .txt.
writeFile(SD, "/data.txt", "Reading ID, Date, Hour, Temperature \r\n");
Если файл уже существует, код продолжает выполнение.
else {
Serial.println("File already exists");
}
Наконец, мы закрываем файл.
file.close();
Включение пробуждения по таймеру
Затем вы включаете пробуждение по таймеру с временем, которое вы определили ранее в переменной TIME_TO_SLEEP.
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Инициализация библиотеки для DS18B20
Далее вы инициализируете библиотеку для датчика температуры DS18B20.
sensors.begin();
Получение показаний и логирование данных
После инициализации всего мы можем получить показания, метку времени и записать всё на microSD карту.
Чтобы сделать код более понятным, мы создали следующие функции:
getReadings(): считывает температуру с датчика температуры DS18B20;
getTimeStamp(): получает дату и время с NTP сервера;
logSDcard(): записывает вышеуказанные данные на microSD карту.
После выполнения этих задач мы увеличиваем readingID.
readingID++;
Наконец, ESP32 переходит в глубокий сон.
esp_deep_sleep_start();
getReadings()
Давайте посмотрим на функцию getReadings(). Эта функция просто считывает температуру с датчика температуры DS18B20.
sensors.requestTemperatures();
temperature = sensors.getTempCByIndex(0); // Temperature in Celsius
По умолчанию код получает температуру в градусах Цельсия. Вы можете раскомментировать следующую строку и закомментировать предыдущую, чтобы получить температуру в градусах Фаренгейта.
//temperature = sensors.getTempFByIndex(0); // Temperature in Fahrenheit
getTimeStamp()
Функция getTimeStamp() получает дату и время. Следующие строки обеспечивают получение корректной даты и времени:
while(!timeClient.update()) {
timeClient.forceUpdate();
}
Иногда NTPClient возвращает 1970 год. Чтобы этого не происходило, мы принудительно обновляем данные.
Затем преобразуйте дату и время в читаемый формат с помощью метода getFormattedDate():
formattedDate = timeClient.getFormattedDate();
Дата и время возвращаются в следующем формате:
2018-04-30T16:00:13Z
Поэтому нам нужно разделить эту строку, чтобы получить дату и время по отдельности. Вот что мы делаем здесь:
// Extract date
int splitT = formattedDate.indexOf("T");
dayStamp = formattedDate.substring(0, splitT);
Serial.println(dayStamp);
// Extract time
timeStamp = formattedDate.substring(splitT+1, formattedDate.length()-1);
Serial.println(timeStamp);
Дата сохраняется в переменной dayStamp, а время – в переменной timeStamp.
logSDCard()
Функция logSDCard() объединяет всю информацию в строковой переменной dataMessage. Каждое измерение разделяется запятыми.
dataMessage = String(readingID) + "," + String(dayStamp) + "," + String(timeStamp) + "," + String(temperature) + "\r\n";
Примечание: \r\n в конце переменной dataMessage обеспечивает запись следующего измерения на новой строке.
Затем с помощью следующей строки мы записываем всю информацию в файл data.txt на microSD карте.
appendFile(SD, "/data.txt", dataMessage.c_str());
Примечание: функция appendFile() принимает только переменные типа const char для сообщения. Поэтому используйте метод c_str() для преобразования переменной dataMessage.
writeFile() и appendFile()
Последние две функции: writeFile() и appendFile() используются для записи и добавления данных на microSD карту. Они взяты из примеров библиотеки SD карт, и вам не следует их изменять.
Чтобы попробовать другие примеры работы с microSD картой, перейдите в File > Examples > SD(esp32).
Загрузка кода на плату
Теперь загрузите код на ваш ESP32. Убедитесь, что у вас выбрана правильная плата и COM порт.
Демонстрация
Откройте Serial Monitor со скоростью передачи 115200 бод.
Нажмите кнопку Enable на ESP32 и проверьте, что всё работает правильно (ESP32 подключён к вашей локальной сети, и microSD карта правильно подключена).
Примечание: Если всё подключено правильно, но вы продолжаете получать ошибку инициализации SD карты, питание модуля microSD карты от 5V может решить проблему.
Дайте ESP32 поработать несколько часов, чтобы проверить, что всё работает как ожидается. После периода тестирования извлеките microSD карту и вставьте её в компьютер. На microSD карте должен быть файл data.txt.
Вы можете скопировать содержимое файла в таблицу, например, в Google Sheets, а затем разделить данные по запятым. Для разделения данных по запятым выделите столбец с вашими данными, затем перейдите в Data > Split text to columns… Затем вы можете построить графики для анализа данных.
Заключение
В этом руководстве вы научились логировать данные на microSD карту с помощью ESP32. Мы также показали вам, как считывать температуру с датчика температуры DS18B20 и как запрашивать время с NTP сервера.
Вы можете применить концепции из этого руководства в ваших собственных проектах. Вам также могут понравиться:
Вам также может быть интересно прочитать другие статьи, связанные с ESP32:
Altimeter Datalogger: ESP32 with BMP388, MicroSD Card Storage and OLED Display
ESP32 Datalogger: Download Data File via Web Server (Arduino IDE)
ESP32 Datalogging to Google Sheets (using Google Service Account)