No puedo leer la tarjeta sd por bluetooth

Hola gente del foro, soy nuevo en el tema arduino. Estoy armando un datalogger de tension y corriente con un arduino uno, un rtc y un lector de memorias. Todo funciona bien, pero quiero agregarle un modulo bluetooth para poder leer la memoria sd en formato txt y no logro hacerlo funcionar. Subo los archivos que estoy usando. Muchas gracias. Saludos

1.ino (3.31 KB)

Bluetooth.ino (12.6 KB)

Los bocetos no debes ponerlos como adjunto. Para eso hay una opción llamado "code" (a la izquierda de B).

Cuéntanos que modulo bluetooth estas usando (HC-05 o HC-10 por ejemplo) ? Esta como Maestro o Esclavo ?

Porque estas iniciando el modulo BT 4 veces ? deja solo el del setup()

BluetoothSerial.begin(9600);

Luego veo que usas:

BluetoothSerial.println(reading);

Prueba con:

BluetoothSerial.write(reading);

Hola Kike_GL estoy usando el modulo bluetooth HC-05. Esta configurado como maestro. Voy a probar como tu me indicas y comento. Gracias. Saludos.

Hola buenas noches colegas. Hice los cambios pero sigo sin poder ver los datos en de la sd por bluetooth. Muchas gracias. Saludos.

Como te dije anteriormente, debes editar tu primer mensaje poniendo el código completo entre las etiquetas code no como adjunto.

/*
***Energy Data Logger***

Data logger para monitoreo de consumo de energía electrica.
mide tensión y corriente para calcular el consumo de energía, y registra los datos en una trajeta SD

Copyright (C) 2018  Javier D'Ambra

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/* Conexiones de hardware / uso de pines
   Placa Arduino Nano

   Pines 0 y 1 -> Conexión serie/USB, para comunicación con PC (programación, control, etc.)

   SD - Se comunica por SPI
   MOSI -> pin 11
   MISO -> pin 12
   CLK -> pin 13
   CS (SS) -> Pin 10

   Reloj RTC DS3231 - Se comunica por I2C/Wire
   SDA -> pin A4
   SCL -> pin A5
   
   Monitoreo de señales analógicas
   Tensión:           //para medir tensión se debe conectar un transformador ac/ac adecuado y calibrar los parámetros.
    pin A2
   Corriente:         //para poder medir todos los parámetros electricos, se debe sensar corriente con un tranf de corriente SCT-013 100a.
    pin A3
    
   Senales de info/control
    LED "latido" -> pin 5
    LED "errorSD" -> pin 6

   Pines reservados para futuras mejoras
    LED (reservado) -> pin 4
    Boton "arriba"      |
    Boton "abajo"       |
    Boton "izquierda"   | -> array (teclado analógico) conectado a A1
    Boton "derecha"     |
    Boton "enter"       |
*/


// Librerías que serán incluídas
#include <SPI.h>        //Comunicación con periferícos SPI
#include <Wire.h>       //Comunicación I2C
#include <SdFat.h>      //Usamos la librería SdFat en lugar de la de arduino por estar mas optimizada - Manejo de tarjeta SD - https://github.com/greiman/SdFat
SdFat SD;               //Línea necesaria para compatibizar el programa escrito para SD.h (libreria original)
#include <TimeLib.h>      //Gestion de fecha, hora, etc. - https://www.pjrc.com/teensy/td_libs_Time.html
#include <DS1307RTC.h>    //Librería para control del reloj RTC (DS1307 ó DS3231) - https://www.pjrc.com/teensy/td_libs_DS1307RTC.html
#include <EmonLib.h>      //Librería "EMON" (Energy Monitor) con funciones para medir tensión y corriente y calcular parámetros de energía - https://openenergymonitor.org/
#include <SoftwareSerial.h>

// Declaración de etiquetas para los pines utilizados

// pines reservados para futuras mejoras
//const int pinLedReservado = 4; // LED reservado
//const int pinTeclado = A1; // Pin para teclado analógico

// Pin para selección de la SD
const int CS_SD = 10;

// Pin para led´s
const int pinLedLatido = 5;   // "latido"
const int pinErrorSD = 6;     // "errorSD"

// Pines analógicos, señales analógicas
const int pinTension = 2;      // Pin (analógico) para la medición (Valor de tensión) de la energía eléctrica.
const int pinCorriente = 3;    // Pin (analógico) para la medición (Valor de Corriente) de la energía eléctrica.

// Constantes varias

const unsigned long intervaloLectura = 2000;      //inervalo de lectura de sensores [milisegundos]
const unsigned long intervaloEscrituraSD = 100;     //intervalo de escritura de datos en la SD [seg]

// Variables globales
EnergyMonitor emon1;  //Crea instancia de la librería Emon para medición parámetros eléctricos.

// Variable para indicar presencia de tarjeta SD
boolean presenciaSD = 0;

// Sincro de reloj

const int intervaloSincro = 300; //Intervalo de sincronización del reloj arduino con el RTC [Seg.].

SoftwareSerial BluetoothSerial(2, 3); //RX, TX

File nrg_log;

//----------------------------------------------------------------------------------------------------------------

void setup() {
  
  Serial.begin(9600);
  
  BluetoothSerial.begin(9600); // Initialise BlueTooth
 
  //inicialización mediciones
  emon1.voltage(pinTension, 230.00, 1.6);  // Voltage: input pin, calibration, phase_shift
  emon1.current(pinCorriente, 60.6);       // Current: input pin, calibration.
  
  //inicialización de pines reservados a futuro (conectados en placa de control)
  //pinMode(pinLedReservado, OUTPUT);
  
  //Establecer pines digitales necesarios como salida
  pinMode(pinLedLatido, OUTPUT);  //salida donde se conecta el led "latido"
  pinMode(pinErrorSD, OUTPUT);    //salida donde se conecta el led "errorSD"
  
  //Inicializa tarjeta SD
  // ver si la SD está presente y puede inicializarse:
  if (!SD.begin(10)) {
    presenciaSD = 0;  //tarjeta no detectada  
    digitalWrite(pinErrorSD, HIGH);   //activa led error SD
  }
  else {
    presenciaSD = 1;  //tarjeta detectada
    digitalWrite(pinErrorSD, LOW);  // apaga led error SD
  }
  
  //Icicializamos el reloj y el tiempo
  setTime(RTC.get());
  ajustarReloj(); //funcion para ajustar el reloj por consola de ser necesario
  setSyncProvider(RTC.get); //Establecemos el reloj RTC como proveedor del tiempo
  setSyncInterval(intervaloSincro); // lo actualizamos segun intervalo definido
}
void loop() {
  static unsigned long millisPrevio = intervaloLectura;
  static unsigned long millisPrevio2 = intervaloEscrituraSD;
  static float energia = 0;
  static float energiaParcial = 0;
  static boolean ledLatido = LOW;
  static String datos;
  unsigned long millisActual = millis();
  
  if (millisActual - millisPrevio >= intervaloLectura){ //Ejecuta las siguientes acciones solo si se cumple el intervalo
    Serial.println(F("Fecha/Hora; Potencia activa; Potencia aparente; Tensión; Corriente; Factor de potencia"));
    Serial.print(timeLabel());
    Serial.print(" ");
    emon1.calcVI(20,1000);         // Calcula todos los parametros. No. de medias ondas (cruces), time-out
    emon1.serialprint();           // Imprime todas las variables (Pot real, pot aparente, Vrms, Irms, factor de potencia)
    energiaParcial = energiaParcial + ((emon1.realPower * (intervaloLectura/1000))/3600000); //calculamos la energía acumulada (desde el ultimo grabacion SD) expresado en KWh.
    energia = energia + ((emon1.realPower * (intervaloLectura/1000))/3600000); //calculamos la energía acumulada (desde el ultimo reset) expresado en KWh.
    Serial.print(F("\nEnergía consumida: "));
    Serial.println(energia, 4);
    datos = timeLabel();           // coloca la marca de tiempo en el String datos    
    datos = datos + ", " + String(emon1.Vrms, 2);  //va agregando todos los valores medidos al string
    datos = datos + ", " + String(emon1.Irms, 2);
    datos = datos + ", " + String(emon1.realPower, 1);
    datos = datos + ", " + String(emon1.powerFactor, 2);
    datos = datos + ", " + String(emon1.apparentPower, 1);
    datos = datos + ", " + String(energiaParcial, 4);
    datos = datos + ", " + String(energia, 4);
    
    if (ledLatido == LOW) {
      ledLatido = HIGH;      
    }
    else {
      ledLatido = LOW;
    }
    
    digitalWrite(pinLedLatido, ledLatido);
    millisPrevio = millisActual;
  }
  
  if (millisActual - millisPrevio2 >= intervaloEscrituraSD * 1000UL){  //si se cumple el intervalo especificado, procede a grabar los datos
    if (grabarDatosSD(datos)) {   //graba los datos en la SD - si hubo error al grabar devuelve 1
      digitalWrite(pinErrorSD, HIGH); //como hubo error e grabado prende el led error SD
    }
    energiaParcial = 0; //Vuelve a cero el contadordeenergía que integra entre períodos de grabación.
    millisPrevio2 = millisActual;
  }
}
//función que devuelve un String con la Hora/fecha actual
//Agrega el '0' a la izquierda en los valores de una cifra y le da formato a la hora/fecha
String timeLabel() {
  time_t t = now();
  String tiempoActual = String('0');
  tiempoActual = year(t);
  if (month(t) < 10)
    tiempoActual = String(tiempoActual + '-' + '0' + month(t));
  else
    tiempoActual = String(tiempoActual + '-' + month(t));
  if (day(t) < 10)
    tiempoActual = String(tiempoActual + '-' + '0' + day(t));
  else
    tiempoActual = String(tiempoActual + '-' + day(t));
  tiempoActual = String(tiempoActual + ' ');
  if (hour(t) < 10)
    tiempoActual = String(tiempoActual + '0' + hour(t));
  else
    tiempoActual = String(tiempoActual + hour(t));
  tiempoActual = String(tiempoActual + ':');
  if (minute(t) < 10)
    tiempoActual = String(tiempoActual + '0' + minute(t) + ':');
  else
    tiempoActual = String(tiempoActual + minute(t) + ':');
  if (second(t) < 10)
    tiempoActual = String(tiempoActual + '0' + second(t));
  else
    tiempoActual = String(tiempoActual + second(t));
  return tiempoActual;
}

//Función que graba en un archivo "nrg_log.txt" las mediciones realizadas
//Si el archivo existe se agregan datos, y si no se crea el mismo
//Recibe un String con el formato que se va a grabar
//Devuelve 0 si salio bien y 1 si hubo error
boolean grabarDatosSD(String data) {
  time_t t = now();
  String date = String('0'); //Generamos un string para usar de nombre de archivo con la fecha del día.
  date = year(t);
  if (month(t) < 10)
    date = String(date + '0' + month(t));
  else
    date = String(date + month(t));
  if (day(t) < 10)
    date = String(date + '0' + day(t));
  else
    date = String(date + day(t));
  date = String(date + ".txt");
  char fileName[13];
  date.toCharArray(fileName, 13); //convertimos el string a array de caracteres (así lo precisa la lib SD)
  
  if (!presenciaSD) {
    return 1;                 //termina la función si la SD no esta inicializada
  }
  if (SD.exists(fileName)) { //Si existe el archivo "fileName" lo abrimos y le agregamos datos etc.
    File nrg_log = SD.open(fileName, FILE_WRITE);
    if (nrg_log) {           //Si el archivo se abre correctamente escribimos en el...                  
      nrg_log.println(data);
      nrg_log.close();
      digitalWrite(pinErrorSD, HIGH); //
      delay(100);                     //
      digitalWrite(pinErrorSD, LOW);  //
      delay(50);                      // Doble parpadeo de LED para indicar que grabamos a la SD
      digitalWrite(pinErrorSD, HIGH); //
      delay(100);                     //
      digitalWrite(pinErrorSD, LOW);  //
      return 0;
    }
    else {
      return 1;   //No se abrió el archivo...
    }
  }
  else {                      //si no existe el archivo "nrg_log.cvs" lo creamos y escribimos su encabezado antes de los datos...
    File nrg_log = SD.open(fileName, FILE_WRITE);
    if (nrg_log) {           //Si el archivo se abre correctamente escribimos en el...
      nrg_log.print(F("Archivo de registro de mediciones de energía eléctrica. Creado: "));
      nrg_log.println(timeLabel());
      nrg_log.println('\n');
      nrg_log.println(F("Fecha/Hora, Tensión, Corriente, Potencia activa, Factor de potencia, Potencia aparente, Energía de intervalo, Energía consumida total"));
      nrg_log.println(data);
      nrg_log.close();
      digitalWrite(pinErrorSD, HIGH); //
      delay(100);                     //
      digitalWrite(pinErrorSD, LOW);  //
      delay(50);                      // Doble parpadeo de LED para indicar que grabamos a la SD
      digitalWrite(pinErrorSD, HIGH); //
      delay(100);                     //
      digitalWrite(pinErrorSD, LOW);  //

  // re-open the file for reading:
  File nrg_log = SD.open("fileName.txt");
  if (nrg_log) {
    //Serial1.println("fileName.txt:");
    
    // read from the file until there's nothing else in it:
    while (nrg_log.available()) {
      char reading[10] = "";
      char fileName = nrg_log.read();
      int idx = 0;
      bool somethingWasRead = false;
      while (fileName != -1 && fileName != 13 && fileName != 10){
        reading[idx] = fileName;
        fileName = nrg_log.read();
        idx++;
        somethingWasRead = true;
      }
      reading[idx++]='\0';
      //reading[idx] = 10;
      if (somethingWasRead){
       BluetoothSerial.write(reading);
       delayMicroseconds(500);
       //BTSerial.flush();
      }
    }
    // close the file:
   nrg_log.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening fileName.txt");
  }
    }
    else {
      return 1;
    }
  }
}
/* Archivo de funciones auxiliares para manejo del chip RTC
parte del proyecto Energy Data Logger
*/

//Función para ajustar y chequear el reloj (RTC) de ser necesario.
void ajustarReloj(){
  unsigned long millisPrevio = millis();
  Serial.print(F("La fecha/hora seteada es: "));
  Serial.println(timeLabel());
  Serial.println(F("Si desea modificarla presione \"y\""));
  Serial.println(F("Si desea chequear el RTC presione \"c\""));
  while (millis() - millisPrevio < 10000UL) {  //esperamos un tiempo la orden de entrar a la consola
    if (Serial.available() > 0) {
      char input = Serial.read();
      if ((input == 'y')||(input == 'Y')) {
        setearTiempo();
        break;
      }
      else if((input == 'c')||(input == 'C')){
        chequearRTC();
        break;
      }
      else {
        Serial.println(F("\nOpción incorecta..."));
      }
    }
  }
  Serial.println(F("Arrancando..."));
  delay(5000);
  return;
}

//Función que setea el tiempo en el RTC
//-------------------------------------
//Basado en el ejemplo SetSerial.ino de la librería DS3232RTC de Jack Christensen.
//https://github.com/JChristensen/DS3232RTC
//setea fecha/hora ingresando a travez del monitor serial lo siguiente:
// año,mes,dia,hora,minuto,segundo,
//el año puede ser de dos o cuatro dígitos.
//la coma final anula el timeout de un segundo permitiendo setaer el RTC de manera mas precisa
//no se realizan verificaciones de formato o validación.
void setearTiempo(){
  time_t t;
  tmElements_t tm;

  Serial.println(F("Ingrese la nueva fecha/hora [aaaa,mm,dd,HH,mm,ss,]: "));
  // chequear la entrada para setear el RTC, longitud minima 12, ej. yy,m,d,h,m,s
  while(1){   //esperamos hasta que lleguen datos...
    if (Serial.available() >= 12) {
      // note that the tmElements_t Year member is an offset from 1970,
      // but the RTC wants the last two digits of the calendar year.
      // use the convenience macros from the Time Library to do the conversions.
      int y = Serial.parseInt();
      if (y >= 100 && y < 1000){
        Serial.println(F("Error: el año se debe ingresar con dos o cuatro digitos!"));
      }
      else {
        if (y >= 1000)
          tm.Year = CalendarYrToTm(y);
        else    // (y < 100)
          tm.Year = y2kYearToTm(y);
        tm.Month = Serial.parseInt();
        tm.Day = Serial.parseInt();
        tm.Hour = Serial.parseInt();
        tm.Minute = Serial.parseInt();
        tm.Second = Serial.parseInt();
        t = makeTime(tm);
        RTC.set(t);        // use the time_t value to ensure correct weekday is set
        setTime(t);
        Serial.print(F("La nueva fecha/hora es: "));
        Serial.println(timeLabel());
        // dump any extraneous input
        while (Serial.available() > 0) Serial.read();
        return;
      }
    }
  }
}

//Función que chequea el estado del RTC
void chequearRTC(){
  time_t t;
  t = RTC.get();
  if (t){
    setTime(t);
    Serial.print(F("Chip RTC OK \nLa fecha/hora es: "));
    Serial.println(timeLabel());
  }
  else {
    if (RTC.chipPresent()) {
      Serial.println(F("El RTC se encuentra detenido, resetee el micro y ajuste la fecha/hora"));
    } 
    else {
      Serial.println(F("Error de lectura del RTC!  chequear circuito."));
    }
  }
  delay(10000);
  return;
}[code]


Hola lo subo asi por partes porque es muy grande el archivo. Y admite solo 9000 caracteres. Los dos primeros son es el codigo entero. y esta otra parte es la segunda ventana. Es la parte del RTC. Gracias. Saludos

Hola colegas hice algunas pruebas mas pero sigo sin poder leer la tarjeta de memoria por bluetooth. Los datos se guardan en la sd.

Muchas gracias. Saludos.

si pudiste realizar la conexion de bluetooth para leer los datos de la sd