martes, 12 de febrero de 2013

Integración del módulo tajetas SD

(4ª parte del invento de sistema de control de caldera de gasoil, post aquí)

Esta vez me ha costado más de lo que esperaba, he perdido mucho tiempo con el lector de tarjetas SD, ya que no conseguía hacerlo funcionar.
El poco tiempo del que dispongo lo perdí algunas noches de las últimas dos semanas peleando con el lector de tarjetas que no funcionaba, conseguía identificar la tarjeta, la capacidad disponible, los archivos presentes, pero no grababa ni daba mensaje de error, probé de todo, hasta me puse a investigar dentro de las librerías, que a su vez llaman a otras librerías que se encargan de la comunicación serie y de las que sospechaba, ya que con el único sketch con el que leía la tarjeta, tenía una función para ajustar la velocidad del bus a la mitad.
Al final, después de muchas pruebas, casualmente probé otra tarjeta diferente (una Lexar de 2Gb) que tenía por ahí y funciona perfectamente.



Entonces, por ahora tenemos integrado y funcionando:

  • Sensor de ultrasonidos para el nivel de combustible HC-SR04.
  • Reloj en tiempo real DS1307.
  • Pantalla LCD de 20 caracteres por 4 líneas.
  • Módulo lector/grabador de tarjetas SD para grabar el log.
  • Sensor de temperatura y humedad DHT-11.
Además he tenido que cambiar la placa Arduino, de la duemilanove que tenía antes a la Mega 1280 ya que se me estaba quedando pequeña y aun no había empezado a integrar sensores y actuadores.

La foto no es muy atractiva pero no deja de ser un prototipo en pruebas.
Ahora tengo que empezar a probar con los sensores de temperatura y con los sensores de estado de las bombas o de flujo de agua, además de optimizar un poco el programa racionalizando el muestreo de variables, no tiene sentido grabar cada 2 o 5 segundos como está el programa ahora, ni todas las variables en cada ciclo.
Hay variables como puede ser la de nivel de tanque que no varían apreciablemente en menos de un minuto, y la lectura de las mismas ralentiza el programa, el DHT-11 es otro ejemplo de lectura lenta.

El sensor DHT-11 que se puede ver en la foto, el de la carcasa azul sobre el aislante de la tubería, ahora está en el exterior, registrando la temperatura y humedad del aire exterior.
Para la medida de las temperaturas de los circuitos de agua, posiblemente emplearé los LM-35 y el conversor A/D que integra el Arduino.
Para la temperatura exterior también tendré que cambiar el tipo de sensor porque el utilizado DHT-11 no registra temperaturas menores que cero.
El LM-35 sí puede hacerlo pero necesita una alimentación un poco especial, con tensiones negativas y positivas, habrá que dedicarle un poco de tiempo.
En el programa que copio a continuación hay unas cuantas lineas que imprimen por el puerto serie, sólo están a modo de comprobación para ver en el Serial Monitor qué está haciendo el micro, proporciona más info que en la LCD, una vez que haya terminado las pruebas se pueden eliminar.
Al menos ya no hay que tomar los datos a mano, ya los registra en la tarjeta SD y se pueden tratar en una excell, luego pondré una muestra.


/* 
 * 
 */ 
#include <SD.h> //libreria para el control del lector SD
#include <LiquidCrystal.h> // libreria para la pantalla LCD
#include <NewPing.h>  //libreria para el sensor de ultrasonidos
#include "Wire.h"  // libreria para conectar con el reloj DS1307
#include "DHT.h"  // libreria con la que trabaja el sensor de temp y hum
#define TRIGGER_PIN  7  // Arduino pin conectado al trigger pin del sensor ultrasonido.
#define ECHO_PIN     6  // Arduino pin conectado al echo pin del sensor ultrasonido.
#define MAX_DISTANCE 150 // distancia maxima necesaria (centimetros). funciona hasta 400-500cm.
#define DS1307_I2C_ADDRESS 0x68 //direccion del reloj en el bus
#define DHTPIN 31     // Indicamos el pin donde conectaremos la patilla data del sensor DHT
#define DHTTYPE DHT11   // DHT 11 
DHT dht(DHTPIN, DHTTYPE);
const int chipSelect = 53; // inicializa la libraria con el pin de CS para la tarjeta SD
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //inicializa la libreira de la LCD con los pines utilizados
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // Inicializa la libreria con los pines y la distancia maxima.
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
int ledState = LOW;
// Convertir numeros decimales normales a binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convertir BCD a numeros decimales normales
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}
// Leer fecha y hora del ds1307
void getDateDs1307(byte *second,
  byte *minute,
  byte *hour,
  byte *dayOfWeek,
  byte *dayOfMonth,
  byte *month,
  byte *year)
  {
  // Resetea el puntero de registro
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
  *dayOfWeek  = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month      = bcdToDec(Wire.read());
  *year       = bcdToDec(Wire.read());
}

void setup()  
{
  pinMode(13, OUTPUT);
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  Wire.begin(); //Arranca la comunicacion con el reloj
  lcd.begin(20, 4); // Arranca la LCD con columna, fila 
  Serial.begin(9600);
  // Para poner el reloj en hora, cambiar los valores siguientes.
  // Mientras no se programa un procedimiento para ponerlo mediante una botonera
  // comentar la funcion setDateDs1307 para que no se ponga en hora y se inicialice.
  
  second = 10;
  minute = 21;
  hour = 00;
  dayOfWeek = 4;
  dayOfMonth = 24;
  month = 1;
  year = 13;
 
  //setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
  

  Serial.println("Comprobacion sensor DHTxx:");
  dht.begin(); //Iniciamos el sensor
  Serial.print("Inicializando tarjeta SD...");
  // hay que asegurarse de que el pin CS está configurado como salida 
  // aunque no se use:
  pinMode(53, OUTPUT);
  // comrpobar si la tarjeta está presente y puede ser inicilizada:
  if (!SD.begin(chipSelect)) {
    Serial.println("Fallo de tarjeta, o no presente");
    // no hacer nada:
    return;
  }
  Serial.println("Tarjeta inicializada.");
}

void loop()
{    
  // leer reloj
  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  // leer nivel tanque
  float uS = sonar.ping_median(10); // Leer tiempo de retorno del sensor en uS.
  float cm = uS / 58; //pasarlo a centimetros
  float x = (7.5758 * cm); // convertir la distancia a la superficie a nivel de 
  float litros = (1057.878 - x); //combustible en litros
   // La lectura de la temperatura o de la humedad lleva sobre 250 milisegundos  
  // La lectura del sensor tambien puede estar sobre los 2 segundos (es un sensor muy lento)
  int h = dht.readHumidity();  //Guarda la lectura de la humedad en la variable float h
  int t = dht.readTemperature();  //Guarda la lectura de la temperatura en la variable float t
 // Comprobamos si lo que devuelve el sensor es valido, si no son numeros algo esta fallando
// if (isnan(t) || isnan(h)) // funcion que comprueba si son numeros las variables indicadas 
// {
// Serial.println("Fallo al leer del sensor DHT"); //Mostramos mensaje de fallo si no son numeros
// } else {
 //Mostramos mensaje con valores actuales de humedad y temperatura, asi como maximos y minimos de cada uno de ellos
     
// } 
  
  // imprimir en la pantalla LCD
  lcd.clear();
  lcd.noCursor();
  lcd.setCursor(0, 0);
  lcd.print("   Hora      Fecha");
  lcd.setCursor(1,1);
  //lcd.print("  ");
  if(hour < 10)
    lcd.print("0");
  lcd.print(hour, DEC);
  lcd.print(":");
  if(minute < 10)
    lcd.print("0");
  lcd.print(minute, DEC);
  lcd.print(":");
  if(second < 10)
    lcd.print("0");
  lcd.print(second, DEC);

  lcd.setCursor(12, 1);
  lcd.print(dayOfMonth, DEC);
  lcd.print("-");
  lcd.print(month, DEC);
  lcd.print("-");
  lcd.print(year, DEC);

 
  lcd.setCursor(0, 2);

  lcd.print(litros);
  lcd.println(" litros     ");
   Serial.print("Temperatura: "); 
   Serial.print(t);
   Serial.print(" *C  ");
   Serial.print("Humedad relativa: "); 
   Serial.print(h);
   Serial.println(" %\t");
    lcd.setCursor(0, 3);
    lcd.print(t);
    lcd.print(" oC  ");
    lcd.print(h);
    lcd.print(" % Humedad");  
 // digitalClockDisplay(); 
 
  
  // make a string for assembling the data to log:
  String dataString = "";
Serial.println("empieza string");
    dataString = String(dayOfMonth,DEC);
    dataString += "/"; 
Serial.println("dia");
    dataString += String(month,DEC);
    dataString += "/"; 
Serial.println("mes");
    dataString += String(year,DEC);
    dataString += ",";
Serial.println("año"); 
    dataString += String(hour,DEC);
    dataString += ":"; 
Serial.println("hora");
    dataString += String(minute,DEC);
    dataString += ":";
Serial.println("minuto");
    dataString += String(second,DEC);
    dataString += ","; 
Serial.println("segundo");
    dataString += String((int) t,DEC);
    dataString += ",";
Serial.println("temp");
    dataString += String((int) h,DEC);
    dataString += ",";
Serial.println("hum");
    dataString += String((int) cm,DEC);
    dataString += ",";
Serial.println("distanc");
    dataString += String((int)litros,DEC);
Serial.println("acaba string");
  ledState = !ledState;
  digitalWrite(13, ledState); // esto es para ver parpadear el LED de la placa cuando el programa pasa por aqui.
   // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.print("grabado :");
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  } 
  ledState = !ledState;// esto es para ver parpadear el LED de la placa cuando el programa pasa por aqui.
  digitalWrite(13, ledState); // amodo de comprobación.
  delay(500);
}

2 comentarios:

  1. Mu interesante, estoy trabajando en algo similar, y te agradecería me pasases el diagrama de conexión del lector de tarjetas SD pues estoy teniendo problemas para comunicar con la SD y me gustaría contrastar la conexión.
    Un saludo

    ResponderEliminar
    Respuestas
    1. Hola, te dejo el esquema en https://drive.google.com/file/d/0Bxi2zAgtRZ32azZ5Uk9oMXltVnM/edit?usp=sharing

      Espero que te sirva.
      Saludos.

      Eliminar