TODOPIC

Otros Microcontroladores / Dispositivos programables => Arduino => Mensaje iniciado por: nachin27 en 01 de Mayo de 2019, 18:52:08

Título: Ayuda, no puedo leer la tarjeta sd por bluetooth
Publicado por: nachin27 en 01 de Mayo de 2019, 18:52:08
Hola gente del foro, soy nuevo en el mundo arduino. Estoy armando un datalogger de tension y corriente. Lo monte con un arduino uno, tiene un reloj DS3231 y un lector de tarjetas sd. Funciona todo perfecto, me guarda los datos en la sd con fecha y hora. El tema es que quise agregarle un modulo bluetooth para leer los datos grabados en la sd y no logro hacerlo andar de ninguna manera. Espero me puedan ayudar. Muchas gracias de antemano. Saludos.

Código: [Seleccionar]
/*
***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 Uno

   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;
    }
  }
}[code]

/* 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]