Telemetría y data logger with Arduino Part III


Para compltar esta serie de posts sobre telemetría y data logging con arduino, queda unicamente la parte de guardar datos en algún dispositivo local para poder ejecutar más tarde un post proceso. Para esto he elegido una tarjeta SD con la cual se puede hablar a través del protocolo SPI. Para esto compré un lector de tarjetas muy económico de de el fabricante Waveshare. Buscando SD reader waveshare se puede encontrar el pequeño interfaz en ebay, dealextreme etc. Utilicé este por el precio super económico ya que todos leen exactamente igual.

El lector tiene los pines identificados por las dos caras de la placa, para nosotros con arduino las interesan los nombres del reverso de la placa (la parte que lleva el logo de waveshare).
Conectarla arduino es muy facil, solo tenemos que utilizar los pines del bus SPI, en el arduino UNO, leonado, etc, estos son:

MOSI – pin 11
MISO – pin 12
CLK – pin 13
CS – pin 4 (se puede seleccionar otro pin sin problema, no forma parte del SPI)

Sin embargo en arduino MEGA, que es la placa que yo uso para este sketch, los pines son:

MOSI – pin 51
MISO – pin 50
CLK – pin 52
CS – pin 4 (se puede seleccionar otro pin sin problema, no forma parte del SPI)

Para la correcta lectura es necesario poner resistencias los cables MISO, MISI y CS, pero a mi me ha pasado con dos tarjetas distintas que el valor de estas resistencias no servía para ambas, con lo que estos valores que indico son orientativos, y haciendo pruebas debería funcionar en unos minutos:

MOSI – 1k
MOSO – 1K
CS – pull up 10k (resistencia linea de 3.3V)

¡¡ Además de esto hay que darse cuenta de que la placa debe ser alimentada con 3.3V !!

Después de cablear correctamente podemos utilizar los sketckes de test que incluye el IDE de arduino:

Comprobar comunicación con tarjeta:


Para compltar esta serie de posts sobre telemetría y data logging con arduino, queda unicamente la parte de guardar datos en algún dispositivo local para poder ejecutar más tarde un post proceso. Para esto he elegido una tarjeta SD con la cual se puede hablar a través del protocolo SPI. Para esto compré un lector de tarjetas muy económico de de el fabricante Waveshare. Buscando SD reader waveshare se puede encontrar el pequeño interfaz en ebay, dealextreme etc. Utilicé este por el precio super económico ya que todos leen exactamente igual.

El lector tiene los pines identificados por las dos caras de la placa, para nosotros con arduino las interesan los nombres del reverso de la placa (la parte que lleva el logo de waveshare).
Conectarla arduino es muy facil, solo tenemos que utilizar los pines del bus SPI, en el arduino UNO, leonado, etc, estos son:

MOSI – pin 11
MISO – pin 12
CLK – pin 13
CS – pin 4 (se puede seleccionar otro pin sin problema, no forma parte del SPI)

Sin embargo en arduino MEGA, que es la placa que yo uso para este sketch, los pines son:

MOSI – pin 51
MISO – pin 50
CLK – pin 52
CS – pin 4 (se puede seleccionar otro pin sin problema, no forma parte del SPI)

Para la correcta lectura es necesario poner resistencias los cables MISO, MISI y CS, pero a mi me ha pasado con dos tarjetas distintas que el valor de estas resistencias no servía para ambas, con lo que estos valores que indico son orientativos, y haciendo pruebas debería funcionar en unos minutos:

MOSI – 1k
MOSO – 1K
CS – pull up 10k (resistencia linea de 3.3V)

¡¡ Además de esto hay que darse cuenta de que la placa debe ser alimentada con 3.3V !!

Después de cablear correctamente podemos utilizar los sketckes de test que incluye el IDE de arduino:

Comprobar comunicación con tarjeta:


#include <SD.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
const int chipSelect = 4;    

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("\nInitializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
//  pinMode(10, OUTPUT);     // change this to 53 on a mega
  pinMode(53, OUTPUT);     // change this to 53 on a mega  


  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
   Serial.println("Wiring is correct and a card is present."); 
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
  
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

  
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
  
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
  Serial.println("END");
}


void loop(void) {

}

Con este sketch hemos comprobado que la tarjeta es leida correctamente, debe producir una salida por el puerto serie como esta:

Initializing SD card...Wiring is correct and a card is present.

Card type: SD1

Volume type is FAT16

Volume size (bytes): 1027850240
Volume size (Kbytes): 1003760
Volume size (Mbytes): 980

Files found on the card (name, date and size in bytes): 
TEST.TXT      2000-01-01 01:00:00 72
END

Aclaro que a mi el listado de ficheros en la tarjeta me salió siempre vacio aún habiendo ficheros, hasta que ejecuté el segundo script y ese si lo reconocío con normalidad, no le doy mayor importancia por que el uso principal que quiero darle es escribir en la tarjeta, no leer de ella.

Si por lo contrario la salida del script es esta otra:

Initializing SD card...initialization failed. Things to check:
* is a card is inserted?
* Is your wiring correct?
* did you change the chipSelect pin to match your shield or module?

Deberemos comprobar el cableado y los valores de las resistencias hasta que arduino detecte la tarjeta microsd

Una vez que este sketch se ejecute correctamente, podemos pasar a probar la lectura y escritura en la tarjeta con el siguiente código:

#include <SD.h>

File myFile;

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
//   pinMode(10, OUTPUT);
   pinMode(53, OUTPUT);
   
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("test.txt", FILE_WRITE);
  
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
	// close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  
  // re-open the file for reading:
  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
    
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
    	Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
  	// if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

void loop()
{
	// nothing happens after setup
}

Una vez ejecutado esto, deberíamos mostrarnos lo siguente por el puerto serie:

Initializing SD card...initialization done.
Writing to test.txt...done.
test.txt:
testing 1, 2, 3.

Con esto hemos comprobado que la comunicación y la escritura es correcta, y solo nos queda adaptar el segundo sketch a nuestras necesidades para poder guardar los datos que nos interesen, o incluso leer configuraciones desde él en el arranque del arduino.

Espero que estos tres posts sean de utlidad y puedan ayudar a alguien a montar un logger o telemetría con arduino.

PARTE I
PARTE II



#include <SD.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
const int chipSelect = 4;    

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("\nInitializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
//  pinMode(10, OUTPUT);     // change this to 53 on a mega
  pinMode(53, OUTPUT);     // change this to 53 on a mega  


  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
   Serial.println("Wiring is correct and a card is present."); 
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
  
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

  
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
  
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
  Serial.println("END");
}


void loop(void) {

}

Con este sketch hemos comprobado que la tarjeta es leida correctamente, debe producir una salida por el puerto serie como esta:

Initializing SD card...Wiring is correct and a card is present.

Card type: SD1

Volume type is FAT16

Volume size (bytes): 1027850240
Volume size (Kbytes): 1003760
Volume size (Mbytes): 980

Files found on the card (name, date and size in bytes): 
TEST.TXT      2000-01-01 01:00:00 72
END

Aclaro que a mi el listado de ficheros en la tarjeta me salió siempre vacio aún habiendo ficheros, hasta que ejecuté el segundo script y ese si lo reconocío con normalidad, no le doy mayor importancia por que el uso principal que quiero darle es escribir en la tarjeta, no leer de ella.

Si por lo contrario la salida del script es esta otra:

Initializing SD card...initialization failed. Things to check:
* is a card is inserted?
* Is your wiring correct?
* did you change the chipSelect pin to match your shield or module?

Deberemos comprobar el cableado y los valores de las resistencias hasta que arduino detecte la tarjeta microsd

Una vez que este sketch se ejecute correctamente, podemos pasar a probar la lectura y escritura en la tarjeta con el siguiente código:

#include <SD.h>

File myFile;

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
//   pinMode(10, OUTPUT);
   pinMode(53, OUTPUT);
   
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("test.txt", FILE_WRITE);
  
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
	// close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  
  // re-open the file for reading:
  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
    
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
    	Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
  	// if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

void loop()
{
	// nothing happens after setup
}

Una vez ejecutado esto, deberíamos mostrarnos lo siguente por el puerto serie:

Initializing SD card...initialization done.
Writing to test.txt...done.
test.txt:
testing 1, 2, 3.

Con esto hemos comprobado que la comunicación y la escritura es correcta, y solo nos queda adaptar el segundo sketch a nuestras necesidades para poder guardar los datos que nos interesen, o incluso leer configuraciones desde él en el arranque del arduino.

Espero que estos tres posts sean de utlidad y puedan ayudar a alguien a montar un logger o telemetría con arduino.

PARTE I
PARTE II


11 comentarios de “Telemetría y data logger with Arduino Part III”

  1. Saludos, muy interesante tu blog.

    Quería saber si al momento de utilizar una shield de SD que trabajar por el pin 10 ya no puedo usar este mismo pin para hacer un puerto serial por software.

    Gracias

  2. Buenas tardes

    Lo cierto es que yo solo he usado el SD con arduino mega, y además al usar el mega, nunca he tenido necesidad de utilizar el software serial. En cualquier caso hay más pines a parte del 10 que puedes usar para el software serial, solo usa otro.

    Un saludo

    Álvaro

  3. Hola Alvaro,
    Un proyecto muy interesante. Yo tengo el mismo módulo SD junto a Arduino uno. He probado las tres resistencia y no me llega a funcionar con el programa de ejemplo. Me aparece «Initializing SD card…initialization failed…» Podria indicarme exactamente como se conectan las tres resistencias. He mirado y no veo mucho información del tema, la mayoría de montajes suelen ser divisores de tensión es decir en total 6 resistencias. Pero prefiero tu montaje con tres y ademas saber que tu modulo que es el mismo que el mio te funciona.
    Gracias

  4. Hola Álvaro,
    Muy interesante el proyecto, tengo un módulo sd como el tuyo junto Arduino uno. He puesto las resistencias y no me funciona. Puedes decirme exactamente como se conectan, creo que ahí esta mi fallo. He revisado por internet y casi todo lo que veo es con divisores de tensión, es decir 6 resistencias. Prefiero tu montaje con 3 y ademas saber que te funciona con mi misma tarjeta.
    Gracias y saludos

  5. Hola Álvaro,
    Muchas gracias por el aporte. Yo estoy teniendo problemas con la lectura, trato de leer un fichero de configuración de un SD para tomar fechas e intervalos de programación y es horrible, la misma función la llamas desde setup() y funciona, quería que leyera la configuración cada vez que pulsara un botón y la meto en el loop() y hace cosas raras. No entiendo muy bien.
    Por cierto en relación a lo de la SD que comentas y las resistencias, yo lo he hecho igual que esta WEB de este muchacho que te dejo aquí y funciona de lujo y bien barato que es, aunque eso si por lo que valen en los chinos estos pequeños montajes, (2€ o así) no merece la pena ni sacar el soldador.
    http://electronicavm.wordpress.com/2011/11/05/arduino-shield-tarjeta-sd/#more-989

  6. Buenos días

    Lamento no haberte respondido antes, pero no le presto mucha atención al blog en épocas de trabajo, y acabo de leerte, pero me alegro de que pudieras solucionar el problema.
    Relamente habría que poner alguna medida más de las que pongo en el artículo, por que de ese modo se puede quemar la sd, pero para una prueba es suficiente, sobre todo si pruebas con tarjetas pequeñas olvidadas por casa, que solo sirven para estas cosas.

  7. Hola Álvaro y resto de comentaristas,
    Después de hacer bastantes pruebas, yo conecto directamente sin resistencias y me funciona perfectamente. No se si es una burrada, pero os aseguro que de momento no le pasa nada al circuito. Todo lo que veo de resistencias (fundamentalmente divisores de tensión) son montajes para tarjeteros que no llevan un circuito con componentes. Nuestra tarjeta microsd WaveShare ya lleva en el circuito sus resistencias de 10k ademas de un condensador, entiendo que ya esta preparado para conectar al SPI directamente. En la web del fabricante podéis descargar el esquema del circuito y comprobarlo http://www.wvshare.com/product/Micro-SD-Storage-Board.htm . Me falta una prueba por hacer, esta noche lo voy a dejar conectado hasta mañana, si le pasa algo al circuito lo comentare en el foro, si no digo nada es que esta todo ok.
    Saludos

  8. Hola, yo tambien tengo esta tarjeta.
    Si la conectas directamente con el arduino MEGA funciona solo de vez en cuando. incluso aveces deja de funcionar.

    voy a probar a poner las resistencias a ver si va bien,

    Gracias por la ayuda !

  9. Hasta que al fin pude!!!!

    Tengo un Arduino MiniPro con Artmega328 a 16Mhz, y el Waveshare SD.
    Lo conecté solo con las resistencias (MOSI – 1k / MOSO – 1K) y tengo un pequeño circuito que baja el voltaje del pin 5v a 3.3v, con eso conectado, más el Sketch que aparece al principio y listo…
    Deben recordar que la línea 12 del primer código publicado por Alvaro (const int chipSelect = 4;) es donde le indican a que pin quieren que mande los datos el CS o SCLK.

    Yo lo conecté así:
    VCC -> 3.3v
    GND -> GND
    MISO (DO) -> Resistencia 1K -> PIN 12
    MOSI (DI) -> Resistencia 1K -> PIN 11
    SCLK (CS) -> PIN 4

    Y después de 3 días peleando con el código, pensando en que las librerías para variar no me servían y etc, dí con el Post de Alvaro y listo!!!

    Muchas gracias por la ayuda, me sacaste una migraña de encima, ahora seguiré con mi proyecto, que es el siguiente:

    – Arduino (MiniPro)
    – Pantalla LCD (LCD I2C de 16×2)
    – Sensor de Humedad y Temp. (DHC11)
    – Sensor Barometrico (BMP180)
    – Reloj (RTC DS1302)
    – GPS (NEO-6M-0-001)
    – SD (Waveshare)
    – Mini Circuito conversor de 5v a 3.3v

    La idea inicial era dotar a mi Drone (Parrot ArDrone v1.0), de un Log de vuelo que me permita monitorear además condiciones de clima. De acá voy a sacar ideas para luego poder convertir el Drone en un UAV de vuelo programado, y por otra parte un sistema de domótica para mi casa que modifique diferentes condiciones según el clima, como controlar el regadío automático, sistema de aire acondicionado, intensidad de luces, persianas eléctricas e incluso alertar cuando hay que salir con paraguas o no… Incluso pensé en un sistema para mi moto que incluya alarma, corte de motor y limitador de velocidad si es que hay lluvia o se detecta exceso de humedad ambiental para prevenir caidas accidentales… En fin… Ni idea donde voy a terminar con esto y solo llevo 3 semanas con Arduino jajaja… Saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *