Empiezo el blog con una serie de artículos en los que construiré una caja musical que al abrirla reproduzca un fichero mp3 aleatorio almacenado en una tarjeta SD. Para ello añadiremos la circuitería necesaria a una caja de madera.
Vamos a empezar conectando un módulo lector de tarjetas SD a un microcontrolador
Arduino uno. Nuestro módulo lector de tarjetas es un YL-30.
La conexión de los pines al microcontrolador es el siguiente:
Pin CS (Chip Select) al pin digital 10
Pin MOSI (Master Out Slave In) al pin digital 11
Pin MISO (Master In Slave Out) al pin digital 12
Pin SCK (System Clock) al pin digital 13
Pin +5V al pin 5V
Pin GND al pin GND
Es importante no cambiar la conexión de los pines ya que en el sketch vamos a usar la biblioteca
SD de arduino, que a su vez usa la
SPI,para acceder al sistema de ficheros de la tarjeta. Esta biblioteca usa estos pines para comunicarse con el módulo YL-30.
Y aquí lo tenemos montado en la placa de prototipo
El sketch
Una vez montado nuestro prototipo tenemos que crear un sketch que generará un número aleatorio y seleccionará el fichero de la tarjeta que corresponda al número generado. Para ello usaremos el
entorno de programación de arduino.
#include <SD.h>
bool isSdOpened;
File root;
File entry;
long fileCount;
void setup(){
pinMode(10,OUTPUT);
isSdOpened=SD.begin(10);
Serial.begin(9600);
Serial.print("SD.begin ");
Serial.println(isSdOpened);
root=SD.open("/");
root.rewindDirectory();
fileCount=0;
entry=root.openNextFile();
while(entry){
fileCount++;
Serial.print(entry.name());
Serial.print("\t");
if(entry.isDirectory()){
Serial.println("Directorio");
}
else{
Serial.println(entry.size(), DEC);
}
entry.close();
entry=root.openNextFile();
}
root.rewindDirectory();
Serial.print("Numero de ficheros: ");
Serial.println(fileCount);
randomSeed(analogRead(0));
}
void loop(){
root.rewindDirectory();
int randNumber = random(1,fileCount+1);
for(int i=0;i<randNumber;i++){
entry=root.openNextFile();
entry.close();
}
Serial.print("Numero aleatorio: ");
Serial.println(randNumber);
Serial.print("Fichero: ");
Serial.println(entry.name());
delay(10000);
}
Más información sobre el lenguaje de programación de arduino
aquí. Está basado en C y básicamente lo que hace es ejecutar una vez la función
setup y repetir indefinidamente la función
loop.
Comentarios al código fuente
La primera instrucción de la función setup
pinMode(10,OUTPUT) pone el pin al que hemos conectado el pin CS del módulo SD en modo salida. Sin esta instrucción las demás funciones de acceso a los ficheros de la tarjeta no funcionarán.
La siguiente instrucción
isSdOpened=SD.begin(10) inicializa el módulo lector para que podamos usarlo. Por defecto usa el pin 10 del microcontrolador, así que si lo hemos montado tal como indica el esquema la podemos pasar sin parámetros.
Siguiendo con la función setup, una vez inicializado el módulo abrimos el directorio raiz con la instrucción
root=SD.open("/"). La siguiente instrucción
root.rewindDirectory() lo que hace es volver al primer fichero del directorio y en teoría no es necesaria cuando acabas de abrir un directorio, pero parece ser que hay un bug que provoca errores si no se rebobina el directorio al abrirlo. Una vez abierto el directorio, lo recorremos en el bucle while para contar el número de ficheros y poder sacar así el número aleatorio dentro del rango correcto.
Un detalle muy importante a tener en cuenta es que los experimentos se hacen con gaseosa, es decir, no uses la tarjeta SD de tu cámara cuyas fotos aún no has pasado al ordenador para hacer las pruebas porque lo puedes lamentar amargamente. Y lo digo por las instrucciones
entry=root.openNextFile() y
entry.close(), que hacen lo que indica su nombre, abrir y cerrar ficheros. El peligro, que he tenido ocasión de comprobar, es que una operación de apertura sin su correspondiente cierre puede corromper el fichero.
En la instrucción
randomSeed(analogRead(0)) inicializa el generador aleatorio de números para que la función
random() no genere siempre la misma secuencia de números aleatorios. El uso de la función
analogRead(0) como parámetro de randomSeed() es porque necesitamos inicializar el generador de números aleatorios con un número diferente cada vez. En un ordenador lo haríamos pasando como parámetro a randomSeed() la hora del sistema, pero nuestro microcontrolador no tiene reloj así que lo que hacemos es leer de un pin que no está conectado a nada cuyo valor es imprevisible. El
problema es que la función analogRead() devuelve un valor entre 0 y 1023, con lo cual es bastante probable que con el uso se repitan secuencias de números, pero como tampoco vamos a generar claves de cifrado no creo que suponga mucho inconveniente.
La salida del sketch por el puerto serie es la siguiente:
SD.begin 1
01-BOB~1.MP3
3368960
02-BOB~1.MP3
3897344
03-BOB~1.MP3
4413505
04-BOB~1.MP3
6598656
05-BOB~1.MP3
7415808
06-BOB~1.MP3
5928960
07-BOB~1.MP3
3074048
08-BOB~1.MP3
4009984
09-BOB~1.MP3
3710976
10-BOB~1.MP3
3268608
11-BOB~1.MP3
3045376
12-BOB~1.MP3
5967872
13-BOB~1.MP3
6866944
14-BOB~1.MP3
4851712
15-BOB~1.MP3
6514688
16-BOB~1.MP3
7540736
17-BOB~1.MP3
3913728
18-BOB~1.MP3
7213056
Numero de ficheros: 18
Numero aleatorio: 17
Fichero: 17-BOB~1.MP3
Numero aleatorio: 8
Fichero: 08-BOB~1.MP3
Numero aleatorio: 16
Fichero: 16-BOB~1.MP3
Numero aleatorio: 8
Fichero: 08-BOB~1.MP3
Numero aleatorio: 1
Fichero: 01-BOB~1.MP3
Numero aleatorio: 10
Fichero: 10-BOB~1.MP3
Numero aleatorio: 5
Fichero: 05-BOB~1.MP3
Numero aleatorio: 8
Fichero: 08-BOB~1.MP3
Numero aleatorio: 7
Fichero: 07-BOB~1.MP3
Numero aleatorio: 12
Fichero: 12-BOB~1.MP3
Numero aleatorio: 14
Fichero: 14-BOB~1.MP3
Los más viejos del lugar habrán reconocido la estructura 8+3 de los ficheros que se usaba en windows 95 y 98. La biblioteca
SD de arduino sólo soporta los sistemas de ficheros
FAT16 y
FAT32, pero para el caso que nos ocupa es más que suficiente.
En la próxima entrega conectaremos el módulo reproductor de MP3 al prototipo que hemos creado y modificaremos el sketch para que reproduzca el fichero que hemos seleccionado aleatoriamente.