Una tarjeta microSD es un medio de almacenamiento externo y extraíble que podemos usar desde MicroPython.
El sistema de archivos interno (que vimos en el capítulo anterior) es fantástico, pero tiene dos limitaciones grandes: es pequeño (unos pocos megabytes) y es difícil de extraer (tienes que usar herramientas para descargar los archivos).
Si estamos construyendo una estación meteorológica, un GPS tracker o una caja negra para un vehículo, necesitamos espacio de verdad. Necesitamos Gigabytes.
La solución estándar en la industria es usar una Tarjeta microSD. Son baratas, fiables y, lo mejor de todo, podemos sacar la tarjeta, meterla en el PC y abrir el archivo .csv en Excel directamente.
Hardware: módulo microSD y SPI
Las tarjetas SD pueden funcionar en dos modos: SDIO (más rápido, pero complejo y requiere pines específicos) y SPI (más lento, pero funciona en cualquier microcontrolador).
En MicroPython, casi siempre usaremos el modo SPI.
Necesitamos un Módulo lector de microSD.
- VCC: 5V o 3.3V (Depende del módulo. Muchos módulos azules traen regulador y aceptan 5V. Si usas un adaptador simple “breakout”, va estrictamente a 3.3V).
- GND: Tierra.
- SCK, MOSI, MISO: Pines del bus SPI.
- CS (Chip Select): El pin para activar la tarjeta.
Voltaje Lógico Las tarjetas SD funcionan estrictamente a 3.3V. Si usas un Arduino de 5V quemarías la tarjeta. Pero como estamos usando ESP32 o Raspberry Pi Pico (que son de 3.3V), podemos conectar los pines de datos (MOSI, MISO, SCK, CS) directamente sin miedo.
El driver sdcard.py
A diferencia del driver de la pantalla OLED o el bus OneWire, el driver para tarjetas SD no suele venir pre-instalado en el firmware base de MicroPython (para ahorrar espacio).
Tenemos que instalarlo. Es el driver oficial mantenido por MicroPython.
Si tienes conexión WiFi configurada (vía mip):
import mip
mip.install("sdcard")
Si no, descarga el archivo sdcard.py del repositorio oficial de MicroPython y súbelo a la raíz de tu placa con Thonny.
Montar el sistema de archivos
Aquí viene el concepto clave: Montar (Mounting).
El sistema operativo no sabe qué hay dentro de la tarjeta SD. Nosotros tenemos que decirle: “Oye, coge este dispositivo físico y haz que sus archivos aparezcan dentro de la carpeta /sd”.
Esto se hace con el módulo os y la clase VfsFat (Virtual File System FAT).
Inicialización y montaje
Vamos a conectar una SD a un ESP32 usando el bus SPI estándar (VSPI).
import machine
import os
import sdcard
# 1. Configuración del SPI (Hardware SPI)
# Pines para ESP32 (VSPI): SCK=18, MOSI=23, MISO=19
# Pin CS (Chip Select): Podemos usar cualquiera, ej. GPIO 5
cs = machine.Pin(5, machine.Pin.OUT)
spi = machine.SPI(2, baudrate=1000000, polarity=0, phase=0, sck=machine.Pin(18), mosi=machine.Pin(23), miso=machine.Pin(19))
# 2. Inicializar la tarjeta SD
try:
sd = sdcard.SDCard(spi, cs)
# 3. Montar el sistema de archivos
# El primer argumento es el objeto de bloque (la tarjeta)
# El segundo es la ruta donde queremos verla ('/sd')
vfs = os.VfsFat(sd)
os.mount(vfs, "/sd")
print("Tarjeta SD montada correctamente en /sd")
# Listamos para comprobar
print("Archivos en la SD:", os.listdir("/sd"))
except OSError as e:
print("Error al montar la SD:", e)
Si intentas montar la tarjeta y ya estaba montada (por ejemplo, si ejecutas el script dos veces sin reiniciar), te dará error. Es buena práctica comprobarlo o capturar la excepción.
Guardar medidas en la tarjeta SD
Una vez montada, usarla es tan fácil como usar la memoria interna. La única diferencia es que la ruta del archivo debe empezar por /sd/.
Vamos a crear un Datalogger que guarde datos simulados en formato CSV (Valores separados por comas), el formato favorito de Excel.
import time
import random
# Ruta del archivo en la tarjeta
FILENAME = "/sd/log_datos.csv"
def escribir_cabecera():
# Comprobamos si el archivo existe para no borrar la cabecera si reiniciamos
try:
os.stat(FILENAME)
print("El archivo ya existe. Añadiendo datos...")
except OSError:
print("Creando archivo nuevo con cabecera...")
with open(FILENAME, "w") as f:
f.write("Timestamp,Temperatura,Humedad\n")
def registrar_dato(temp, hum):
t = time.localtime()
timestamp = "{:02d}/{:02d}/{} {:02d}:{:02d}:{:02d}".format(t[2], t[1], t[0], t[3], t[4], t[5])
# Formato CSV: fecha, dato1, dato2
linea = "{},{},{}\n".format(timestamp, temp, hum)
# IMPORTANTE: Modo 'a' (Append) para añadir al final
with open(FILENAME, "a") as f:
f.write(linea)
print("Guardado:", linea.strip())
# --- Programa Principal ---
escribir_cabecera()
while True:
# Simulamos lectura de sensores
temperatura = random.randint(20, 30)
humedad = random.randint(40, 60)
registrar_dato(temperatura, humedad)
# Es importante sincronizar/guardar periodicamente.
# El 'with open' ya se encarga de cerrar y guardar (flush) en cada vuelta.
time.sleep(5)
Buenas prácticas con tarjetas SD
Trabajar con SDs tiene sus riesgos. Aquí van los consejos de veterano:
- Formato FAT32: Asegúrate de que tu tarjeta está formateada en FAT16 o FAT32. Las tarjetas muy nuevas o grandes (64GB+) suelen venir en exFAT, que MicroPython NO soporta por defecto. Usa tarjetas de 32GB o menos, o re-formatéalas a FAT32.
- El LED parpadeante: Algunos módulos SD tienen un LED que parpadea al escribir. Nunca quites la alimentación mientras ese LED esté activo, o corromperás el sistema de archivos.
- Cierre de archivos: Fíjate que en el ejemplo usamos
with open(...). Esto asegura que el archivo se cierra (close()) inmediatamente después de escribir. Si dejas el archivo abierto y se va la luz, perderás los datos que estaban en el búfer de memoria RAM y no llegaron a escribirse en la tarjeta. - Consumo: Las tarjetas SD consumen bastante (pueden tener picos de 100mA al escribir). Asegúrate de que tu fuente de alimentación es estable.
Desmontar la tarjeta
Si quieres expulsar la tarjeta por software (para que sea seguro retirarla), usamos umount.
os.umount("/sd")
Con esto, ya no tenemos límite de memoria. Podemos guardar logs de temperatura cada segundo durante años sin llenar la tarjeta. ¡El límite ahora es tu imaginación (y la batería)!