Muy buenas. Necesito ayuda, porqué después de realizar el código de programado de una estación meteorológica (incluye sensores de temperatura, presión, una placa fotovoltaica, y un anemómetro que mide a través de pulsos), me he encontrado con dos principales problemas a la hora de guardar los datos.
El código cada 10 segundos toma datos de cada una de las sondas, y a los 2 minutos, calcula un promedio, que escribe en la tarjeta SD junto con la hora y fecha de la toma de los datos, o eso es lo que debería hacer.
A través del monitor serial puedo ver como todas las sondas están recopilando información correctamente, pero cuando toca hacer el guardado de datos, se presenta un problema: que en la tarjeta solo hay impreso el nombre del fichero (que es el mes, día, hora y minuto.txt), y nada más, ninguno de los datos que he mandado que se guardaran.
El segundo problema es que de vez en cuando, el reloj no toma bien la hora, y marca que nos encontramos en el día 1 de Enero del 2000, y a pesar de que reviso que el cableado esté dispuesto correctamente, se corrige aparentemente de manera aleatoria.
Hay que tener en cuenta que en el código cada 50 guardados de información en la tarjeta SD, hago que la placa Arduino se resetee y cree un nuevo archivo de datos, como medida desesperada para ver si puedo salvar algo...
Alguien podría ayudarme, ¿por favor?
Muchísimas gracias,
El código es el siguiente:
#include <SD.h> //Incluimos la librería para trabajar con tarjetas SD
#include <SPI.h> //Incluimos la librería para la comunicación SPI
#include <Wire.h>
#include <RTClib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Adafruit_BMP085.h>
RTC_DS3231 rtc;
Adafruit_BMP085 bmp;
const int csPin = 53; //Pin 53 en MEGA2560. 4 o 9 en Arduino UNO. ¡No conectar NADA al pin 10!!!
const int misoPin = 50; //MISO pin para MEGA256
const int placaPin = A1; //Pin analógico para la lectura de la tensión de la placa
const int tempPin = 2;
const int anemPin = 3; //Pin digital para contar los pulsos que envía el anemometro
const int greenLEDPin=A3;
const int redLEDPin=A2;
//Rojo: 5 seg encendido si no inicia la SD en el setup;
//Rojo o Verde: 3 parpadeos al iniciar la tarjeta en el setup y crear el fichero de txtFilename.txt;
//Verde: Un parpadeo de 150ms después de cada lectura a los 10 segundos
//Rojo o Verde: 1 parpadeo de 2 segundos depués de grabar el promedio en la tarjeta;
//Rojo y Verde 2 segundos ON después de xx iteraciones, antes de resetear la tarjeta y crear un nuevo TXT
int txtLinesCounter = 0;
///////PARÁMETROS AJUSTABLES POR EL PROGRAMADOR///////
const int recordTime = 10000; //Tiempo para que se repitan las mediciones en milisegundos (10 segundos = 10000)
const int averageTime = 120000; //Tiempo para que se hagan los promedios en milisegundos (2 minutos = 120000)
const int anemTime = 5; //Intérvalo de muestreo del anemómetro en segundos
//const int delayTime = 2000; //Delay de descanso después de las repeticiones if (Esto ha sido puesto para que cuando no se cumplan los tiempos de mediciones la placa 'descanse' antes de continuar)
const int txtMaxLines = 50;
//Variable para almacenar los datos como string
String dataStringHora;
String dataStringPlaca;
String dataStringTemp;
String dataStringPres;
String dataStringTemp2;
String dataStringAnem;
String fecha;
String hora;
char txtFilename[13]; // Nombre del fichero TXT que se crea después de xx lecturas.
char dateString[22]; // Variable para almacenar los datos de fecha como string
//Variables Placa Fotovoltaica
float v1 = 0;
float mA = 0;
float totalmVolt = 0;
float totalmAmp = 0;
float averagemVolt = 0;
float averagemAmp = 0;
//Variables Sensor Temperatura
OneWire oneWire(tempPin);
DallasTemperature sensors(&oneWire);
float tempCelsius = 0;
float totalTemp = 0;
float averageTemp = 0;
//Variables sonda barométrica
float presion = 0;
float totalPres = 0;
float averagePres = 0;
//Temperatura sonda bar
float temp2 = 0;
float totalTemp2 = 0;
float averageTemp2 = 0;
//Variables Anemómetro
int interruptCounter = 0;
float windSpeed = 0;
float totalWindSpeed = 0;
float averageWindSpeed = 0;
//Variables de la función millis()
unsigned long currentMillis = 0;
int measures = 0;
unsigned long lastMeasurementTime = 0;
unsigned long lastAverageTime = 0;
File dataFile = SD.open(txtFilename, FILE_WRITE);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
sensors.begin();
Wire.begin();
//Definición de pines:
pinMode(placaPin, INPUT);
pinMode(greenLEDPin,OUTPUT);
pinMode(anemPin, INPUT_PULLUP);
pinMode(redLEDPin,OUTPUT);
pinMode(csPin, OUTPUT); //Para evitar problemas en la SD lo definimos como output
pinMode(misoPin, OUTPUT); //Para evitar problemas en la SD lo definimos como output
pinMode(10, OUTPUT); //Para evitar problemas en la SD lo definimos como output y no conectamos nada a el PIN 10 (Paul McWorther Lesson 21)
//Comunicación con el reloj RTC
if (!rtc.begin()) {
Serial.println (F("Error al iniciar el reloj RTC_DS3231"));
showErrorAndReset();
}
Serial.println("Reloj RTC inicializado");
//Comunicación con la SD
if (!SD.begin(csPin)) {
Serial.println (F("Error al iniciar la tarjeta SD"));
showErrorAndReset();
} else {
Serial.println("Tarjeta SD inicializada");
createFilename();
createDataFile();
}
//Comunicación con la sonda barométrica
if (!bmp.begin()) {
Serial.println (F("Error al iniciar la sonda barométrica"));
showErrorAndReset();
}
Serial.println("Sonda barométrica inicializada");
}
void loop() {
// put your main code here, to run repeatedly:
currentMillis = millis(); //Cada vez que se resetee el loop, currentMillis será igual a millis(), por lo tanto, igual al tiempo desde que se inició el código.
//Cuando llegue a 50 líneas escritas en la SD, la tarjeta Arduino se reiniciará.
if (txtLinesCounter >= txtMaxLines) {
resetBoard();
} else {
//Cada 10 segundos se realizan mediciones de todas las sondas:
if (currentMillis - lastMeasurementTime >= recordTime) {
lastMeasurementTime = currentMillis;
//Medición de la placa solar:
meassureVolt();
//Impresión de los resultados en el Serial Monitor
Serial.print("Tensión en mV: ");
Serial.println(v1);
Serial.print("Corriente en mA: ");
Serial.println(mA);
//Guardado de la información en una variable
totalmAmp += mA;
totalmVolt += v1;
//Medición del sensor de temperatura:
meassureTemp();
//Impresión de los resultados en el Serial Monitor
//SE IMPRIME EN EL VOID...
//Guardado de la información en una variable
totalTemp += tempCelsius;
//Medición de la sonda barométrica:
meassurePres();
//Impresión de los resultados en el Serial Monitor
Serial.print("Presión sonda: ");
Serial.print(presion);
Serial.println(" Pa");
Serial.print("Temperatura sonda bar: ");
Serial.print(temp2);
Serial.println(" *C");
//Guardado de la información en una variable
totalPres += presion;
totalTemp2 += temp2;
//Medición del anemómetro:
meassureWindSpeed();
//Impresión de los resultados en el Serial Monitor
Serial.print("Velocidad del viento en km/h: ");
Serial.println(windSpeed);
Serial.print("Velocidad del viento en m/S: ");
Serial.println((float)windSpeed / 3.6);
//Guardado de la información en una variable
totalWindSpeed += windSpeed;
Serial.println(" ");
//Al acabar de medir en todas las sondas, se suma +1 medición
measures++;
}
//Cada 2 minutos se calcula un promedio de los datos que se han ido almacenando cada 10 segundos
if (currentMillis - lastAverageTime >= averageTime) {
lastAverageTime = currentMillis;
//Cálculo de promedios:
calcularPromedio();
//Tomar la hora:
reloj();
//Imprimir datos (promedio + hora) en el monitor serial y SD:
imprimirSD();
}
}
}
void meassureVolt(){
v1 = analogRead(placaPin) * 5.0 / 1023.0 * 1000.0;
mA = v1 / 100;
}
void meassureTemp(){
sensors.requestTemperatures(); //Request temperature readings
tempCelsius = sensors.getTempCByIndex(0); //Get temperature from the sensor in Celsius
//Check if temperature reading is valid (DS18B20 returns -127°C when reading is not available)
if (tempCelsius != -127.00) {
Serial.print("TemperaturaPanel: ");
Serial.print(tempCelsius);
Serial.println(" *C");
} else {
Serial.println("Error reading temperature!");
}
}
void meassurePres(){
presion = bmp.readPressure();
temp2 = bmp.readTemperature();
}
void meassureWindSpeed(){
interruptCounter = 0;
attachInterrupt(digitalPinToInterrupt(anemPin), countup, RISING);
delay(anemTime * 1000); //El muestreo de velocidad del viento se realiza durante 5 segundos
detachInterrupt(digitalPinToInterrupt(anemPin));
windSpeed = (float)interruptCounter / (float)anemTime * 1.2; //Factor 1.2 calculat empíricament
}
void countup() {
interruptCounter++;
}
void calcularPromedio() {
//Cálculo promedio de mVolt y mAmp
averagemAmp = totalmAmp / measures;
averagemVolt = totalmVolt / measures;
//Cálculo promedio de temperatura:
averageTemp = totalTemp/ measures;
//Cálculo promedio de presión:
averagePres = totalPres/ measures;
averageTemp2 = totalTemp2/ measures;
//Cálculo promedio de la velocidad del viento:
averageWindSpeed = totalWindSpeed/ measures;
}
void imprimirSD () {
//Creación de los strings que irán en la SD:
dataStringHora = fecha + hora;
dataStringPlaca = "mVolt promedio: ;" + String(averagemVolt) + "; mAmp promedio: ;" + String(averagemAmp) +";";
dataStringTemp = "Temperatura promedio placa: ;" + String(averageTemp) + "; *C;";
dataStringPres = "Presion promedio: ;" + String(averagePres) + "; Pa;";
dataStringTemp2 = "Temperatura promedio tejado: ;" + String(averageTemp2) + "; *C;";
dataStringAnem = "Velocidad promedio viento: ;" + String(averageWindSpeed) + "; km/h;";
//Almacenamiento del string creado dentro de la SD:
File dataFile = SD.open(txtFilename, FILE_WRITE);
if (dataFile) {
dataFile.print(dataStringHora);
dataFile.print(dataStringPlaca);
dataFile.print(dataStringTemp);
dataFile.print(dataStringPres);
dataFile.print(dataStringTemp2);
dataFile.println(dataStringAnem);
blinkLED(greenLEDPin, 3, 750);
dataFile.close();
//Impresión de lo guardado en la SD en el monitor serial
Serial.println(dataStringHora);
Serial.println(dataStringPlaca);
Serial.println(dataStringTemp);
Serial.println(dataStringPres);
Serial.println(dataStringTemp2);
Serial.println(dataStringAnem);
Serial.println("Datos almacenados correctamente.");
Serial.println(" ");
txtLinesCounter++;
Serial.print("Contador de lineas en Fichero TXT: ");
Serial.println(txtLinesCounter);
Serial.println(" ");
} else {
Serial.println("Error al abrir el archivo.");
showErrorAndReset();
}
}
void reloj() {
DateTime now = rtc.now();
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
//rtc.adjust(DateTime(2023, 9, 11, 14, 58, 20));
//Obtención del día de la semana
String diaSemana;
switch (now.dayOfTheWeek()) {
case 1: diaSemana = "Lunes"; break;
case 2: diaSemana = "Martes"; break;
case 3: diaSemana = "Miercoles"; break;
case 4: diaSemana = "Jueves"; break;
case 5: diaSemana = "Viernes"; break;
case 6: diaSemana = "Sabado"; break;
case 7: diaSemana = "Domingo"; break;
default: diaSemana = "Desconocido"; break;
}
//Formato de fecha: Día de la semana, Día/Mes/Año
fecha = diaSemana + ";" + String(now.day()) + "/" + String(now.month()) + "/" + String(now.year()) + " ";
// Formato de hora: Hora:Minuto:Segundo
hora = String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second()) + ";";
}
void createFilename() {
DateTime now = rtc.now();
snprintf(txtFilename, sizeof(txtFilename), "%02d%02d%02d%02d.txt",
now.month(), now.day(), now.hour(), now.minute());
Serial.print("Filename: ");
Serial.println(txtFilename);
} //cierre void createFilename
void createDataFile() {
File dataFile = SD.open(txtFilename, FILE_WRITE);
if (dataFile) {
dataFile.println(txtFilename);
dataFile.close();
blinkLED(greenLEDPin, 3, 150);
//Serial.println(txtFilename);
//Serial.println("txtFilename grabado en TXT")); //(F()) guarda en la memoria flash en vez de la RAM y ahorra memoria. Solo sirve para MENSAJES DE TEXTO O VARIABLES FIJAS
} else {
blinkLED(redLEDPin, 3, 150);
Serial.println(F("Error grabando txtFilename en TXT"));
}
} //cierre createDataFile
void resetBoard() {
Serial.println("Número máximo de líneas en TXT alcanzado. Reseteando tarjeta: ");
blinkLED(greenLEDPin, 1, 2000);
blinkLED(redLEDPin, 1, 2000);
asm volatile (" jmp 0"); // Software Reset
} //cierre void resetBoard
void showErrorAndReset() {
blinkLED(redLEDPin, 1, 5000);
asm volatile (" jmp 0");
} //cierre void showErrorAndReset
void blinkLED(int pin, int count, int delayMs) {
for (int i = 0; i < count; i++) {
digitalWrite(pin, HIGH);
delay(delayMs);
digitalWrite(pin, LOW);
delay(delayMs);
}
} //corchete cierre blinkLED