bclose

Shield Ethernet y SD card

Usando la tarjeta SD del Shield Ethernet

Objetivos

 

 
    • Presentar la SD disponible en el Shield Ethernet.
    • Mostrar como leer y escribir en la tarjeta SD.
    • Ver algunos ejemplos sencillos de uso.

 

 

Material requerido.

Imagen de Arduino UNO  Arduino UNO o equivalente.
Shield Ethernet
Un Shield Ethernet

 

Las SD Card

 

En los últimos años, las tarjetas SD y microSD se han popularizado mucho, debido al auge de la fotografía digital y la telefonía móvil. No es fácil encontrar un teléfono móvil o Tablet, a quien no se le pueda ampliar la memoria con una de estas tarjetas, con la excepción claro está, de Apple, que como es habitual va por libre.

micro SD card
micro SD a SD completa

Basadas en la tecnología de memoria FLASH, permiten escribir con buena velocidad (Relativamente ) y además no pierden el contenido cuando las desconectamos, lo que las ha convertido en una solución de primera para intercambiar información.

Desde cámaras de fotos, Teléfonos digitales y Memorias USBs, la tecnología FLASH ha tenido un éxito rotundo y una aceptación masiva, lo que ha llevado los precios a la baja y prácticamente han acabado con CDs DVDs y demás formatos ópticos para la transferencia de información.

Hoy día no es raro comprar memorias USB de 8, 16 o 32 Gb por el precio de una entrada de cine. Y como nuestro Shield Ethernet lleva un lector grabador de tarjetas micro SD, no podíamos dejar pasar la ocasión sin ver cómo usarlas.

Detalle SD card

Aunque ya hemos comentado que los Arduinos, incluyen una memoria EEPROM interna que podemos usar como mini disco duro, no se puede comparar con la posibilidad de disponer de una tarjeta SD intercambiable, especialmente en lo que a capacidad se refiere.

Por eso, en muchos proyectos, es muy interesante de disponer de uno de estos pequeños grabadores, que nos permitan ir registrando los datos que vamos leyendo de sensores, normalmente en combinación un Reloj de tiempo real RTC, y a los que posteriormente podemos acceder y procesador en nuestros PCs mucho más cómodamente.

 

Características básicas de las SD Card

 

Lo primero que os interesa saber es que Arduino puede leer y escribir SD Cards con ciertas limitaciones, debido a la librería actualmente en uso. Como siempre estas limitaciones o especificaciones pueden cambiar en el futuro, pero es importante que las tengáis en cuenta.

La primera es que Arduino puede leer y escribir en estas tarjetas, pero no formatearlas. Esto debe hacerse desde vuestros PCs. No es grave, pero es así.

Lo segundo es que vuestros PCs pueden manejar varios formatos de sistema de archivos, pero la librería SD por ahora solo soporta FAT16 y FAT32.

Ambos formatos son una herencia de los viejos tiempos y de algún modo determinan el máximo tamaño de disco (O de tarjeta) que puedes usar. En principio si usas FAT32 deberías poder usar hasta una tarjeta de 32Gb.

Así que si queréis que el Shield Ethernet lea vuestra tarjeta, nada de formatearla en NTFS de Windows, HPFS de Apple o extN de Linux. Solo FAT16 y FAT32.

Después tenemos otra limitación con los nombres e archivos que quedan limitados al viejo formato 8.3, con nombre de 8 caracteres y extensiones de tres. Y nada de acentos en los nombres ni Ñs ni espacios en blanco. Nada que no sean letras y números, sin signos raros.

Si usas Windows en cualquier versión, puedes introducir la tarjeta SD y formatearla desde el administrador de archivos. Introduce la tarjeta en el lector y cuando la reconozca, apuntala y pulsa el botón derecho. Elige la opción formatear y veras una ventana como esta:

Formatear una tarjeta SD
Opciones de formateo para SD
En el sistema de archivos puedes elegir FAT32, y mantén el tick en la opción formato rápido. Con inicio te formateará la tarjeta.

En OSX ve a Aplicaciones, Utilidades, Discos. Elije la tarjeta SD y selecciona el formato de disco MS-DOS FAT

Como formatear una tarjeta SD

 

Existe un programa que suelen recomendar si tenéis cualquier problema, que tiene versiones para Mac y Windows llamado SD Formatter  que podéis descargar gratuitamente de internet. Está desarrollado y soporte por la asociación de fabricantes de tarjetas SD.

Por ultimo tenéis que saber que la librería puede no escribir inmediatamente los datos que le envías a la SD, y para asegurarse de que es así, debes hacer una llamada a flush (Vaciar) o close (Guardar y cerrar).

 

Comprobando la SD Card

 

Necesitáis saber que el Shield Ethernet y la librería, controlan el acceso a Ethernet y a la SD Card por SPI. Vimos que era así en el caso Ethernet y recordad que no podíamos usar unos pines en el Arduino, los que corresponden a la gestión el bus SPI.

Usamos el pin 10, Slave Select habitualmente en un UNO para seleccionar el acceso a Ethernet (El 53 en un MEGA), y necesitamos otro pin para indicar que vamos a hablar con la tarjeta SD. En el caso de un Arduino UNO el Shield Ethernet utiliza el pin 4 y por también lo reservamos en las sesiones anteriores.

Vamos a comprobar que la SD esta correcta y que podemos usarla. Aseguraros de que esta formateada y ponerle uso pocos ficheros en ella (con nombre 8.3) introducidla en el lector del Shield y enciende Arduino.

Como la librería SD viene de serie con nuestro Arduino, podemos cargar uno de los ejemplos para comprobar que lee la tarjeta:  \\Achivo\Ejemplos\SD\CardInfo

Salida ARduino

 

Si todo va bien cuando lo corráis tendréis una salida parecida a esto:

Os informa de que ha podido  identificar la SD, y os da información del tipo de formato, tamaño de la tarjeta y hasta hace un listado de los ficheros que contiene junto con algunas características.

Si veis algo así, perfecto podemos seguir. SI recibís algún mensaje de error, necesitamos que lo corrijáis antes de seguir.

Los problemas más típicos suelen ser

 
  • No tener bien encajado el Shield en el Arduino
  • Por defecto trae el pin 10 como output pero si usáis un Mega tenéis que cambiarlo pinMode(10, OUTPUT);     // change this to 53 on a mega
 

 

El programa de control

 

Para usar la tarjeta SD, tenéis en primer lugar que cargar las librerías SPI y la SD:

#include <SPI.h>
#include <SD.h>

Después tenéis que activar el pin SS

pinMode(10, OUTPUT);     // Para un Arduino UNO
pinMode(53, OUTPUT);     // Para un MEGA

Y como siempre, necesitamos iniciar la SD Card con

SD.begin(4) ;

Donde 4 es el chipSelect es de la tarjeta SD. El resto es fácil. Definir un objeto File para leer un fichero de la SD:

File root;

Ya solo queda abrir un fichero para lectura. Supón que se llama index.htm

File dataFile = SD.open("index.htm ");

Si consigue abrir correctamente dataFile tomara un valor que apunta a la estructura a leer del fichero, en caso contrario se pondrá a 0 indicando el error.

Vamos a ver cómo hacer un programa  que lea un fichero en la SD y lo envié a la consola para ver lo que contiene:

#include <SPI.h>
#include <SD.h>
const int chipSelect = 4;

void setup()
   {  Serial.begin(9600);
      while (!Serial)  ;       // wait for serial port to connect. Needed for Leonardo only
      Serial.print("Probando SD card...");
      pinMode(10, OUTPUT);         // Esto es necesario aunque creas que no lo usas.
      if (!SD.begin(chipSelect))
           {  Serial.println("No hay tarjeta");
              return;    // NO sigas
           }
      Serial.println("Sd encontrada.");
      File dataFile = SD.open("index.htm");
     if (dataFile)   // Si ha podido abrir el fichero
        {    while (dataFile.available())              // Mientras no llegues al final
                  Serial.write(dataFile.read());       // Lee el fichero y envialo al serie
             dataFile.close();                         // Cierra el fichero al acabar
        }
     else     // SI no puede abrir el fichero
           Serial.println("Error, no puedo usar indes.htm");
   }
void loop()
   { }

SD.open() abre el fichero que buscamos y devuelve un puntero de tipo File para leer datos directamente., o un 0 si no puede.

Conviene insistir en que la SD card es también una clase que deriva de stream y por tanto hereda propiedades que ya conocemos de otras sesiones. Es el caso de datFile.Available() que vimos anteriormente con Serial como Serial.Available(), es decir, mientras haya datos disponibles, pendientes de leer.

dataFile.read(), lee un carácter del fichero y Serial.write lo envía a la consola. Por ultimo dataFile.Close, cierra y libera el fichero .

 
  • Si no hacemos dataFile.close(), no podemos estar seguros de que se ha escrito todo lo que queríamos al fichero.
  • No basta con sacar la SD y llevártela. Si lo haces puedes corromper toda la información de la SD Card.
  • Además la librería SD solo permite un fichero abierto a la vez. Si quieres abrir otro fichero tienes que cerrar primero el anterior
 

 

Un programa que grabe datos en la SD card

 

La tarjeta SD se comporta como la puesta Serie, y prácticamente se maneja igual, con pequeñas diferencias. En el programa anterior para leer el fichero,  usábamos:

File dataFile = SD.open("index.htm");

Sin pasarle ningún parámetro a SD.open() diferente del nombre del fichero. Esto hace que lo abramos en forma de lectura, lo que impide que escribamos en él. Solo podemos leer.

Para conseguir escribir en un fichero usamos

File dataFile = SD.open("data.txt", FILE_WRITE);

La idea del nuevo programa Programa 65_2, es que va a escribir unos valores que lee de las puertas A2 a A4 y lo graba en el fichero data.txt (Naturalmente, como no tenemos nada conectado, leerá basura, pero eso no nos importa mucho ahora mismo). La parte interesante del programa está aquí:

File dataFile = SD.open("data.txt", FILE_WRITE);
if (dataFile)   // Si ha podido abrir el fichero
   {    dataFile.println("Vamos a escribir un par de textos en la tarjeta SD")
        for (int j=0 ; j <20 ; j++)
           {
              dataFile.println("Analog 2: " + String(analogRead(A2)));
              dataFile.println("Analog 3: " + String(analogRead(A3)));
              dataFile.println("Analog 4: " + String(analogRead(A4)));
              dataFile.println("....................................");
              delay (100);
           }
        dataFile.close();
        Serial.println("Listo. Terminado");
        Volcado() ;
   }

Abrimos el fichero data.txt y escribimos a él como si fuera la puerta Serie. Al acabar simplemente cerramos el fichero y listo.

Volcado() es una función que hace lo que vimos en el programa anterior. Copia a la consola el contenido del fichero para que veáis lo que contiene.

SAlida a consola del Arduino

Si corréis el programa unas cuantas veces veréis que, la primera vez, crea el fichero data.txt y escribe lo que le pedimos en él. Pero si cuando hace el SD.open () el fichero ya existe, la información que le enviamos se añade al final, sin borra el contenido anterior.

Lo que resulta muy práctico cuando quieres grabar información de sensores y generar un histórico

 

Operando con la estructura de ficheros de la SD

 

Siempre que creas un sistema de ficheros en un dispositivo vas a necesitar ayudas para mantenerlo. La librería SD de Arduino, nos da una serie de funciones para jugar con ficheros y directorios. Al hacer

SD.open (“File.txt”)

Se crea el fichero en caso de no existir y podemos leer, pero no escribir. Y cuando hacemos:

SD.open("data.txt", FILE_WRITE)

Se crea, si no existe, y escribirá desde el principio. Pero si existe, todo lo que escribamos decíamos que se añade al final de lo que ya existía.  Pero a veces nos interesa empezar una página en blanco, lo que podemos hacer borrando el fichero si existe:

SD.remove(“data.txt”);

Y mejor aún si comprobamos si existe antes:

if (SD.exists(data.txt)
    SD.remove(“data.txt”) ;

También podemos usar estructuras de directorios (Aunque no tengo claro hasta donde) y podemos crearlos y bórrarlos con la SD library:

SD.mkdir("/a/b/c")
SD.rmdir(filename)

Mkdir puede crear directorios anidados y basta con referir el path completo del fichero y rmdir los elimina con todo su contenido

También dispone de un juego completo de funciones de ayuda:

MétodoDescripción
File.Available()Nos indica que si hemos llegado al fin e un fichero
File.flush()Se asegura de que se escribe en la SD todo. Algo que hace automáticamente al hacer close()
File.read()Lee un carácter del fichero abierto y avanza a la siguiente posición
File.write()Escribe un carácter al fichero y avanza la posición
File.position()Te indica la posición donde escribirá/leerá el próximo carácter en relación al principio el fichero
File.size()Devuelve el tamaño de un fichero
File.seek(pos)Coloca el apuntador que indica donde leerá/escribirá en la posición que le indicamos a partir del inicio y siempre que este entre 0 y File.size()
File.peek()Lee un char de la posición que marca el apuntador y no avanza
File.isDirectory()Indica si el fichero abierto es o no un directorio

 

Hay algún que otro método adicional que podéis consultar en la documentación de la SD library

 

Resumen de la sesión

 

 
    • Hemos presentado la librería Arduino que nos permite acceder a la SD Card incluida.
    • Hemos visto un par de ejemplos sencillos, para mostrar cómo se lee y se escribe en la tarjeta.
    • Hemos visto que cuando escribimos, el modo por defecto, es añadir desde el final de lo que hubiera. La idea de esto es facilitar la creación de registros de datos de una forma cómoda, y es uno de los usos más habituales de las tarjetas SD.

 

 

 

 

(66) Comments

    • Rafa

    Hola. Gracias por los tutos. Estoy usando la SD para guardar datos de temperatura, humedad y hora. La cuestión es que quiero guardar también la máxima y la mínima de esos datos pero sin que se escriban a cada toma. Se que no se pueden grabar datos en dos archivos, pero ¿puedo cerrar uno, abrir otro, escribir y luego cerrarlo? Es decir, escribir en dos archivos, pero alternando. ¿Es posible?¿Cómo tendría que hacerlo? Muchas gracias.

    • En efecto, aunque el soft ware te impide tener dos archivos abiertos a la vez puedes cerrar uno, abrir el dos y escribir, cerrar el dos, y volver a abrir el uno para seguir escribirendo desde el final sin borrar, escribiendo al final

      No recuerdo de memoria los comandos, pero habia una forma de abrir un archivo existente y que apunte al final para añadir mas texto

    • Camilo

    Hola me parece muy interesante todos sus post, me han servido de mucha ayuda. Tengo una duda y me encantaría que pueda ayudarme. Baje 2 librerías sd que hay en Arduino, para guardar datos en la tarjeta sd desde un teclado matrícial. La tarjeta sd y teclado están bien configurados pero cuando reviso los datos almacenados guarda datos que supone son de un sensor y no de un teclado. Muchas gracias!

    • Hola Camilo, ¿qué librerías estás utilizando?en principio no necesitas más librerías que las que se indican en la sesión , las que corresponden a SPI.h y a Sd.h, con ellas podrías guardar los datos que quieras en la SD siguiendo la estructura del ejemplo. Un saludo.

    • Gabroel

    puedo mandar archivos con esta targeta por la direccion ip?

  • naturalmente que si gabriel. una tarjeta ethernet es basicamente una puerta serie que envia por tcpip lo que quieras enviar.otro tema diferente es como enviar un fichero, para lo quw vas anecesitar alguna libreria que te haga la gestion de la transferenci pormftp por ejemplo, peromdispones de las librerias de tcpip completas en ru arduino

  • Buenas a todo, primero que todo muchas gracias por estos tutoriales. A aquellos que no les reconoce la memoria microSD con el ejemplo del IDE cardinfo les cuento lo siguiente. Resulta que a mi me ocurria lo mismo, recorde que con los pines rx y tx si los estas usando y quieres cargar el sketch simplemente no lo carga o te da problemas, asi que probe a retirar la microSD cuando estoy subiendo el programa al arduino y la inserto una vez ya se cargo, desde alli todo anda bien. Es mas, cuando les salga el problema, prueben retirando e insertando de nuevo la memoria, asi me di cuenta yo; lo se, suena algo peligroso. Lo curioso es que mi memoria es de 8GB pero segun el ejemplo card info me la reconoce como si fuera de 4GB

  • Perdona. Ya me di cuenta que no te aclaraba al principio el tema. He copiado el programa Ejemplo en el que se crea un archivo en la SD, y antes de crearlo ya me dice que está creado. E igualmente el de borrado. Eso me produce inseguridad, porque debe ser que hago algo mal. Y cada vez lo compruebo con el CardInfo. Te copio mi programa aquí:
    if (SD.exists(“inicio.txt”)) {
    Serial.println(“inicio.txt existe.”);
    }
    else {
    Serial.println(“inicio.txt no existe.”);
    }

    Serial.println(“Creando inicio.txt…”);
    archivo = SD.open(“inicio.txt”, FILE_WRITE);
    archivo.close();

    if (SD.exists(“inicio.txt”)) {
    Serial.println(“inicio.txt exists.”);
    }
    else {
    Serial.println(“inicio.txt no existe.”);
    }
    Creo que está igual que en el ejemplo, y a mí me sale que está creado antes de crearlo, y que está eliminado antes de eliminarlo.

    Pero es la segunda pregunta la que no tengo ni idea. ¿Cómo colocar la hora correcta en la tarjeta?

    Muchas gracias por tu dedicación

    • Leonardo

    Hola, me estoy leyendo todos los post que hay aquí, ya que son de inmensa utilidad, ya que aunque manejo el inglés, es muy útil que lo hagas en español, así que gracias.
    Tengo una duda que al parecer podría resolver la duda de José MAría Martínez:
    ¿Cómo se podría agregar la hora exacta de cada lectura a la SD? Considerando que la hora se pierde cada vez que se desconecta la placa Arduino de una fuente de poder.
    Gracias por todo.

    • Para ver como s emaneja la SD podeis revisar esta sesion: http://www.prometec.net/data-logger-shield/

      Es un shield que incluye varias cosas ademas de la tarjeta SD (y que se maneja igual) pero que ademas incluye reloj y bateria para evitar el problema de la perdida de la hora en los apagados

    • José María Martínez

    Hola. Gracias por este trabajo. Tengo dos preguntas de novato. En primer lugar, en el programa de ejemplo de Arduino cuando creas un archivo te dice que está creado antes de estarlo, a mi modo de ver. Estas instrucciones están antes de crearlo, y por eso me sale que está creado. Lo del archivo inicio es mío.
    if (SD.exists(“inicio.txt”)) { Serial.println(“inicio.txt exists.”); } else { Serial.println(“inicio.txt no existe.”); }
    Y en segundo lugar, el reloj no está actualizado y no sé cómo hacerlo en la SD. Tengo un rtc3231 que ya lo sé manejar, pero no incluirlo en la SD. Ya sé que se podría eliminar la llamada a la fecha, ¿Pero no podría modificar algo del reloj en la SD?

    • Hola Jose Maria, Tengo hoy un dia bastante espeso pero he leido varias veces tu consulta y no estoy muy seguro de que e slo que me preguntas. ¿Me lo puedes aclarar un poco?

  • Hola buen día.
    Estoy iniciando en el mundo arduino, mi consulta es, ya que estoy realizando un proyecto con el sensor LM35 y quisiera guardar/registrar en la SD de los datos obtenidos de la temperatura que mide el sensor. Entonces si es posible hacerlo?

    Gracias, esperando tu respuesta

    • Claro que es posible segio y tienes varios ejemplos hechos con el ethernet shield como el que me hablas y con el shield data logger que es exactamente igual

    • Andrea

    Hola buen dia, estoy trabajando con un proyecto y utilizo la libreria de arduino SD.h pero esto hace que la memoria de variables globales se aumente mucho, al agregar esta libreria el programa deja de funcionar debido a que el micro queda con muy poca memoria, existe alguna otra libreria … teniendo en cuenta que solo necesito escribir en un archivopara un datalogger.

  • Gracias, como siempre, por tu atención.
    Aunque no quisiera parecer pesado, me gustaria plantear una nueva cuestión, con la que llevo peleando bastante tiempo (hasta ahora sin exito):
    He montado un programa donde grabo periodicamente (1 min) en un tarjeta SD las lecturas de varias señales de temperatura. El archivo lo abro, grabo con toda la información (medias minutales) y lo cierro cada vez. Seguramente este sea un caso muy frecuente cuando se quiere monitorizar señales y dejarlas registradas. El programa me funciona bien, pero si saco la tarjeta para ver los datos y la vuelvo a meter en mi módulo, no se vuelven a grabar nuevos datos.
    Por qué este comportamiento?. Como lo puedo solucionarlo, para que unicamente falten los datos durante el tiempo en que no habia tarjeta, pero una vez repuesta vuelva a grabarlos.
    Gracias.

    • Hola jm, hay varios ejemplos de esto en los tutos, si no recuerdo mal uno con la tarjeta etherner y otro con el shield data logger. Busca SD en el indice y te aparecara varios resultados y si tienes problemas con cualquiera comentame ¿Vale?

  • Ya lo conseguí. La cuestión es que el nombre de archivo es un array de caracteres y hay que pasar el String a este formato para que el compilador lo acepte. Con estas instrucciones es facil:
    File Archivo;
    String LogName; LogName = getLogName(); // función que devuelve la fecha como String
    char filename[LogName.length() + 1];
    LogName.toCharArray(filename, sizeof(filename));
    Archivo = SD.open(filename, FILE_WRITE);

    Un saludo

  • Hola.
    Gracias por permitirnos estas consultas que de tanta utilidad resultan.
    Quisiera plantear una pregunta. En mi proyecto quisiera grabar unos archivos con datos obtenidos de varios sensores en una tarjeta SD. Quisiera que el archivo tuviera un nombre que identificara la fecha en que se creo (yyyymmdd.LOG), pero como la función SD.open (“fileName”) tiene un parámetro tipo char*, no se como convertir las cadenas String con la fecha a char.
    He intentado solucionarlo de muchas maneras pero no lo consigo. Seguro que este es un caso de programación relativamente frecuente y estará mas que resuelto, pero yo no he sido capaz. Me podeis ayudar y darme algún enlace o ejemplo de código que permita abir fichero cuyo nombre sea la fecha de creación?.
    Muchas gracias anticipadas.

    • Hola jmcn
      No hay mucha diferencia entre string y char[] pero el compilador s epuede poner muy puntilloso con esas conversiones y sin conocer el programa tampoco te puedo recomendar un casting, asi que el consejo mas sensato que puedo darte seria que uses directamente arrays de char en lugar de strings a la hora de usar esas libreria

      SI por cualquier razon no puedes dejanos cer tu codigo para poder opinar

    • Antonio

    hola amigo hay posibilidad de mostrar un archivo de la sd en la una ip?

    • Hola ANtonio, no deberia ser complicado. Basta con que al recibir una orden dada por la web el servidor vuelque el contenido del fichero a la web y deberia verse en el navegador si es de texto

  • Give a Reply

    WordPress Anti-Spam by WP-SpamShield