De vez en cuando, tienes una idea para un proyecto de Arduino que necesita una forma de almacenar una gran cantidad de datos, como por ejemplo un datalogger GPS o un registrador de temperaturas.

La solución es usar algo que se puede encontrar en cualquier cámara digital o reproductor de MP3: ¡Flash Cards! A menudo se llaman tarjetas SD o tarjetas microSD. Su capacidad para almacenar gigabytes de datos en un espacio más pequeño que una moneda las convierte en una parte esencial de nuestras vidas.

Con el módulo de tarjeta microSD, incorporar el registro de datos en tu próximo proyecto de Arduino es muy fácil. Echemos un vistazo.

Descripción del módulo micro SD

El módulo de tarjeta microSD contiene dos componentes principales:

Una tarjeta microSD estándar tiene un voltaje de funcionamiento de 3.3 V. Como resultado, no podemos conectarlo directamente a circuitos que usan lógica de 5V; de hecho, cualquier voltaje superior a 3.6V puede dañar permanentemente la tarjeta microSD. Es por eso que el módulo incluye un regulador capaz de bajar el voltaje a 3.3V.

El módulo también incluye un chip de cambio de nivel lógico 74LVC125A, lo que permite una comunicación segura y fácil con tu microcontrolador favorito de 3.3V o 5V sin dañar la tarjeta SD.

¡Hay un zócalo para tarjetas microSD en la parte delantera! Cualquier tarjeta de memoria microSD funcionará perfectamente. La dirección correcta para insertar una tarjeta microSD generalmente está impresa en el módulo.

Modo de comunicación – SPI frente a SDIO

Las tarjetas microSD pueden ser interfazadas de dos maneras: en modo SPI y en modo SDIO.

El modo SDIO es mucho más rápido y se utiliza en teléfonos móviles, cámaras digitales y otros dispositivos. Sin embargo, es más complicado y requiere la firma de acuerdos de no divulgación. Debido a esto, es poco probable que los aficionados como nosotros encuentren código de interfaz en modo SDIO.

Por lo tanto, casi todos los módulos de tarjetas SD utilizan el modo SPI “más lento y con menos sobrecarga”, que es más sencillo de implementar en cualquier microcontrolador.

Pinout del módulo de tarjeta MicroSD

El módulo de la tarjeta microSD es fácil de conectar. Hay seis pines en él:

VCC: El pin proporciona energía al módulo y debe conectarse al pin de 5V del Arduino.

GND: es un pin de tierra.

MISO (Master In Slave Out): es la salida SPI del módulo de tarjeta microSD.

MOSI (Master Out Slave In): es la entrada SPI al módulo de tarjeta microSD.

SCK (reloj serie): pin acepta pulsos de reloj del maestro (un Arduino en nuestro caso) para sincronizar la transmisión de datos.

CS (Selección de chip): pin es un pin de control que se utiliza para seleccionar uno (o un conjunto) de dispositivos esclavos en el bus SPI.

Preparación de la tarjeta microSD

Antes de insertar la tarjeta microSD en el módulo y conectarla al Arduino, debe formatear correctamente la tarjeta a FAT16 o FAT32.

Si tienes una nueva tarjeta SD, es probable que ya esté preformateada con un sistema de archivos FAT; Sin embargo, puedes encontrar problemas con la forma en que fábrica hizo el proceso. O, si tienes una tarjeta antigua, debe formatearse. En cualquier caso, es una buena idea formatear la tarjeta antes de usarla.

Se recomienda utilizar la utilidad oficial de formateador de tarjetas SD desarrollada por la asociación SD. ¡Puede resolver muchos problemas causados por un mal formato! Descarga y ejecuta el formateador en tu computadora; simplemente selecciona la unidad adecuada y haz clic en Format.

Cableado de un módulo de tarjeta microSD a un Arduino

Ahora que tu tarjeta está lista para usar, ¡podemos conectar la placa de conexión microSD a tu Arduino!

Conecta el pin VCC del módulo a 5V en el Arduino y el pin GND a tierra

Ahora nos quedamos con los pines que se utilizan para la comunicación SPI. Debido a que las tarjetas microSD requieren una gran cantidad de transferencia de datos, funcionan mejor cuando se conectan a los pines SPI de hardware del microcontrolador.

Ten en cuenta que cada placa Arduino tiene diferentes pines SPI que deben conectarse correctamente. Para placas Arduino como la UNO/Nano V3.0 esos pines son digitales 13 (SCK), 12 (MISO), 11 (MOSI) y 10 (CS).

En la tabla siguiente se enumeran las conexiones de pines:

El siguiente diagrama muestra cómo conectar el módulo de tarjeta microSD al Arduino.

¡Es todo! ¡Ahora estás listo para comenzar a registrar datos!

Código Arduino – Probando el módulo de la tarjeta SD con CardInfo

Comunicarse con una tarjeta SD es mucho trabajo, pero afortunadamente para nosotros, el IDE de Arduino ya incluye una biblioteca muy útil llamada SD que facilita la lectura y escritura de tarjetas SD.

Comencemos con un simple sketch de ejemplo de CardInfo. Este sketch no escribe ningún dato en la tarjeta. En cambio, indica si la tarjeta es reconocida y muestra información al respecto. Esto puede ser muy útil para determinar si una tarjeta SD es compatible o no. Por lo tanto, se recomienda ejecutar este sketch antes de probar una nueva tarjeta.

Para abrir el sketch de ejemplo de CardInfo, ve a File > Examples > SD > CardInfo.

Comprueba que la línea chipSelect se inicializó correctamente al principio del sketch. En nuestro caso, estamos usando el pin digital #10, así que cámbialo a 10.

Ahora, inserta la tarjeta SD en el módulo y cargue el sketch. Cuando abra el monitor serie, puedes ver resultados diferentes según el escenario.

Escenario 1: Todo está bien

Si todo está bien, deberías ver información útil. Por ejemplo, en nuestro caso, el tipo de tarjeta es SDHC (SD High Capacity), el tipo de volumen es FAT32 y el tamaño de la tarjeta es de 4 GB.

Escenario 2: la tarjeta SD está dañada

Si tiene una tarjeta dañada como esta, verás algo como esto:

Aunque la tarjeta respondió, todos los datos son inexactos. Como puedes ver, no hay ID de fabricante o ID de OEM, y el ID de producto es ‘N / A. Parece que la tarjeta devolvió errores.

Si obtienes algo como esto, puedes intentar reformatearlo, pero si el problema persiste, es posible que tengas que tirar la tarjeta a la basura :(.

Escenario 3: error de cableado o tarjeta dañada permanentemente

Si hay un error de cableado o la tarjeta está dañada permanentemente, verás algo similar a esto. Puedes ver que ni siquiera pudo inicializar la tarjeta SD.

En este caso, vuelve a comprobar el cableado y vuelve a ejecutar el sketch.

Escenario 4: la tarjeta SD no está formateada correctamente

Si el cableado es correcto pero la tarjeta SD no está formateada correctamente, verá algo como esto:

Intenta formatear la tarjeta y ejecuta el sketch de nuevo.

Código Arduino – Lectura y escritura de datos

Suponiendo que hayas tenido éxito con el sketch anterior, procederemos al siguiente experimento. El siguiente sketch mostrará cómo escribir en un archivo y luego verificar su contenido leyéndolo de nuevo. Prueba el sketch antes de entrar en detalles.

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

File myFile;

// cambie esto para que coincide con su shield o modulo SD;
const int chipSelect = 10;

void setup()
{
  // Abra la comunicacion y espere a que abra el puerto:
  Serial.begin(9600);
  while (!Serial) {
; // espero el Puerto serial para conectar. Necesario solo para Arduino leonaro
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin()) {
    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
}

Después de cargar el código, el monitor serie mostrará lo siguiente.

Si reinicias tu Arduino y dejas que el sketch se ejecute nuevamente, los nuevos datos se agregarán al archivo sin sobrescribir los datos antiguos.

Explicación del código:

El sketch comienza incluyendo la librería SD y la librería SPI, que nos permiten comunicarnos con la tarjeta SD a través de la interfaz SPI.

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

A continuación, declaramos el pin Arduino al que está conectado el pin CS (Chip Select) del módulo de tarjeta SD. A excepción del pin CS, no necesitamos declarar ningún otro pin SPI porque estamos usando una interfaz SPI de hardware y estos pines ya están declarados en la biblioteca SPI.

Luego creamos un objeto de archivo llamado myFile , que tiene métodos y atributos para acceder y manipular archivos.

const int chipSelect = 10;
File myFile;

En la sección setup(), inicializamos la comunicación serie y llamamos a la función SD.begin(). Si logra reconocer la tarjeta, imprime “initialization done.” en el monitor serie. Si no lo hace, imprime “initialization failed!” y el programa termina.

Serial.begin(9600);
  Serial.print("Initializing SD card...");
  if (!SD.begin()) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

A continuación, llamamos a la función open(). Esta función abre un archivo o crea un archivo si no existe. Requiere dos parámetros: el nombre del archivo para abrir y el modo en que se debe abrir el archivo.

El modo de archivo puede ser FILE_READ (abre el archivo para leer y coloca el cursor al principio del archivo) o FILE_WRITE (abre el archivo para leer y escribir y coloca el cursor al final del archivo).

En nuestro caso, estamos creando un archivo llamado “test.txt” y abriéndolo en modo de lectura-escritura.

myFile = SD.open("test.txt", FILE_WRITE);

Después de abrir el archivo, usamos la función println() para escribir datos en él. La función println() es similar a la que utilizamos para imprimir datos en el monitor serie. La función print() también está disponible si no desea mover el cursor a una nueva línea.

Luego cerramos el archivo usando la función close(). Esta función cierra el archivo y se asegura de que los datos escritos en él se guarden en la tarjeta SD.

if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    myFile.close();
    Serial.println("done.");
  } else {
    Serial.println("error opening test.txt");
  }

Ahora leamos de nuevo el contenido del mismo archivo para ver si la operación de escritura anterior fue exitosa. Para lograr esto, primero abriremos el archivo usando la misma función open(), pero esta vez en modo de lectura. Debido a que el archivo “test.txt” ya se ha creado, simplemente lo abrirá.

Luego, usando la función myFile.read(), leeremos el archivo y lo imprimiremos en el monitor serie. Debido a que la función read() solo lee un carácter a la vez, tenemos que usar el bucle while y la función myFile.available() para leer todos los caracteres del archivo.

Finalmente, cerramos el archivo.

myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close();
  } else {
    Serial.println("error opening test.txt");
  }

Debido a que esto es solo un sketch para demostrar cómo leer y escribir archivos, no tiene sentido ejecutar el código varias veces. Por lo tanto, todo el código se coloca en la función setup(), que se ejecuta una vez, en lugar de la función loop(), que se ejecuta repetidamente.

void loop(){
}

Aspectos importantes a tener en cuenta

  • Puede usar las funciones print() y println() para escribir cadenas, variables, etc., al igual que los objetos serie.
  • read() devuelve un solo carácter a la vez. No lee una línea completa.
  • Cuando haya terminado con el archivo, debe usar la función close()para asegurarse de que todos los datos se escriban permanentemente. Esto también reduce la cantidad de RAM que se utiliza.
  • Puedes abrir archivos en un directorio. Para abrir un archivo en el directorio, por ejemplo, utiliza SD.open(“/myfiles/example.txt”). Recuerda que la ruta de acceso al archivo es relativa.
  • La libreria de tarjetas SD no admite nombres de archivo largos porque utiliza el formato de nombre de archivo 8.3. Así que mantén los nombres de archivo cortos. Por ejemplo, “datalog.txt” está bien, pero “My Sensor log file.text” no lo está.
  • Ten en cuenta que los nombres de archivo no distinguen entre mayúsculas y minúsculas. Entonces.txt datalog es lo mismo que DataLog.Txt y DATALOG.TXT

Algunas funciones útiles de la Biblioteca SD

Funciones específicas de objetos SD

Hay muchas funciones útiles que puede usar con SD Object. Algunos de ellos se enumeran a continuación:

  • exists(filename): La función se puede utilizar para determinar si existe o no un archivo, que devuelve verdadero o falso.
  • remove(filename): La función se puede utilizar para eliminar un archivo. ¡Pero procede con precaución! Esto elimina permanentemente un archivo; No hay forma de deshacerlo.
  • mkdir("/mynewdir"): La función se puede utilizar para crear subdirectorios. Es útil para almacenar una gran cantidad de archivos en una ubicación.

Funciones específicas del objeto de archivo

También hay algunas funciones útiles que puede usar con File Objects.

  • seek(): La función se puede utilizar para mover el cursor de lectura/escritura a una nueva ubicación. seek(0) , por ejemplo, moverá el cursor al principio del archivo.
  • position(): devuelve la ubicación del cursor en el archivo.
  • size(): devuelve el número de bytes de un archivo si desea conocer su tamaño.
  • isDirectory(): La función se puede utilizar para determinar si un archivo es un directorio.
  • openNextFile(): La función se puede utilizar para examinar todos los archivos de un directorio.
  • name(): function se puede utilizar para encontrar el nombre de un archivo mientras navega por un directorio con la función openNextFile(). Devuelve un puntero a una matriz de caracteres con formato 8.3, que se puede imprimir directamente mediante Serial.print().

Traducido desde: In-Depth Tutorial to Interface Micro SD Card Module with Arduino (lastminuteengineers.com)