Progetto di un Data Logger con microSD e microcontrollore ESP32 – Parte 3

In questa terza parte del progetto di un Data Logger descriveremo dettagliatamente il codice del progetto e lo caricheremo nell’ESP32. Realizzeremo il prototipo e ne testeremo il funzionamento con la visualizzazione dei dati della temperatura ambientale con data e ora memorizzati nella scheda microSD rilevati in un determinato periodo di monitoraggio.

Descrizione del codice

In sostanza, in questo progetto di esempio, l’ESP32 effettua una lettura della temperatura ogni 10 minuti, i cui valori vengono registrati su una scheda di memoria microSD insieme alla data e ora di registrazione. Tra una lettura e l’altra che avviene ogni 10 minuti, l’ESP32 viene posto in modalità deep sleep durante la quale il codice è bloccato nella funzione setup(), quindi non esegue la funzione loop(). Trascorso l’intervallo di tempo di 10 minuti, l’ESP32 si risveglia dal deep sleep e riprende la sua attività di lettura e archiviazione della temperatura. Di seguito viene fatta una dettagliata descrizione del funzionamento del codice il cui listato completo è stato riportato nel precedente articolo “Progetto di un Data Logger con microSD e microcontrollore ESP32 - Parte 2”.

Le inizializzazioni

Il codice inizia con l’importazione delle librerie:

Librerie della scheda microSD:
// Libraries for SD card
#include "FS.h"
#include "SD.h"
#include <SPI.h>

Librerie del sensore di temperatura DS18B20:
//DS18B20 libraries
#include <OneWire.h>
#include <DallasTemperature.h>

Librerie per ricevere data e ora dal server NTP:
// Libraries to get time from NTP Server
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

Per l’impostazione della durata del deep sleep si utilizza un fattore di conversione da microsecondi a secondi, in modo da impostare il tempo di sleep in secondi nella variabile “TIME_TO_SLEEP”.
In questo progetto, l'ESP32 viene impostato per andare in sleep per 10 minuti (600 secondi). Se si desidera che l’ESP32 resti in deep sleep per un periodo di tempo diverso, basta inserire il relativo numero di secondi nella variabile 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;

Prima di caricare il codice nell’ESP32 si devono inserire le credenziali SSID e PASSWORD di accesso alla rete Wi-Fi:
// Replace with your network credentials
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

Viene definito il pin GPIO05 dell’interfaccia SPI dell’ESP32 che attiva/disattiva la scheda microSD:
// Define CS pin for the SD card module
#define SD_CS 5

Viene creata la variabile “readingID” per contenere l'identificativo (ID) della lettura, ossia il numero di posizione della lettura in modo di organizzare le letture.
Per salvare un valore di ID in una variabile durante il deep sleep, è possibile salvarlo nella memoria dell'RTC aggiungendo RTC_DATA_ATTR prima della definizione della variabile:
// Save reading number on RTC memory
RTC_DATA_ATTR int readingID = 0;

Viene creata una variabile Stringa per contenere i dati da salvare sulla scheda microSD:
String dataMessage;

Viene definito il pin GPIO21 dell’ESP32 per acquisire i dati dal sensore di temperatura, quindi sono create le istanze necessarie per la comunicazione con il protocollo One Wire del sensore di temperatura DS18B20 con l’ESP32… 
// 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);
… e una variabile float per contenere il valore di temperatura rilevata dal sensore DS18B20:
// Temperature Sensor variables
float temperature;

Le due righe seguenti definiscono una richiesta client NTPC di data e ora da un server NTP:
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

Quindi, si inizializzano le variabili Stringa per salvare la data e l'ora:
// Variables to save date and time
String formattedDate;
String dayStamp;
String timeStamp;


La funzione setup()

Per richiedere data e ora al server NTP è necessario connettersi alla rete Wi-Fi e per questo viene utilizzata la seguente sezione di codice: 
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.");

Successivamente si inizializza il client NTP per ottenere data e ora da un server NTP:
// Initialize a NTPClient to get time
timeClient.begin();

È possibile utilizzare il metodo setTimeOffset(<time>) per regolare l'ora per il proprio fuso orario…
timeClient.setTimeOffset(3600);

… decommentando uno dei seguenti fusi:
// Set offset time in seconds to adjust for your timezone, for example:
// GMT +1 = 3600
// GMT +8 = 28800
// GMT -1 = -3600
// GMT 0 = 0


Con le seguenti righe di codice si inizializza la scheda microSD. Poi, con le istruzioni “if” si controlla se la scheda microSD è collegata correttamente:
// 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
}

Quindi, prova ad aprire il file “data.txt” sulla scheda microSD…
// 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");

… e se quel file non esiste, occorre crearlo e scrivere l'intestazione del file .txt:
if(!file) {
Serial.println("File doens't exist");
Serial.println("Creating file...");
writeFile(SD, "/data.txt", "Reading ID, Date, Hour, Temperature \r\n");
}

…se il file esiste già, il codice continua:
else {
Serial.println("File already exists"); 
}

… infine chiude il file:
file.close();

Viene poi abilitato il wake-up del timer già definito in precedenza nella variabile “TIME_TO_SLEEP”:
// Enable Timer wake_up
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

Successivamente, viene inizializzata la libreria del sensore di temperatura DS18B20:
// Start the DallasTemperature library
sensors.begin();

Dopo le inizializzazioni, si procede alla registrazione dei dati (data logging) delle letture e del timestamp nella scheda microSD:
getReadings();
getTimeStamp();
logSDCard();

Completate queste attività, viene incrementata la variabile readingID:
// Increment readingID on every new reading
readingID++;

Infine, l’ESP32 entra in deep sleep:
// Start deep sleep
Serial.println("DONE! Going to sleep now.");
esp_deep_sleep_start(); 
}


La funzione loop

Il codice non avvia la funzione loop finchè l’ESP32 è in deep sleep:
{
// The ESP32 will be in deep sleep
// it never reaches the loop()
}

La funzione getReading()

Questa funzione esegue la lettura della temperatura dal sensore di temperatura DS18B20.

Per default, il codice rileva la temperatura in gradi Celsius, ma è possibile decommentare la riga successiva e commentare la precedente per ottenere la temperatura in Fahrenheit:
sensors.requestTemperatures(); 
temperature = sensors.getTempCByIndex(0); // Temperature in Celsius
//temperature = sensors.getTempFByIndex(0); // Temperature in Fahrenheit


La funzione getTimeStamp()

La funzione getTimeStamp() ottiene la data e l'ora dal server NTP:
while(!timeClient.update()) {
timeClient.forceUpdate();
}
La data e l'ora sono convertite in un formato leggibile con il metodo getFormattedDate():
formattedDate = timeClient.getFormattedDate();

La stringa ottenuta contenente data e ora viene suddivisa per ottenere data e ora separatamente. La data viene salvata nella variabile “dayStamp” e l'ora nella variabile “timeStamp”:
// 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);

 [...]

ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 2195 parole ed è riservato agli ABBONATI. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici che potrai leggere in formato PDF per un anno. ABBONATI ORA, è semplice e sicuro.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend