6 de novembro de 2023 - Blog Ryndack Componentes
Rua Jovelina Claudino Buhrer, 440 - São José dos Pinhais - PR (41) 3383-3034
Projetos

É provável que você já tenha desejado reproduzir um áudio com o Arduino, mas como se faz isso? Vem com a gente, que nesse post você vai aprender!

A ideia por traz do projeto desse post é usar uma rede R2R, que é um conversor digital analógico formado por alguns resistores (se você ainda não conhece, confira o nosso post sobre ela), para reproduzir um áudio salvo na memória de um Arduino, de maneira simples e barata, usando poucos componentes.

Para esse projeto você não irá precisar de muita coisa, os materiais são:

  1. 25 resistores de 1kΩ

  2. 1 capacitor de 100nF

  3. Uma caixa de som

  4. Um Arduino

Esse projeto pode ser dividido em 3 etapas, sendo elas:

  1. Escolha e extração de um arquivo de áudio

  2. Escrita do código a ser executado

  3. Montagem do circuito


Escolha e Extração do Áudio 

A primeira etapa é a escolha de um arquivo de áudio. Para isso, precisamos levar em conta uma limitação comum em microcontroladores, a memória. No caso do Arduino, ela é de 32Kb, então precisamos garantir que o arquivo de áudio utilizado e o programa escrito não excedam este valor.

Assim, escolhemos um arquivo que seja curto, e com uma baixa frequência de amostragem. Para este artigo foi escolhido um áudio de cerca de 16 segundos com uma frequência de amostragem de 2000 amostras por segundo.
Com um arquivo de áudio selecionado, é preciso transformar ele em um vetor, que será gravado no Arduino. Para isso, usamos a função audioread do octave. O resultado dessa função é uma matriz [y fs], na qual y são os dados de áudio e fs a taxa de amostragem.

Os dados y são dispostos na forma de uma matriz que tem os frames de áudio colocados nas linhas e os canais nas colunas. A fim de simplificar o processo e de gerar um arquivo menor usamos um áudio mono, que fará com que y possua apenas uma coluna.

O próximo passo é transformar y em um vetor de uma unica linha com valores inteiros de 0 a 255, o que é possível com algumas contas simples e com a função reshape. Por fim, esse arquivo é salvo como um arquivo “.h”, que sera usado no código do Arduino. Isso esta demonstrado no script abaixo.

# Le o arquivo de audio, aqui usamos inicio e fim de modo que fim-inicio = numero_de_amostras. 
[y fs] = audioread("nome_do_arquivo_de_audio", [inicio fim]) 

# Determina o numero de linhas e o numero de colunas (1 para áudios mono) de y. 
[linha coluna] = size(y) 

# Transpõe y, em um vetor de 1 linha. 
y = reshape(y, 1, linha) 

# Transforma y em um vetor de 0 a 255 com números inteiros e salva em audio. 
audio = round(255*y+128) 

# Cria um arquivo .h com "const unsigned char pontos[ ] PROGMEM = {" salvo na primeira linha. 
dlmwrite("Audio.h", "const unsigned char pontos[ ] PROGMEM = {", "") 

# Adiciona o vetor com o audio ao arquivo .h criado. 
dlmwrite("Audio.h", audio, ",", "-append") 

# Fecha a chave. 
dlmwrite("Audio.h", "}", "", "-append")



Importante lembrar que para este script funcionar adequadamente, o arquivo de áudio deve estar salvo na mesma pasta que o octave. A fim de melhor aproveitar a memória do microcontrolador, foi usado o comando PROGMEM, que faz com que a variável, quando gravada, seja salva na memória flash, e não na RAM do Arduino.


Código do Arduino

O código implementado no Arduino ficou como está a seguir

#define F_CPU 16000000

#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include "Pontos.h"

int i=0, Min=130;

//Interrupção quando há um estouro do timer0.
ISR(TIMER0_OVF_vect){ 

     //Reinicia o timer0.
     TCNT0 = Min; 

     //Manda o valor da posição i do vetor com o audio para o PORTD.
     PORTD = pgm_read_byte_near(pontos + i); 

     //incrementa a posição do vetor com o audio.
     if(i>30998){ 
          i = 0;
     }
     else{
          i += 1;
     }
}

//Configura o timer0 e as saídas.
void main (void){
     //Habilita interruoções globais.
     SREG |= (1<<7); 

     //Configura o timer0 para operação normal, não conectada.
     TCCR0A = 0; 
     TCCR0B = 0;

     //Define o prescale como sendo 64.
     TCCR0B |= ((1 << CS01)+(1 << CS00)); 

     //Inicia o timer0.
     TCNT0 = Min; 

     //Habilita interrupção por estouro do timer 0.
     TIMSK0 |= (1<<TOIE0); 

     //Configura o PORTD (pinos 0 ao 7), como saídas.
     DDRD = 0xFF; 

     //Loop vazio
     while (1){

     }
}

No código acima, vimos que o registrador TCNT0 incrementa seu valor em uma unidade uma vez a cada \frac{N}{f_{CPU}} segundo com N sendo o valor do prescale (64). Além disso, haverá um estouro no timer sempre que o valor de TCNT0 atingir 255. Dessa forma, temos que a frequência do timer (f) será:

(1)   \begin{equation*} f=\frac{f_{CPU}}{N*(255-Min)} \end{equation*}

Com Min sendo o menor valor de TCNT0. A fim de que o audio seja reproduzido adequadamente, precisamos que f seja igual a fs. Usando fs=2000, f_{CPU} = 16MHz e N igual a 64, temos:

(2)   \begin{equation*} 2000=\frac{16000000}{64*(255-Min)} \end{equation*}

Resolvendo para Min encontramos Min = 130. Desse modo, temos um estouro do timer a cada 0,5ms, fazendo com que a rotina de interrupção ISR seja acionada. Nessa interrupção, primeiramente atualizamos o valor presente na saída (PORTD) e reiniciamos o valor de TCNT0.

Em seguida, atualizamos a posição do vetor que será mandado ao PORTD na próxima iteração.
Já na função main temos a configuração do PORTD como saída, configuração do timer0 no modo desconectado com o prescale definido e configuração da interrupção por estouro do timer.
Por fim temos o loop vazio, que mantem o microcontrolador ativo aguardando a próxima interrupção. O código usado e um arquivo .h com um áudio exemplo estão disponíveis em nosso GitHub.

Montagem

A montagem é bem simples, como mostra a imagem abaixo:


Ela basicamente consiste em uma rede R2R, com a saída ligada em um capacitor e uma caixa de som para computador. Já os pinos de 0 a 7 são ligados aos pinos de mesmos valores do Arduino.
O funcionamento desse circuito é simples, já que ele consiste basicamente em um conversor digital analógico. Esse conversor transforma a saída do Arduino em um sinal de tensão analógico que é usado na caixa de som. O capacitor presente é um capacitor de desacoplamento, já que a saída do R2R apresenta um nível de tensão CC e a componente de CA.
É importante observar que esse circuito não apresenta um amplificador, já que a caixa de som usada já possui um amplificador interno. Viu só como foi fácil? Agora me conta nos comentários, que som que você vai usar para esse projeto? 

0