lunes, 3 de agosto de 2015

Reproductor MP3 controlado mediante IR


Tras meses de no haber publicado nada (muchos proyectos nuevos de por medio + trabajo + vida familiar = 0 publicaciones), traigo el tercer tutorial sobre arduino. En esta ocasión se trata de manejar un reproductor mp3 serie mediante un mando de infrarrojos. ¿Te interesa? Estás invitado!

Utilizaremos el sensor de IR y el mando del anterior tutorial además de un reproductor mp3 serie como este:


Por unos 6€ tendemos un reproductor mp3 de la marca Catalex, versátil, pequeño y con la particularidad de que es manejado mediante comunicación serie con Arduino y que podemos utilizar en multitud de proyectos.

Mi intención es hacer una pequeña demostración de cómo podemos manejar el reproductor con un pequeño mando de infrarrojos. El esquema de conexión es el siguiente:


Como podemos observar, solo necesitamos dos entradas de nuestra placa Arduino para manejar el reproductor mp3 (no es necesario que sean las entradas 0 y 1 de nuestra placa), y una entrada más para el sensor de IR. Aquí podéis leer el manual de uso del reproductor

Y ahora pasamos al código de Arduino para manejar el reproductor.
//Librería para el mando IR
#include <Adafruit_NECremote.h>

//Códigos de los botones del mando
#define btn_power 0
#define btn_vol_mas 1
#define btn_stop 2
#define btn_pista_atras 4
#define btn_play 5
#define btn_pista_siguiente 6
#define btn_abajo 8
#define btn_vol_menos 9
#define btn_arriba 10
#define btn_0 12
#define btn_eq 13
#define btn_REPT 14
#define btn_1 16
#define btn_2 17
#define btn_3 18
#define btn_4 20
#define btn_5 21
#define btn_6 22
#define btn_7 24
#define btn_8 25
#define btn_9 26

//Pin del IR
#define IRpin 4
Adafruit_NECremote remote(IRpin);

Declaramos la librería para el recertor IR y los códigos de los botones del mando. Recuerda que los códigos son los de mi mando, para descubrir los códigos de tu mando puedes utilizar el programa que os mostré en el tutorial anterior.

//MP3
#include <SoftwareSerial.h>

//Conexiones MP3
#define ARDUINO_RX 5//conectar a entrada TX del módulo MP3
#define ARDUINO_TX 6//conectar a entrada RX del módulo MP3
SoftwareSerial mySerial(ARDUINO_RX, ARDUINO_TX);

unsigned char playmode = 0; //inicialmente el reproductor estará en pause
#define PLAY  1
#define PAUSE 0
static int8_t Send_buf[8] = {0} ;//Buffer de 8 bytes que mandaremos por serie

int8_t volumen = 0x0f; //Volumen inicial
int8_t carpeta = 0x01; //Carpeta seleccionada
int8_t cancion = 0x01; //Pista seleccionada


//Comandos MP3
#define CMD_NEXT_SONG 0X01
#define CMD_PREV_SONG 0X02
#define CMD_PLAY_W_INDEX 0X03
#define CMD_VOLUME_UP 0X04
#define CMD_VOLUME_DOWN 0X05
#define CMD_SET_VOLUME 0X06
#define CMD_SINGLE_CYCLE_PLAY 0X08
#define CMD_SEL_DEV 0X09
#define DEV_TF 0X02
#define CMD_SLEEP_MODE 0X0A
#define CMD_WAKE_UP 0X0B
#define CMD_RESET 0X0C
#define CMD_PLAY 0X0D
#define CMD_PAUSE 0X0E
#define CMD_PLAY_FOLDER_FILE 0X0F
#define CMD_STOP_PLAY 0X16
#define CMD_FOLDER_CYCLE 0X17
#define CMD_SET_SINGLE_CYCLE 0X19
#define SINGLE_CYCLE_ON 0X00
#define SINGLE_CYCLE_OFF 0X01
#define CMD_SET_DAC 0X1A
#define DAC_ON  0X00
#define DAC_OFF 0X01
#define CMD_PLAY_W_VOL 0X22

Declaramos la librería SoftwareSerial de Arduino que nos permite utilizar pines digitales para utilizarlos en comunicación serie. Definimos los pines 5 y 6 que actuarán como RX y TX respectivamente. Inicializamos el puerto de comunicación serie (mySerial), la variable "playmode" que nos indicará si estamos en pausa o en play, definimos el buffer de 8 bytes que utilizaremos para mandar los comandos al reproductor MP3 y por último los códigos de los comandos que acepta el mp3.

void setup()
{
  mySerial.begin(9600);
  delay(500);//Esperar para que inicialice el chip
    sendCommand(CMD_SEL_DEV, DEV_TF);//Seleccionar la tarjeta SD
  delay(200);//retraso
  sendCommand(CMD_SET_VOLUME, volumen);//Inicializamos el volumen a 15
}

 En el bloque setup inicializamos el puerto serie a 9600 bps, seleccionamos la tarjeta sd del módulo mp3 y inicializamos el volumen a 15 (la mitad de los niveles de volumen que admite el reproductor).

void loop(){
  //pulsación mando IR
  int c = remote.listen(); //Leemos el IR

  // Play / Pause
  if(c == btn_play){
    playOrPause();
  }
  // Stop
  if(c == btn_stop){
    sendCommand(CMD_STOP_PLAY,0);
  }
  //Volumen +
  if(c == btn_vol_mas){
    if(volumen<30) volumen++;
    sendCommand(CMD_VOLUME_UP,0);
  }
  //Volumen -
  if(c == btn_vol_menos){
    if(volumen>0) volumen--;
    sendCommand(CMD_VOLUME_DOWN,0);
  }
  // NEXT
  if(c == btn_pista_siguiente){
    sendCommand(CMD_NEXT_SONG,0);
  }
  // PREV
  if(c == btn_pista_atras){
    sendCommand(CMD_PREV_SONG,0);
  }
  // Siguiente Carpeta
  if(c == btn_arriba){
    if(carpeta<3) {
      carpeta++;
      cancion=0x01;
      sendCommand(CMD_FOLDER_CYCLE,carpeta,cancion);
    }
  }
  // Anterior Carpeta
  if(c == btn_abajo){
    if(carpeta>1) {
      carpeta--;
      cancion=0x01;
      sendCommand(CMD_FOLDER_CYCLE,carpeta,cancion);
    }
  }
  //Poner pista directamente
  if(c == btn_REPT){
    sendCommand(CMD_PLAY_FOLDER_FILE, 0x03, 0x10);// Pista 10 de la carpeta 3
  }
}
En el bloque loop, muestreamos el puerto de infrarrojos esperando la pulsación de algún botón. Según el botón pulsado mandaremos el comando correspondiente. Aclaración: en la tarjeta SD hay tres carpetas llamadas 01, 02 y 03. Los archivos se llaman 001XXX.mp3, 002XXX.mp3. Es así para poder reproducir una pista de una carpeta en concreto.

Y por último tenemos las funciones auxiliares:

void sendCommand(int8_t command, int16_t dat)
{
  delay(20);
  Send_buf[0] = 0x7e; //starting byte
  Send_buf[1] = 0xff; //version
  Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
  Send_buf[3] = command; //
  Send_buf[4] = 0x00;//0x00 = no feedback, 0x01 = feedback
  Send_buf[5] = (int8_t)(dat >> 8);//datah
  Send_buf[6] = (int8_t)(dat); //datal
  Send_buf[7] = 0xef; //ending byte
  for(uint8_t i=0; i<8; i++)//
  {
    mySerial.write(Send_buf[i]) ;
  }
}

void sendCommand(int8_t command, int8_t dat0, int8_t dat1)
{
  delay(20);
  Send_buf[0] = 0x7e; //starting byte
  Send_buf[1] = 0xff; //version
  Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
  Send_buf[3] = command; //
  Send_buf[4] = 0x00;//0x00 = no feedback, 0x01 = feedback
  Send_buf[5] = dat0;//data0
  Send_buf[6] = dat1; //datal
  Send_buf[7] = 0xef; //ending byte
  for(uint8_t i=0; i<8; i++)//
  {
    mySerial.write(Send_buf[i]) ;
  }
}

void playOrPause()
{
  cli();
  if(playmode == PLAY)
  {
    playmode = PAUSE;
    sendCommand(CMD_PAUSE,0);
  }
  else
  {
    playmode = PLAY;
    sendCommand(CMD_PLAY,0);
  }
  sei();
}

La función sendCommand en sus dos variantes son las que se encargan de mandar los comandos via serie al reproductor. En la mayoría de los comandos nos basta con un byte de datos para utilizarlo, pero otros comandos, como reproducir una canción de una carpeta en concreto, necesitaremos dos bytes (uno para indicar la carpeta y otro para la pista). En cuanto a la función PlayOrPause es simplemente verificar si estamos en pause para mandar el comando play o viceversa.

Como veis, es muy simple de utilizar y no os costará ningún esfuerzo añadir más funcionalidades al código. Os dejo el enlace para que lo podáis descargar.

Espero que os haya gustado. Os dejo el vídeo de prueba para ver el reproductor en funcionamiento.


No hay comentarios:

Publicar un comentario