31 julho 2014

Ligando um Sensor de Nível de Líquidos ao Arduino

Esse post é parte de um projeto um pouco maior, mas que não consegui montar ainda simplesmente pela falta de peças. Então vou começar falando apenas do sensor de nível de líquidos, que é um sensor feito de material plástico (PP, segundo o fabricante), composto de uma haste na qual desliza um cilindro feito de material flutuante.

Sensor de nivel de liquido Arduino
 
Esse cilindro possui um ímã que aciona um sensor magnético no meio da haste, que por sua vez fecha o contato dos 2 fios que saem do sensor. Isso mesmo. É uma boia com fios.

Veja na imagem abaixo que o cilindro possui internamente apenas uma pequena parte preenchida com o ímã, o que torna possível invertermos o cilindro e termos um contato normal aberto ou normal fechado, adaptando o sensor às nossas necessidades :

Sensor de liquido - Detalhe


Sozinho, pode por exemplo ser usado como uma chave que é acionada quando um reservatório está cheio (colocando o sensor na parte de cima do reservatório), ou vazio (colocando o sensor na parte de baixo).

Com mais sensores, eu posso controlar vários níveis em um tanque, indicando ao Arduino se o meu tanque está cheio, pela metade ou (quase) vazio.

Sensor de liquido - Vários sensores

Uma ligação básica com apenas um sensor pode ser feita montando esse circuito...


Circuito Arduino e sensor de nivel de liquido
...e carregando esse programa, que acende o led verde quando o reservatório está cheio, e o led vermelho quando o nível do reservatório estiver abaixo do nível máximo :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Programa : Teste sensor liquido Arduino
// Autor : Arduino e Cia

// Pino ligado ao sensor de nivel de liquido
int pinosensor = 3;
// Led verde
int pino_led_cheio = 6;
// Led vermelho
int pino_led_vazio = 7;

void setup()
{
  Serial.begin(9600);
  pinMode(pinosensor, INPUT);
  pinMode(pino_led_cheio, OUTPUT);
  pinMode(pino_led_vazio, OUTPUT);
}

void loop()
{
  int estado = digitalRead(pinosensor);
  Serial.print("Estado sensor : ");
  Serial.println(estado);
  switch(estado)
  {
  case 0:
    digitalWrite(pino_led_vazio, LOW);
    digitalWrite(pino_led_cheio, HIGH);
    break;
  case 1:
    digitalWrite(pino_led_vazio, HIGH);
    digitalWrite(pino_led_cheio, LOW);
    break;
  }
  delay(100);
}

Por enquanto é só. Retorno à esse assunto assim que chegar o resto do material para o meu projeto :-)

29 julho 2014

Módulo sensor de linha analógico QRE1113 Sparkfun

Se você precisa montar um robô seguidor de linha, o módulo sensor de linha QRE1113 da Sparkfun pode ser uma peça importante do seu projeto.

Módulo sensor de linha analógico QRE1113 Sparkfun


O módulo QRE1113 é composto por um led infravermelho e um fototransistor e é do tipo analógico, ou seja, varia a tensão de saída de acordo com a quantidade de luz detectada pelo receptor. Por ter um tamanho bem reduzido (14 x 8 mm), é ideal para construção de robôs seguidores de linha.

O módulo sensor de linha analógico QRE1113


São apenas 3 pinos no módulo : Vcc (5 volts), GND e OUT (Sinal), sendo que este último aceita níveis de tensão de 3.3 à 5v, portanto você pode utilizar esse sensor tanto em sistemas mais comuns, com o Arduino Uno, como em sistemas que utilizem, por exemplo, o Arduino Due, que trabalha com níveis de sinal de 3.3v.
Sensor de linha Sparkfun - Pinagem

O funcionamento é simples : quanto mais luz for recebida pelo sensor, menor será a tensão na saída, assim você pode usar um conjunto de sensores e ajustar, por exemplo, a direção e/ou velocidade dos motores direito e esquerdo do seu robô conforme uma linha for detectada.

Circuito sensor de linha QRE1113 Sparkfun


E como eu faço para ler isso ? Usando uma das portas analógicas do Arduino, e enviando os dados para o serial monitor, que vai mostrar que quanto mais clara a superfície que estamos testando, mais ela vai refletir a luz IR, e mais baixo vai ser o nível de tensão na saída do módulo.

Circuito Arduino e sensor de linha Sparkfun
No programa, nada de bibliotecas específicas ou comandos complicados. Você pode utilizar somente comandos básicos do Arduino para testar o sensor e enviar os dados para a serial. No nosso exemplo, vamos ler o valor da porta analógica A3, e mostrar o nível de tensão na saída do módulo a cada 500 ms. Também vamos acender um led quando a tensão atingir um determinado valor (variável nivel_sinal) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Programa : Teste sensor de linha QRE1113 Sparkfun
//Autor : Arduino e Cia

int nivel_sinal = 0;
int pino_led = 4;
int pino_sensor = A3;

void setup()
{
  pinMode(pino_led, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  //Leitura do sensor
  nivel_sinal = analogRead(pino_sensor);
  //Envia os dados para o serial monitor
  Serial.print("Nivel : ");
  Serial.println(nivel_sinal);
  //Teste o nivel de sinal e acende o led
  if (nivel_sinal < 1000)
  {
    digitalWrite(pino_led, HIGH);
  }
  else
  {
    digitalWrite(pino_led, LOW);
  }
  
  //Aguarda 500 ms e reinicia o processo
  delay(500);
}

Aproxime diferentes materiais do sensor para verificar a variação do sinal na saída do módulo. Cores mais escuras refletem menos a luz, e consequentemente geram menos variação de sinal. O contrário acontece com as cores claras.

Ajuste os valores da variável nivel_sinal para adequar a sensibiidade do sensor às necessidades do seu projeto, ou ainda inclua outras variáveis para testar diferentes níveis de luminosidade.

24 julho 2014

Detectando campos magnéticos com o Sensor Hall KY-003

Sensor de campo magnético hall é um sensor que usa o efeito hall para detectar a aproximação de um campo magnético do sensor, gerando em sua saída um valor analógico ou digital, dependendo do tipo de construção do módulo.

Sensor Hall KY-003 Arduino



Existem diversos tipos de sensor hall para utilização com Arduino. Alguns deles detectam a variação e intensidade do campo magnético e transferem essas informações ao pino de sinal de forma analógica, permitindo medir essa variação de forma confiável e precisa.

Outros trabalham apenas com a saída de forma digital, que é o caso do Sensor Hall KY-003 que eu testei. Aproxime um ímã do sensor e você terá o valor 0 no pino de saída. Na ausência de campo magnético, o valor se manterá estável em 1. 

Desta forma, o funcionamento é o mesmo de qualquer outro sensor ou botão que utilizamos com o Arduino : ligamos o pino de sinal do módulo sensor hall à uma porta digital, e tomamos uma ação de acordo com o estado 0 ou 1 dessa porta.

Esse tipo de sensor é ideal para configurações onde não há possibilidade ou necessidade de contato, como em um medidor de RPM de um motor ou um sistema de alarmes.

Esse módulo pode ser alimentado (pino central) com os próprios 5v do Arduino (tensão máxima suportada pelo módulo é de 24v DC). Conecte o pino da esquerda (-) ao GND e o pino da direita (S) à porta digital do seu Arduino. Um led no lado esquerdo da placa indica a presença de sinal no pino de saída:

Sensor Hall - Pinagem

Circuito Arduino e sensor hall KY-003


O programa que utilizei para testar esse circuito é o mesmo que já usei no artigo Ligando uma lâmpada com relé e push-button, com pequenas alterações quanto às portas. A cada acionamento do sensor hall, o estado do led é invertido e permanece assim até que o sensor seja novamente acionado :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Programa : Teste de acionamento Sensor Hall KY-003
// Autor : Arduino e Cia

// define a porta para o acionamento do led
int pinoled = 6;      
// Porta ligada ao pino SINAL do sensor
int pinosinal = 4;    
// Armazena informações sobre a leitura do sensor
int leitura;          
// Armazena o estado do led (ligado/desligado)
int estadoled = 0;   

void setup()
{
  //Define o pino do led como saida
  pinMode(pinoled, OUTPUT); 

  //Define o pino do sensor hall como entrada
  pinMode(pinosinal, INPUT);      

}

void loop()
{
  leitura = digitalRead(pinosinal);
  if (leitura != 1)
  {
    while(digitalRead(pinosinal) != 1)
    {
      delay(100);
    }
    // Inverte o estado
    estadoled = !estadoled;
    digitalWrite(pinoled , estadoled);  
  } 
}


21 julho 2014

Controlando motores de passo 28BYJ-48 com o Arduino Motor Shield L293D

Conforme prometido no artigo Controlando motores DC com o Arduino Motor Shield L293D, hoje vou apresentar o esquema de funcionamento desse shield com o nosso também já conhecido Motor de Passo 28BYJ-48 Arduino (foto abaixo).

Atualizado : Controle também servo motores com o Motor Shield L293D. Veja no artigo  Controlando servo motor com o Motor Shield L293D.

Motor de passo 5v 28BYJ-48


O motor de passo 28BYJ-48 funciona com alimentação de 5V e possui uma redução de 1/64. Essa redução faz com que o número de passos necessários para que o motor dê uma volta completa seja de 4096, ou no modo de ativação de 4 passos, esse número cai pela metade, para 2048.

"Peraí, modo de ativação de 4 passos ? O que é isso ?"

O motor de passo pode funcionar em 2 modos de ativação : 8 passos (half-mode) ou 4 passos (full step). No modo de ativação de 8 passos, a sequência de acionamento das bobinas segue a tabela abaixo. Primeiro é acionada uma bobina, depois duas, depois uma, depois duas novamente, e assim por diante, até se completarem os 8 passos :

Motor de passo - bobinas

Motor de passo - Modo de ativação de 8 passos



Já no modo de 4 passos, são acionadas 2 bobinas de cada vez, o que reduz o número de acionamentos necessários para movimentar o motor :

Motor de passo - Modo de ativação de 4 passos

O modo de acionamento de 4 passos é utilizado pela biblioteca padrão do Arduino, e teoricamente imprime mais força ao motor, já que sempre teremos duas bobinas sendo acionadas ao mesmo tempo.

Relembrando um pouco sobre o funcionamento do Motor Shield L293D, vimos que ele pode controlar 2 servos, e até 4 motores DC ou 2 motores de passo. Para controlar motores de passo, utilizamos os conectores laterais, os mesmos usados para controlar motores DC :

Motor Shield L293D - Detalhe conectores


Vamos ligar não só um, mas dois motores de passo 28BYJ-48 nessa placa (muito útil para um robô, não ?). Atenção para a ordem de ligação dos fios desse motor, que deve ser a mesma do circuito abaixo. A alimentação será feita por meio dos 5V do próprio Arduino Uno, que usaremos nos testes, por isso vamos manter o jumper PWR na placa.

Circuito Arduino Motor de passo 28BYJ-48 e Motor Shield
 
A biblioteca utilizada para controlar os motores de passo é a AFMotor, que você pode baixar nesse link. Descompacte o arquivo, renomeie a pasta para AFMotor e coloque-a dentro da pasta LIBRARIES da IDE do seu Arduino.

Para controle de motor de passo, os principais comandos do programa são :

  • AF_Stepper nome(passos, porta) - Define o nome dado ao motor de passo, o número total de passos desse motor (para dar uma volta completa) e a porta à qual esse motor está ligado. A porta pode ter o valor 1 para motores ligados no conector do lado esquerdo (M1 / GND / M2), ou o valor 2 para motores ligados no conector do lado direito (M3 / GND / M4)
  • nome.step(numero_passos, direção, tipo_passo) - São os comandos de movimentação do motor identificado por nome. Numero_passos é a quantidade de passos que o motor vai girar ao executar o comando. Os comandos de direção podem ser o FORWARD (gira o motor no sentido horário) ou BACKWARD (gira o motor no sentido anti-horário). Tipo_passo determina de que maneira as bobinas serão acionadas, sendo que pode ser definido como SINGLE (uma bobina por vez), DOUBLE (duas bobinas por vez), INTERLEAVE (alternando entre 1 e 2 bobinas, aumentando a precisão) e MICROSTEPPING, que rotaciona o motor de uma forma mais suave e precisa. Não são todos os motores de passo que aceitam os modos  INTERLEAVE e o MICROSTEPPING.

O programa gira os dois motores de passo, alternadamente, um em cada direção. A cada ciclo, o motor se move na quantidade de graus definida na variável angulo, no início do programa.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Programa : Controlando 2 motores de passo 28BYJ-48 com 
// Arduino Motor Shield L293D
// Autor : Arduino e Cia
 
// Carrega a biblioteca AFMotor 
#include <AFMotor.h>

//Numero de passos para 1 rotacao total
double passos_total = 2048; 
 
// Define as portas para os motores
// Valor 1 para motor em M1/M2 e 2 para motor em M3/M4
int porta_motor_1 = 1; 
int porta_motor_2 = 2;

// Angulo de rotacao do eixo
int angulo = 45; 
 
// Armazena o numero de passos que o motor vai girar
double numero_de_passos = 0; 
 
// Define os parametros do motor 1
AF_Stepper motor_de_passo_1(passos_total, porta_motor_1); 
// Define os parametros do motor 2
AF_Stepper motor_de_passo_2(passos_total, porta_motor_2);
 
void setup()
{
  // Define a velocidade de rotacao do motor 1
  motor_de_passo_1.setSpeed(10);
  // Define a velocidade de rotacao do motor 2
  motor_de_passo_2.setSpeed(10);
  // Inicializa a serial
  Serial.begin(9600);
}
 
void loop()
{
  //Calcula a quantidade de passos, baseado no angulo determinado
  numero_de_passos = angulo / (360 / passos_total);
 
  //Mostra no serial monitor o numero de passos calculados
  Serial.print("Numero de passos : ");
  Serial.println(numero_de_passos);
 
  //Move o motor 1. Use FORWARD para sentido horario,
  //BACKWARD para anti-horario
  motor_de_passo_1.step(numero_de_passos, FORWARD, SINGLE);
  motor_de_passo_1.release();

  delay(10);

  //Move o motor 1. Use FORWARD para sentido horario,
  //BACKWARD para anti-horario
  motor_de_passo_2.step(numero_de_passos, BACKWARD, SINGLE);
  motor_de_passo_2.release();
 
  delay(500);
}

O funcionamento dessa ligação e do programa apresentados você confere no vídeo abaixo :



Falta agora o controle de Servo Motor com esse shield. Assunto para um próximo post. Até lá !


10 julho 2014

Contador com sensor de proximidade infravermelho

A maioria dos sensores IR que eu testei tem um alcance limitado, de apenas alguns centímetros. São ideais para pequenos projetos, maquetes e simulações.

Um sensor um pouco mais, digamos assim, profissional, é este sensor de proximidade infravermelho, que funciona da mesma maneira que os outros sensores IR mas tem algumas características que facilitam a montagem do seu projeto :

Sensor de proximidade infravermelho

Esse sensor funciona basicamente como todos os outros sensores IR : existe um led emissor IR e um receptor IR, tudo no mesmo componente. As diferenças estão na montagem do sensor e na distância de detecção, que pode variar de 3 à 80 cm, ajustáveis por um parafuso na parte de trás do sensor :


Sensor de proximidade IR - Ajuste


Girando o parafuso no sentido horário ou anti-horário, você aumenta ou diminui, respectivamente, a sensibilidade do sensor. O componente tem 45mm de comprimento e um diâmetro de 17mm, e vem com duas porcas que facilitam a montagem nos mais variados tipos de suporte.

Sensor IR - Suporte

A cabo de ligação do sensor tem 3 pinos, sendo o pino vermelho o Vcc (alimentação de 5 volts), amarelo o pino de sinal, e o preto, o GND. A leitura pode ser feita por meio de uma porta digital ou analógica do Arduino, dependendo do seu projeto.

O funcionamento, como eu comentei, é igual ao de outros sensores IR : o led emite luz infravermelha, que dependendo da superfície é refletida e volta para ser detectada pelo fototransistor, enviando um sinal de 0,3 à 1,5v em nível baixo, e de 2,3 à 5v em nível alto, ao pino de sinal.

Eu utilizei esse sensor para montar um contador que registra a passagem de caixas em uma esteira. A cada 10 caixas, é emitido um sinal sonoro para que o operador do equipamento tome algum tipo de ação :


Circuito Arduino Uno R3 - Sensor de proximidade IR




Os dados são enviados para o serial monitor, apenas para monitoramento do contador, mas um display LCD ou 7 segmentos pode ser facilmente adaptado ao projeto.

O comando while(digitalRead(pinosensor) != 1) evita que o contador seja incrementado caso um objeto pare em frente ao sensor :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Programa : Contador com sensor de proximidade IR
// Autor : Arduino e Cia  

int contador = 0;
int pinosensor = 5;
int pinobuzzer = 7;
int leitura; //Armazena o valor lido pelo sensor  
   
void setup() 
{  
  //Define o pino do sensor como entrada, e o do buzzer como saida
  pinMode(pinosensor, INPUT); 
  pinMode(pinobuzzer, OUTPUT);
  Serial.begin(9600); 
}  
   
void loop() 
{  
  //Le as informações do pino do sensor  
  leitura = digitalRead(pinosensor);   
  if (leitura != 1) //Verifica se o objeto foi detectado  
  {  
    contador = contador++; //Incrementa o valor do contador  
    Serial.print("Contador : ");
    Serial.println(contador);
    //Se o contador atingir 10, aciona o buzzer
    if (contador == 10)
    {
      tone(pinobuzzer,262,500);
      contador = 0;
    }
    //Loop caso o objeto pare na frente do sensor
    while(digitalRead(pinosensor) != 1)  
    {  
      //Comando
    }  
  }   
} 

Abaixo, um vídeo demonstrativo do sensor com um contador até 5 :


03 julho 2014

Controlando motores DC com o Arduino Motor Shield L293D

Aquele seu projeto está ficando grande demais e com muitos motores para controlar ? Talvez seja a hora de partir para um controlador de motores integrado, como o Arduino Motor Shield L293D :

Arduino Motor Shield L293D


Esse shield é compatível com Arduino Uno e Arduino Mega, possui dois chips L293D, cada um composto por 2 pontes H (um conceito que já abordamos no artigo Controle de motor CC com o L293D - Ponte H), além de um CI 74HC595. Tudo isso para controlar até 4 motores DC, 2 Servos (alimentados por 5v) ou 2 motores de passo. Lembrando que a corrente máxima suportada por cada L293D é de 600 mA, com picos de 1.2A.

Nas laterais da placa temos os terminais (com parafusos) para conexão dos motores DC ou motores de passo. Na parte superior esquerda, conectores de 3 pinos permitem a conexão de até 2 servos. Um led na parte central da placa indica não só o funcionamento do shield como também que há alimentação para os motores :

Motor Shield L293D - Detalhe conexões
A tensão de entrada pode variar de 4,5 à 25 Vcc. Para utilização de alimentação externa, não se esqueça de retirar o jumper PWR.

Como a maioria dos shields, você tem à disposição os pinos que sobram quando você não está controlando motores, obviamente, e também alguns pinos que estão sempre disponíveis :

  • Pinos disponíveis : os pinos analógicos de A0 a A5, que também podem ser utilizados como pinos digitais 14 a 19. Também estão disponíveis os pinos 2 e 13.
  • Pinos utilizados para controle de motores DC e motores de passo : 11,3,5 e 6, além dos pinos 4,7, 8 e 12.
  • Pinos utilizados para controle de servo motores : pinos 9 (servo 1) e 10 (servo 2)

Para utilizar os pinos que sobram, você pode soldar uma barra de pinos ao shield nos furos correspondentes, como fizemos no nosso shield :

Motor Shield - Detalhe barra de pinos

Essa é uma visão geral sobre a estrutura desse shield. Para utilizá-lo com o Arduino, precisaremos da biblioteca AFMotor, disponível nesse link.

Quando você descompacta o arquivo, é criada uma pasta chamada adafruit-Adafruit-Motor-Shield-library-4bd21ca. Renomeie essa pasta simplesmente para AFMotor, e coloque-a dentro da pasta LIBRARIES da IDE do seu Arduino.

Se você quiser controlar 2 motores DC de 5 volts, por exemplo, utilize alimentação externa e monte o circuito da seguinte maneira :

Circuito Arduino Motor Shield e motores DC
O programa abaixo gira cada motor em um sentido diferente, e depois de 5 segundos inverte essa rotação. Os principais comandos utilizados são :

motor.setSpeed(velocidade) - Ajusta a velocidade de rotação do motor, podendo ser um valor entre 0 (mínimo) e 255 (máximo)
motor.run(sentido) - Aciona o motor. A variável sentido pode ter o valor FORWARD (move o motor no sentido horário), BACKWARD (sentido inverso/anti-horário) ou RELEASE, que determina a parada do motor :


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Programa : Arduino Motor Shield - Controle motores DC
// Autor : Arduino e Cia
 
// carrega a biblioteca AFMotor
#include <AFMotor.h>

// Define o motor1 ligado a conexao 1
AF_DCMotor motor1(1); 
// Define o motor2 ligado a conexao 4
AF_DCMotor motor2(4); 
 
void setup()
{
  // Define a velocidade maxima para os motores 1 e 2
  motor1.setSpeed(255); 
  motor2.setSpeed(255); 

}
 
void loop()
{
  // Aciona o motor 1 no sentido horario
  motor1.run(FORWARD); 
  // Aciona o motor 2 no sentido anti-horario
  motor2.run(BACKWARD); 
 
  // Aguarda 5 segundos
  delay(5000);

  // Desliga os 2 motores
  motor1.run(RELEASE); 
  motor2.run(RELEASE); 

  // Aciona o motor 1 no sentido anti-horario
  motor1.run(BACKWARD);
  // Aciona o motor 2 no sentido horario
  motor2.run(FORWARD); 
 
  // Aguarda 5 segundos
  delay(5000);
  
  // Desliga os 2 motores
  motor1.run(RELEASE); 
  motor2.run(RELEASE);
}

Em um próximo artigo, vamos mostrar como controlar um motor de passo utilizando o Arduino Motor Shield L293D. Até lá !

Atualizado : Controlando motores de passo 28BYJ-48 com o Arduino Motor Shield L293D 
Veja também : Controlando servo motor com o Motor Shield L293D



01 julho 2014

Arduino Uno e Shield MP3 Player Sparkfun

Que tal aposentar seu celular e ouvir suas músicas em MP3 direto no Arduino ?

OK, substituir o celular pode ser um pouco exagerado, mas você pode utilizar as funcionalidades do Shield MP3 Player Sparkfun e incrementar os seus projetos. Quer exemplos ?

  • Sistemas de identificação com avisos sonoros : Ao invés de enviar os dados para uma tela ou acender alguma lâmpada, o seu sistema de identificação pode "falar" o nome do usuário, recebê-lo com um "Bom dia", "Bem vindo", "Acesso liberado", etc.
  • Utilização em brinquedos : Interação ao apertar botões ou em conjunto com acelerômetro quando há movimentação do brinquedo
  • Projetos de auxílio à pessoas com deficiência visual : um despertador que "fala" as horas, uma caixa de correio que avisa quando há correspondência, um sistema que emite um sinal sonoro quando alguém se aproxima. As possibilidades são infinitas.

Com esse Shield MP3 Player Sparkfun você pode fazer tudo isso. Ele aceita arquivos nos formatos Ogg Vorbis, MP3, AAC, WMA e MIDI, possui uma saída para fone de ouvido padrão P2 (conector 3.5mm stéreo) e permite também a conexão de um alto-falante. Um conector para cartões microSD é o responsável pelo armazenamento dos arquivos de áudio.

Shield MP3 Player Sparkfun
Imagem : Sparkfun

Essa placa não vem com a barra de pinos soldada, assim você pode montar a configuração de sua preferência. Uma opção é soldar barras de pinos como essa abaixo, numa configuração "empilhável":

MP3 Player Shield Sparkfun

Ou você pode soldar uma barra de pinos comum, utilizando apenas os pinos necessários para comunicação com o Arduino e funcionamento do shield MP3, que são os pinos mostrados na figura abaixo:


Pinagem MP3 Shield Sparkfun


Os pinos marcados em azul (2, 3, 4, 6, 7 e 8) são os pinos utilizados pelo CI VS1053, "cérebro" da placa e responsável pelo tratamento do som. O pino em vermelho (9), é utilizado para comunicação com o cartão microSD, e os pinos em roxo (11, 12, 13), são utilizados pelos dois, que se comunicam com o Arduino via interface SPI.

E o que sobra ? Pinos 0 e 1 (RX e TX - Comunicação serial), pinos digitais 5 e 10 (PWM) e os pinos analógicos de A0 a A5.

Legal ! E como eu testo tudo isso ?

Bom, a primeira coisa é você soldar a barra de pinos na configuração de sua preferência. Depois, você deve baixar o arquivo Sparkfun-MP3-Player-Shield-Arduino-Library-master.zip nesse link.

Dentro desse arquivo, você tem as pastas SdFAT e SFEMP3Shield, que são as bibliotecas que devem ser extraídas e colocadas na pasta LIBRARIES dentro da IDE do seu Arduino.

Ligação MP3 Player Shield no Arduino


Se você vai usar a placa como "shield", basta encaixá-la no Arduino e seguir o próximo passo. Se você for utilizar apenas os pinos básicos, sua ligação ficará assim :

Circuito Arduino e MP3 Player Sparkfun
O próximo passo é você gravar alguns arquivos MP3 no cartão SD, que deve ter sido formatado previamente no formato FAT ou FAT32. Lembre-se que por ser formato FAT, os arquivos devem seguir o formato 8.3, ou seja. O nome do arquivo deve conter 8 caracteres, mais 3 caracteres para a extensão.

Assim, no exemplo que vamos utilizar, os nomes dos arquivos devem ser track001.MP3, track002.MP3, e assim sucessivamente.

Programa Arduino e MP3 Player Shield Sparkfun


Carregue o programa abaixo, baseado no arquivo de exemplo que já vem na biblioteca SFEMP3Shield :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
//Programa : Teste MP3 Player Sparkfun
//Autor : Arduino e Cia
//Baseador no programa original de 
//author Bill Porter
//author Michael P. Flaga

#include <SPI.h>

//Bibliotecas para cartao SD
#include <SdFat.h>
#include <SdFatUtil.h>

//Biblioteca do MP3 Shield
#include <SFEMP3Shield.h>

SdFat sd;

SFEMP3Shield MP3player;

void setup() {

  uint8_t result; 

  Serial.begin(115200);

  Serial.print(F("F_CPU = "));
  Serial.println(F_CPU);
  Serial.print(F("Free RAM = ")); 
  Serial.print(FreeRam(), DEC); 
  Serial.println(F(" Should be a base line of 1028, on ATmega328 when using INTx"));


  //Inicializa o cartao SD
  if(!sd.begin(SD_SEL, SPI_FULL_SPEED)) sd.initErrorHalt();
  // depending upon your SdCard environment, SPI_HAVE_SPEED may work better.
  if(!sd.chdir("/")) sd.errorHalt("sd.chdir");

  //Inicializa o MP3 Player Shield
  result = MP3player.begin();
  //Verifica se ha erros na conexao
  if(result != 0) {
    Serial.print(F("Error code: "));
    Serial.print(result);
    Serial.println(F(" when trying to start MP3 player"));
  }

#if defined(__BIOFEEDBACK_MEGA__) // or other reasons, of your choosing.
  // Typically not used by most shields, hence commented out.
  Serial.println(F("Applying ADMixer patch."));
  if(MP3player.ADMixerLoad("admxster.053") == 0) {
    Serial.println(F("Setting ADMixer Volume."));
    MP3player.ADMixerVol(-3);
  }
#endif

  help();
}

void loop() {
  MP3player.available();
  if(Serial.available()) {
    parse_menu(Serial.read()); // get command from serial input
  }
  delay(100);
}

uint32_t  millis_prv;

void parse_menu(byte key_command) {

  uint8_t result; 
  
  //Armazena o titulo da musica
  char title[30]; 
  //Armazena o nome do artista
  char artist[30]; 
  //Armazena o nome do album
  char album[30]; 
  
  Serial.print(F("Received command: "));
  Serial.write(key_command);
  Serial.println(F(" "));

  //Caso s seja recebido, para a reproducao
  if(key_command == 's') {
    Serial.println(F("Stopping"));
    MP3player.stopTrack();

  //Caso um numero de 1 a 9 seja recebido,
  //reproduz o arquivo MP3 correspondente
  } else if(key_command >= '1' && key_command <= '9') {
    //convert ascii numbers to real numbers
    key_command = key_command - 48;

#if USE_MULTIPLE_CARDS
    sd.chvol(); // assign desired sdcard's volume.
#endif
    //Comando para o shield reproduzir a musica
    result = MP3player.playTrack(key_command);

    //Checa por erros na reproducao
    if(result != 0) {
      Serial.print(F("Error code: "));
      Serial.print(result);
      Serial.println(F(" when trying to play track"));
    } else {

      Serial.println(F("Playing:"));

      MP3player.trackTitle((char*)&title);
      MP3player.trackArtist((char*)&artist);
      MP3player.trackAlbum((char*)&album);

      //Imprime as informacoes sobre a musica reproduzida
      Serial.write((byte*)&title, 30);
      Serial.println();
      Serial.print(F("by:  "));
      Serial.write((byte*)&artist, 30);
      Serial.println();
      Serial.print(F("Album:  "));
      Serial.write((byte*)&album, 30);
      Serial.println();
    }

  //+/- altera volume da musica
  } else if((key_command == '-') || (key_command == '+')) {
    union twobyte mp3_vol; 
    mp3_vol.word = MP3player.getVolume();

    if(key_command == '-') { // note dB is negative
      // assume equal balance and use byte[1] for math
      if(mp3_vol.byte[1] >= 254) { // range check
        mp3_vol.byte[1] = 254;
      } else {
        mp3_vol.byte[1] += 2; // keep it simpler with whole dB's
      }
    } else {
      if(mp3_vol.byte[1] <= 2) { // range check
        mp3_vol.byte[1] = 2;
      } else {
        mp3_vol.byte[1] -= 2;
      }
    }
    // push byte[1] into both left and right assuming equal balance.
    MP3player.setVolume(mp3_vol.byte[1], mp3_vol.byte[1]); // commit new volume
    Serial.print(F("Volume changed to -"));
    Serial.print(mp3_vol.byte[1]>>1, 1);
    Serial.println(F("[dB]"));

  //< ou > altera a velocidade de reproducao
  } else if((key_command == '>') || (key_command == '<')) {
    uint16_t playspeed = MP3player.getPlaySpeed(); 
    // note playspeed of Zero is equal to ONE, normal speed.
    if(key_command == '>') { // note dB is negative
      // assume equal balance and use byte[1] for math
      if(playspeed >= 254) { // range check
        playspeed = 5;
      } else {
        playspeed += 1; // keep it simpler with whole dB's
      }
    } else {
      if(playspeed == 0) { // range check
        playspeed = 0;
      } else {
        playspeed -= 1;
      }
    }
    MP3player.setPlaySpeed(playspeed); // commit new playspeed
    Serial.print(F("playspeed to "));
    Serial.println(playspeed, DEC);

  /* Alterativly, you could call a track by it's file name by using playMP3(filename);
  But you must stick to 8.1 filenames, only 8 characters long, and 3 for the extension */
  } else if(key_command == 'f' || key_command == 'F') {
    uint32_t offset = 0;
    if (key_command == 'F') {
      offset = 2000;
    }

    //create a string with the filename
    char trackName[] = "track001.mp3";

#if USE_MULTIPLE_CARDS
    sd.chvol(); // assign desired sdcard's volume.
#endif
    //tell the MP3 Shield to play that file
    result = MP3player.playMP3(trackName, offset);
    //check result, see readme for error codes.
    if(result != 0) {
      Serial.print(F("Error code: "));
      Serial.print(result);
      Serial.println(F(" when trying to play track"));
    }

  /* Display the file on the SdCard */
  } else if(key_command == 'd') {
    if(!MP3player.isPlaying()) {
      // prevent root.ls when playing, something locks the dump. but keeps playing.
      // yes, I have tried another unique instance with same results.
      // something about SdFat and its 500byte cache.
      Serial.println(F("Files found (name date time size):"));
      sd.ls(LS_R | LS_DATE | LS_SIZE);
    } else {
      Serial.println(F("Busy Playing Files, try again later."));
    }

  /* Get and Display the Audio Information */
  } else if(key_command == 'i') {
    MP3player.getAudioInfo();

  } else if(key_command == 'p') {
    if( MP3player.getState() == playback) {
      MP3player.pauseMusic();
      Serial.println(F("Pausing"));
    } else if( MP3player.getState() == paused_playback) {
      MP3player.resumeMusic();
      Serial.println(F("Resuming"));
    } else {
      Serial.println(F("Not Playing!"));
    }

  } else if(key_command == 't') {
    int8_t teststate = MP3player.enableTestSineWave(126);
    if(teststate == -1) {
      Serial.println(F("Un-Available while playing music or chip in reset."));
    } else if(teststate == 1) {
      Serial.println(F("Enabling Test Sine Wave"));
    } else if(teststate == 2) {
      MP3player.disableTestSineWave();
      Serial.println(F("Disabling Test Sine Wave"));
    }

  } else if(key_command == 'S') {
    Serial.println(F("Current State of VS10xx is."));
    Serial.print(F("isPlaying() = "));
    Serial.println(MP3player.isPlaying());

    Serial.print(F("getState() = "));
    switch (MP3player.getState()) {
    case uninitialized:
      Serial.print(F("uninitialized"));
      break;
    case initialized:
      Serial.print(F("initialized"));
      break;
    case deactivated:
      Serial.print(F("deactivated"));
      break;
    case loading:
      Serial.print(F("loading"));
      break;
    case ready:
      Serial.print(F("ready"));
      break;
    case playback:
      Serial.print(F("playback"));
      break;
    case paused_playback:
      Serial.print(F("paused_playback"));
      break;
    case testing_memory:
      Serial.print(F("testing_memory"));
      break;
    case testing_sinewave:
      Serial.print(F("testing_sinewave"));
      break;
    }
    Serial.println();

   } else if(key_command == 'b') {
    Serial.println(F("Playing Static MIDI file."));
    MP3player.SendSingleMIDInote();
    Serial.println(F("Ended Static MIDI file."));

#if !defined(__AVR_ATmega32U4__)
  } else if(key_command == 'm') {
      uint16_t teststate = MP3player.memoryTest();
    if(teststate == -1) {
      Serial.println(F("Un-Available while playing music or chip in reset."));
    } else if(teststate == 2) {
      teststate = MP3player.disableTestSineWave();
      Serial.println(F("Un-Available while Sine Wave Test"));
    } else {
      Serial.print(F("Memory Test Results = "));
      Serial.println(teststate, HEX);
      Serial.println(F("Result should be 0x83FF."));
      Serial.println(F("Reset is needed to recover to normal operation"));
    }

  } else if(key_command == 'e') {
    uint8_t earspeaker = MP3player.getEarSpeaker();
    if(earspeaker >= 3){
      earspeaker = 0;
    } else {
      earspeaker++;
    }
    MP3player.setEarSpeaker(earspeaker); // commit new earspeaker
    Serial.print(F("earspeaker to "));
    Serial.println(earspeaker, DEC);

  } else if(key_command == 'r') {
    MP3player.resumeMusic(2000);

  } else if(key_command == 'R') {
    MP3player.stopTrack();
    MP3player.vs_init();
    Serial.println(F("Reseting VS10xx chip"));

  } else if(key_command == 'g') {
    int32_t offset_ms = 20000; // Note this is just an example, try your own number.
    Serial.print(F("jumping to "));
    Serial.print(offset_ms, DEC);
    Serial.println(F("[milliseconds]"));
    result = MP3player.skipTo(offset_ms);
    if(result != 0) {
      Serial.print(F("Error code: "));
      Serial.print(result);
      Serial.println(F(" when trying to skip track"));
    }

  } else if(key_command == 'k') {
    int32_t offset_ms = -1000; // Note this is just an example, try your own number.
    Serial.print(F("moving = "));
    Serial.print(offset_ms, DEC);
    Serial.println(F("[milliseconds]"));
    result = MP3player.skip(offset_ms);
    if(result != 0) {
      Serial.print(F("Error code: "));
      Serial.print(result);
      Serial.println(F(" when trying to skip track"));
    }

  } else if(key_command == 'O') {
    MP3player.end();
    Serial.println(F("VS10xx placed into low power reset mode."));

  } else if(key_command == 'o') {
    MP3player.begin();
    Serial.println(F("VS10xx restored from low power reset mode."));

  } else if(key_command == 'D') {
    uint16_t diff_state = MP3player.getDifferentialOutput();
    Serial.print(F("Differential Mode "));
    if(diff_state == 0) {
      MP3player.setDifferentialOutput(1);
      Serial.println(F("Enabled."));
    } else {
      MP3player.setDifferentialOutput(0);
      Serial.println(F("Disabled."));
    }

  } else if(key_command == 'V') {
    MP3player.setVUmeter(1);
    Serial.println(F("Use \"No line ending\""));
    Serial.print(F("VU meter = "));
    Serial.println(MP3player.getVUmeter());
    Serial.println(F("Hit Any key to stop."));

    while(!Serial.available()) {
      union twobyte vu;
      vu.word = MP3player.getVUlevel();
      Serial.print(F("VU: L = "));
      Serial.print(vu.byte[1]);
      Serial.print(F(" / R = "));
      Serial.print(vu.byte[0]);
      Serial.println(" dB");
      delay(1000);
    }
    Serial.read();

    MP3player.setVUmeter(0);
    Serial.print(F("VU meter = "));
    Serial.println(MP3player.getVUmeter());

  } else if(key_command == 'T') {
    uint16_t TrebleFrequency = MP3player.getTrebleFrequency();
    Serial.print(F("Former TrebleFrequency = "));
    Serial.println(TrebleFrequency, DEC);
    if (TrebleFrequency >= 15000) { // Range is from 0 - 1500Hz
      TrebleFrequency = 0;
    } else {
      TrebleFrequency += 1000;
    }
    MP3player.setTrebleFrequency(TrebleFrequency);
    Serial.print(F("New TrebleFrequency = "));
    Serial.println(MP3player.getTrebleFrequency(), DEC);

  } else if(key_command == 'E') {
    int8_t TrebleAmplitude = MP3player.getTrebleAmplitude();
    Serial.print(F("Former TrebleAmplitude = "));
    Serial.println(TrebleAmplitude, DEC);
    if (TrebleAmplitude >= 7) { // Range is from -8 - 7dB
      TrebleAmplitude = -8;
    } else {
      TrebleAmplitude++;
    }
    MP3player.setTrebleAmplitude(TrebleAmplitude);
    Serial.print(F("New TrebleAmplitude = "));
    Serial.println(MP3player.getTrebleAmplitude(), DEC);

  } else if(key_command == 'B') {
    uint16_t BassFrequency = MP3player.getBassFrequency();
    Serial.print(F("Former BassFrequency = "));
    Serial.println(BassFrequency, DEC);
    if (BassFrequency >= 150) { // Range is from 20hz - 150hz
      BassFrequency = 0;
    } else {
      BassFrequency += 10;
    }
    MP3player.setBassFrequency(BassFrequency);
    Serial.print(F("New BassFrequency = "));
    Serial.println(MP3player.getBassFrequency(), DEC);

  } else if(key_command == 'C') {
    uint16_t BassAmplitude = MP3player.getBassAmplitude();
    Serial.print(F("Former BassAmplitude = "));
    Serial.println(BassAmplitude, DEC);
    if (BassAmplitude >= 15) { // Range is from 0 - 15dB
      BassAmplitude = 0;
    } else {
      BassAmplitude++;
    }
    MP3player.setBassAmplitude(BassAmplitude);
    Serial.print(F("New BassAmplitude = "));
    Serial.println(MP3player.getBassAmplitude(), DEC);

  } else if(key_command == 'M') {
    uint16_t monostate = MP3player.getMonoMode();
    Serial.print(F("Mono Mode "));
    if(monostate == 0) {
      MP3player.setMonoMode(1);
      Serial.println(F("Enabled."));
    } else {
      MP3player.setMonoMode(0);
      Serial.println(F("Disabled."));
    }
#endif

  } else if(key_command == 'h') {
    help();
  }

  // print prompt after key stroke has been processed.
  Serial.print(F("Time since last command: "));  
  Serial.println((float) (millis() -  millis_prv)/1000, 2);  
  millis_prv = millis();
  Serial.print(F("Enter s,1-9,+,-,>,<,f,F,d,i,p,t,S,b"));
#if !defined(__AVR_ATmega32U4__)
  Serial.print(F(",m,e,r,R,g,k,O,o,D,V,B,C,T,E,M:"));
#endif
  Serial.println(F(",h :"));
}

//Imprime o menu de opcoes
void help() {
  Serial.println(F("Arduino SFEMP3Shield Library Example:"));
  Serial.println(F(" courtesy of Bill Porter & Michael P. Flaga"));
  Serial.println(F("COMMANDS:"));
  Serial.println(F(" [1-9] to play a track"));
  Serial.println(F(" [f] play track001.mp3 by filename example"));
  Serial.println(F(" [F] same as [f] but with initial skip of 2 second"));
  Serial.println(F(" [s] to stop playing"));
  Serial.println(F(" [d] display directory of SdCard"));
  Serial.println(F(" [+ or -] to change volume"));
  Serial.println(F(" [> or <] to increment or decrement play speed by 1 factor"));
  Serial.println(F(" [i] retrieve current audio information (partial list)"));
  Serial.println(F(" [p] to pause."));
  Serial.println(F(" [t] to toggle sine wave test"));
  Serial.println(F(" [S] Show State of Device."));
  Serial.println(F(" [b] Play a MIDI File Beep"));
#if !defined(__AVR_ATmega32U4__)
  Serial.println(F(" [e] increment Spatial EarSpeaker, default is 0, wraps after 4"));
  Serial.println(F(" [m] perform memory test. reset is needed after to recover."));
  Serial.println(F(" [M] Toggle between Mono and Stereo Output."));
  Serial.println(F(" [g] Skip to a predetermined offset of ms in current track."));
  Serial.println(F(" [k] Skip a predetermined number of ms in current track."));
  Serial.println(F(" [r] resumes play from 2s from begin of file"));
  Serial.println(F(" [R] Resets and initializes VS10xx chip."));
  Serial.println(F(" [O] turns OFF the VS10xx into low power reset."));
  Serial.println(F(" [o] turns ON the VS10xx out of low power reset."));
  Serial.println(F(" [D] to toggle SM_DIFF between inphase and differential output"));
  Serial.println(F(" [V] Enable VU meter Test."));
  Serial.println(F(" [B] Increament bass frequency by 10Hz"));
  Serial.println(F(" [C] Increament bass amplitude by 1dB"));
  Serial.println(F(" [T] Increament treble frequency by 1000Hz"));
  Serial.println(F(" [E] Increament treble amplitude by 1dB"));
#endif
  Serial.println(F(" [h] this help"));
}

Carregue o programa no Arduino e abra o Serial Monitor. Antes de mais nada, selecione a velocidade de comunicação para 115200, conforme destacado. Um menu de opções será exibido, e você pode selecionar as músicas, alterar o volume e a velocidade de reprodução, tudo através do serial monitor, bastando enviar os caracteres correspondentes:

Shield MP3 Player - Comandos Serial Monitor
Assim, pressione 1 para reproduzir o arquivo track001.mp3, 2 para reproduzir o arquivo track002.mp3, e assim por diante.

Esse é apenas um exemplo de utilização. Informações completas e detalhadas sobre esse shield você pode obter acessando diretamente o site do produto na Sparkfun, nesse link.