Hola compañeros, estoy desarrollando un proyecto en el cual llevo tres semanas atascado sin poder terminarlo, he visto proyectos similares en este foro y en Youtube pero sus soluciones no sirven para mi proyecto. No sé si es cuestión de las librerías que estoy utilizando o si es que no lo estoy haciendo correctamente.
Mi proyecto consta de un ESP32, un RTC DS3231 y un módulo para tarjetas SD. Lo que necesito hacer es crear un archivo de texto en la micro SD y que en ese archivo se almacene la lectura del sensor junto con la hora y la fecha en la que se hizo la lectura.
El problema que tengo es que no consigo escribir en el archivo de texto la fecha y la hora en la que se hizo la lectura. Si alguien me puede ayudar le estaría realmente agradecido. Todavía estoy aprendiendo y ya no sé por dónde tirar, por lo que toda ayuda sería bienvenida... Muchas gracias de antemano.
#include "Arduino.h"
#include "uRTCLib.h"
#include "FS.h"
#include "SD.h"
#include <SPI.h>
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor de microsegundos a segundos */
#define TIME_TO_SLEEP 30
#define SD_CS 5
String datalog;
int Vresistor = 36; // SP pin which is the GPIO36 pin this is adc0
int Vrdata;
uRTCLib rtc;
File file;
#define SOFTWARE_VERSION "1.0"
#define DATE_FORMAT_LONG_MASK 0x01
#define DATE_FORMAT_AMERICAN 0x02
#define DATE_FORMAT_AMERICAN_LONG 0x03
#define DATE_FORMAT_EUROPEAN 0x04
#define DATE_FORMAT_EUROPEAN_LONG 0x05
void printRTC(uint8_t aDateFormatSpecifier = 0);
bool printRTCEveryPeriod(uint16_t aPeriodSeconds, uint8_t aDateFormatSpecifier = 0);
void printRTCDate(uint8_t aDateFormatSpecifier = 0);
void printRTCDateAmericanFormat(bool aPrintLongFormat);
void printRTCDateEuropeanFormat(bool aPrintLongFormat);
void printRTCDateISOFormat();
void printRTCTime(bool aPrintLongFormat = true, bool aDoRefresh = false);
void printRTCTemperature();
bool requestDateBySerialAndSet(void);
#if !defined(__AVR__) && ! defined(PROGMEM)
#define PROGMEM
#endif
//#define SPANISH_NAMES_FOR_DATE
#if defined(SPANISH_NAMES_FOR_DATE)
const char Monday[] PROGMEM= "Lunes";
const char Tuesday[] PROGMEM= "Martes";
const char Wednesday[] PROGMEM= "Miércoles";
const char Thursday[] PROGMEM= "Jueves";
const char Friday[] PROGMEM= "Viernes";
const char Saturday[] PROGMEM= "Sábado";
const char Sunday[] PROGMEM= "Domingo";
const char January[] PROGMEM= "Enero";
const char February[] PROGMEM= "Febrero";
const char March[] PROGMEM= "Marzo";
const char April[] PROGMEM= "Abril";
const char May[] PROGMEM= "Mayo";
const char June[] PROGMEM= "Junio";
const char July[] PROGMEM= "Julio";
const char August[] PROGMEM= "Agosto";
const char September[] PROGMEM= "Septiembre";
const char October[] PROGMEM= "Octubre";
const char November[] PROGMEM= "Noviembre";
const char December[] PROGMEM= "Diciembre";
#else
const char Monday[] PROGMEM= "Lunes";
const char Tuesday[] PROGMEM= "Martes";
const char Wednesday[] PROGMEM= "Miércoles";
const char Thursday[] PROGMEM= "Jueves";
const char Friday[] PROGMEM= "Viernes";
const char Saturday[] PROGMEM= "Sábado";
const char Sunday[] PROGMEM= "Domingo";
const char January[] PROGMEM= "Enero";
const char February[] PROGMEM= "Febrero";
const char March[] PROGMEM= "Marzo";
const char April[] PROGMEM= "Abril";
const char May[] PROGMEM= "Mayo";
const char June[] PROGMEM= "Junio";
const char July[] PROGMEM= "Julio";
const char August[] PROGMEM= "Agosto";
const char September[] PROGMEM= "Septiembre";
const char October[] PROGMEM= "Octubre";
const char November[] PROGMEM= "Noviembre";
const char December[] PROGMEM= "Diciembre";
#endif
const char* const sDayStrings[] PROGMEM = { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
#define DOW_MAX_STRING_SIZE 11
const char* const sMonthStrings[] PROGMEM = { January, February, March, April, May, June, July, August, September, October, November, December };
#define MONTH_MAX_STRING_SIZE 10
// FUNCIONES SISTEMA DE ARCHIVOS Y ALMACENAMIENTO DE DATOS EN LA SD
// Almacenar lecturas del sensor en la SD
void logSDCard() {
// Almacenar Fecha y hora en la SD
file.print(rtc.day());
file.print("/");
file.print(rtc.month());
file.print("/");
file.print(rtc.year());
file.print(" ");
file.print(rtc.hour());
file.print(":");
file.print(rtc.minute());
file.print(":");
file.print(rtc.second());
file.print(" ");
datalog = "Sensor 1: " + String(Vrdata) + "\n";
Serial.println(datalog);
appendFile(SD, "/DataLogger.txt", datalog.c_str());
}
// Crear archivos en la SD
void writeFile(fs::FS &fs, const char * path, const char * message) {
File file = fs.open(path, FILE_WRITE);
if(!file) {
return;
}
if(file.print(message)) {
Serial.println("Archivo creado con éxito");
} else {
Serial.println("Error: No se pudo crear el archivo");
}
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("Guardando lectura del sensor en el archivo: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file) {
Serial.println("ERROR: No se pudo guardar la lectura del sensor");
return;
}
if(file.print(message)) {
Serial.println("La lectura del sensor se guardó con éxito");
} else {
Serial.println("ERROR: No se pudo guardar la lectura del sensor");
}
file.close();
}
void ReadVresistor()
{
Vrdata = analogRead(Vresistor);
Serial.println(Vrdata);
}
// FUNCIONES RTC HORA Y FECHA FORMATEADAS
bool requestDateBySerialAndSet(void) {
uint8_t tSecond, tMinute, tHour, tDayOfMonth, tMonth, tYear;
char tInputBuffer[17];
Serial.println();
Serial.println(F("Introducir la hora en el formato: \"HH MM SS DD MM YY\""));
Serial.setTimeout(30000);
// read exactly 17 characters
size_t tReadLength = Serial.readBytes(tInputBuffer, 17);
if (tReadLength == 17 && tInputBuffer[14] == ' ') {
#ifdef AVR
sscanf_P(tInputBuffer, PSTR("%2hhu %2hhu %2hhu %2hhu %2hhu %2hhu"), &tHour, &tMinute, &tSecond, &tDayOfMonth, &tMonth, &tYear);
#else
sscanf(tInputBuffer, "%2hhu %2hhu %2hhu %2hhu %2hhu %2hhu", &tHour, &tMinute, &tSecond, &tDayOfMonth, &tMonth, &tYear);
#endif
// read newline etc.
while (Serial.available()) {
Serial.read();
}
Serial.setTimeout(1000);
Serial.println();
Serial.println(F("Introducir el día de la semana como un número entre 1 y 7 (Domingo-Sábado) - Timeout is 10 seconds"));
Serial.readBytes(tInputBuffer, 7);
if (tInputBuffer[0] > '0' && tInputBuffer[0] < '8') {
rtc.set(tSecond, tMinute, tHour, tInputBuffer[0] - '0', tDayOfMonth, tMonth, tYear);
Serial.print(F("Hora establecida a: "));
printRTC();
return true;
}
}
Serial.println(F("El RTC no se ha modificado."));
return false;
}
/*
* @return true if update/refresh happened
*/
bool printRTCEveryPeriod(uint16_t aPeriodSeconds, uint8_t aDateFormatSpecifier) {
static long sLastMillisOfRTCRead;
if (millis() - sLastMillisOfRTCRead >= (1000 * aPeriodSeconds)) {
sLastMillisOfRTCRead = millis();
rtc.refresh();
printRTC(aDateFormatSpecifier);
return true;
}
return false;
}
void printRTC(uint8_t aDateFormatSpecifier) {
rtc.refresh();
printRTCDate(aDateFormatSpecifier);
Serial.print(' ');
printRTCTime((aDateFormatSpecifier & DATE_FORMAT_LONG_MASK), false);
Serial.println();
}
void printRTCDateAmericanFormat(bool aPrintLongFormat) {
#if defined(__AVR__)
char tDateString[(2 * DOW_MAX_STRING_SIZE) + 1 + (2 * MONTH_MAX_STRING_SIZE) + 1 + 12];
#else
char tDateString[DOW_MAX_STRING_SIZE + MONTH_MAX_STRING_SIZE + 12];
#endif
if (aPrintLongFormat) {
#if defined(__AVR__)
// fist copy day of week
strcpy_P(&tDateString[sizeof(tDateString) - (DOW_MAX_STRING_SIZE + MONTH_MAX_STRING_SIZE) - 3],
(PGM_P) pgm_read_word(&sDayStrings[rtc.dayOfWeek() - 1]));
strcpy_P(&tDateString[sizeof(tDateString) - (MONTH_MAX_STRING_SIZE) - 2],
(PGM_P) pgm_read_word(&sMonthStrings[rtc.month() - 1]));
sprintf_P(tDateString, PSTR("%s, %s %2hhu, 20%2hhu"),
&tDateString[sizeof(tDateString) - (DOW_MAX_STRING_SIZE + MONTH_MAX_STRING_SIZE) - 3],
&tDateString[sizeof(tDateString) - (MONTH_MAX_STRING_SIZE) - 2], rtc.day(), rtc.year());
#else
sprintf(tDateString, "%s, %s %2u, 20%2u", sDayStrings[rtc.dayOfWeek() - 1],
sMonthStrings[rtc.month() - 1], rtc.day(), rtc.year());
#endif
} else {
sprintf_P(tDateString, PSTR("%02u/%02u/20%2u"), rtc.month(), rtc.day(), rtc.year());
}
Serial.print(tDateString);
}
void printRTCDateEuropeanFormat(bool aPrintLongFormat) {
#if defined(__AVR__)
char tDateString[(2 * DOW_MAX_STRING_SIZE) + 1 + (2 * MONTH_MAX_STRING_SIZE) + 1 + 12];
#else
char tDateString[DOW_MAX_STRING_SIZE + MONTH_MAX_STRING_SIZE + 12];
#endif
if (aPrintLongFormat) {
#if defined(__AVR__)
// fist copy day of week
strcpy_P(&tDateString[sizeof(tDateString) - (DOW_MAX_STRING_SIZE + MONTH_MAX_STRING_SIZE) - 3],
(PGM_P) pgm_read_word(&sDayStrings[rtc.dayOfWeek() - 1]));
strcpy_P(&tDateString[sizeof(tDateString) - (MONTH_MAX_STRING_SIZE) - 2],
(PGM_P) pgm_read_word(&sMonthStrings[rtc.month() - 1]));
sprintf_P(tDateString, PSTR("%s, %2hhu. %s 20%2hhu"),
&tDateString[sizeof(tDateString) - (DOW_MAX_STRING_SIZE + MONTH_MAX_STRING_SIZE) - 3], rtc.day(),
&tDateString[sizeof(tDateString) - (MONTH_MAX_STRING_SIZE) - 2], rtc.year());
#else
sprintf(tDateString, "%s, %2u/%s/20%2u", sDayStrings[rtc.dayOfWeek() - 1], rtc.day(),
sMonthStrings[rtc.month() - 1], rtc.year());
#endif
} else {
sprintf_P(tDateString, PSTR("%02u/%02u/20%2u"), rtc.day(), rtc.month(), rtc.year());
}
Serial.print(tDateString);
}
void printRTCDateISOFormat() {
char tDateString[11];
#if defined(__AVR__)
sprintf_P(tDateString, PSTR("%02hhu/%02hhu/20%2hhu"), rtc.day(), rtc.month(), rtc.year());
#else
sprintf(tDateString, "%02u/%02u/20%2u", rtc.day(), rtc.month(), rtc.year());
#endif
Serial.print(tDateString);
}
void printRTCDate(uint8_t aDateFormatSpecifier) {
if (aDateFormatSpecifier & DATE_FORMAT_AMERICAN) {
printRTCDateAmericanFormat((aDateFormatSpecifier & DATE_FORMAT_LONG_MASK));
} else if (aDateFormatSpecifier & DATE_FORMAT_EUROPEAN) {
printRTCDateEuropeanFormat((aDateFormatSpecifier & DATE_FORMAT_LONG_MASK));
} else {
// Formato ISO
printRTCDateISOFormat();
}
}
void printRTCTemperature() {
Serial.print(rtc.temp() / 100);
Serial.print('.');
Serial.print(rtc.temp() - ((rtc.temp() / 100) * 100));
}
void printRTCTime(bool aPrintLongFormat, bool aDoRefresh) {
if (aDoRefresh) {
rtc.refresh();
}
char tTimeString[9];
#if defined(__AVR__)
if (aPrintLongFormat) {
sprintf_P(tTimeString, PSTR("%02hhu:%02hhu:%02hhu"), rtc.hour(), rtc.minute(), rtc.second());
} else {
sprintf_P(tTimeString, PSTR("%02u:%02u"), rtc.hour(), rtc.minute());
}
#else
if (aPrintLongFormat) {
sprintf(tTimeString, "%02u:%02u:%02u", rtc.hour(), rtc.minute(), rtc.second());
} else {
sprintf(tTimeString, "%02u:%02u", rtc.hour(), rtc.minute());
}
#endif
Serial.print(tTimeString);
}
void setup() {
Serial.begin(115200);
// Inicializar SD card
SD.begin(SD_CS);
while (!Serial);
Serial.println(F("START " __FILE__ "\r\nVersion " SOFTWARE_VERSION " from " __DATE__));
#ifdef ARDUINO_ARCH_ESP8266
URTCLIB_WIRE.begin(21, 22); // D3 and D4 on ESP8266
#else
URTCLIB_WIRE.begin();
#endif
rtc.set_rtc_address(0x68);
rtc.set_model(URTCLIB_MODEL_DS3231);
// Establecer fecha y hora en el RTC -> RTCLib::set(byte segundos, byte minutos, byte horas, byte díaDeLaSemana, byte díaDelMes, byte mes, byte año)
// Compilar 1 vez para establecer fecha en el RTC, comentar la línea del "rtc.set" y recompilar
//rtc.set(0, 22, 12, 3, 11, 8, 21); // 11/08/2021 12:22:00
if (rtc.lostPower() || rtc.year() < 19) {
if (requestDateBySerialAndSet()) {
rtc.lostPowerClear();
}
}
// Montar SD y crear sistema de archivos
if(!SD.begin(SD_CS)) {
Serial.println("No se pudo montar la SD");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE) {
Serial.println("No se encuentra ninguna SD");
return;
}
Serial.println("Inicializando la SD...");
if (!SD.begin(SD_CS)) {
Serial.println("ERROR - Inicialización de la SD fallida!");
return; // init failed
}
File file = SD.open("/DataLogger.txt");
if(!file) {
Serial.println("El archivo no existe...");
Serial.println("Creando archivo...");
writeFile(SD, "/DataLogger.txt", "Neodomo DataLogger SD \r\n");
}
else {
Serial.println("El archivo ya existe");
}
file.close();
printRTC(DATE_FORMAT_EUROPEAN_LONG);
delay(300);
ReadVresistor();
logSDCard();
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
esp_deep_sleep_start(); // sleep
}
void loop() {
}