- Descrição: O Módulo Bluetooth possibilita transmitir e receber dados através…
Arduino – Transmissão serial de áudio através de laser
Existem vários meios de comunicação para troca de informações entre dois ou mais Arduinos, sejam meios utilizando fios ou sem fio (wireless). Cada meio de comunicação tem sua particularidade, vantagens e desvantagens. Uma forma de comunicação sem fio que pode ser utilizada com o Arduino é o laser. Esta forma de comunicação pode alcançar longas distâncias e é simples de ser utilizada.
O laser (ampliação de luz por meio da emissão estimulada de radiações) é um tipo de radiação eletromagnética monocromática. O laser é basicamente um feixe de luz que se propaga quase que de forma paralela, ou seja, as ondas se propagam com a mesma intensidade no espaço e no tempo, logo, quase não existe dispersão de luz, diferente das lâmpadas em que os fótons se propagam aleatoriamente.
O laser é aplicado em diversas áreas, desde a medicina e indústrias até equipamentos eletrônicos. Além disso, o laser também é comumente utilizado em projetos com plataformas microcontroladas. Com o Arduino, por exemplo, o laser pode ser utilizado junto a um receptor de laser para construção de um simulador de segurança, onde o laser emissor tem sua luz direcionada para o receptor e quando esse feixe de luz é interrompido o Arduino aciona um buzzer.
Uma outra funcionalidade do laser junto ao Arduino é a transmissão de dados. É comum encontrar em diversos blogs, projetos utilizando o laser emissor e o receptor de laser para envio de mensagens entre dois Arduinos, onde no emissor é digitado uma mensagem e no receptor a mensagem é recebida e exibida.
Para demonstrar o uso do laser no envio de dados entre dois Arduinos, optei por fazer a transmissão de áudio.
Essa transmissão será unidirecional e feita através de comunicação serial, onde o laser emissor vai estar com o pino de sinal conectado ao pino TX do primeiro Arduino (1) e o receptor de laser vai estar com o pino de sinal conectado ao pino RX do segundo Arduino (2). No Arduino (1), além do laser emissor teremos também um Módulo Leitor de Micro SD Card responsável por armazenar o áudio que será transmitido. No Arduino (2), teremos além do receptor de laser, um Módulo Amplificador de Áudio LM386 responsável por amplificar o sinal de áudio que sai do Arduino e vai para o alto falante. A taxa de comunicação serial nos dois Arduinos será configurada em 115200 bits/segundo e a modulação do áudio no Arduino (2) será feita através de PWM.
O arquivo de áudio a ser transmitido possui algumas restrições. Este arquivo deve estar no formato WAV, monofônico (mono), ter 8 bit de resolução, PCM unsigned 8 bit e taxa de amostragem (sample rate) em 11.5KHz. Testei diversas taxas de amostragem até chegar no valor de 11.5KHz, que deixa o áudio o mais perto possível do real considerando a transmissão serial em 115200 bits/segundo. Com a taxa de amostragem em 8KHz o áudio fica extremamente acelerado, com a taxa em 14,4KHz ou 16KHz o áudio fica muito lento.
OBS: o intuito desta postagem é demonstrar uma das funcionalidades do laser e do Arduino (dentro de suas limitações). Portanto, leve em consideração que a qualidade do áudio transmitido não será tão boa.
Para execução desta prática você vai precisar dos seguintes itens:
02 – Arduino Uno R3 com Cabo USB
01 – Módulo Laser LED 6mm 650nm de Alta Potência
01 – Módulo Receptor de Laser
01 – Módulo Leitor de Micro SD Card
01 – Módulo Amplificador de Áudio LM386
01 – Alto falante Stereo 3W 4 Ohms 52mm
01 – Fonte DC 12V 1A Bivolt Chaveada (para o LM386)
01 – Fonte DC 9V 1A Bivolt Chaveada (para um dos Arduinos)
14 – Cabos Jumper macho-fêmea
01 – Cartão de memória (micro SD Card)
OBS: você também pode alimentar os dois Arduinos pelo PC através de dois cabos USB. Caso não tenha uma fonte de 12VDC para o LM386, utilize uma outra fonte externa de pelo menos 5VDC.
Monte o esquema de ligação conforme a imagem abaixo:
(Clique na imagem para ampliar)
OBS: no esquema de ligação o laser emissor está sendo alimentado com 5VDC, contudo, você também pode alimentá-lo com 3.3VDC. Lembrando que em 5VDC ele funciona em potência máxima.
Vale ressaltar que o Módulo Receptor de Laser deve ser utilizado em locais que não possua excesso de luz (lâmpadas ou luz solar), pois o módulo pode sofrer interferências e a saída de sinal será afetada. No vídeo ao final desta postagem, você vai ver que fiz uma espécie de proteção para o receptor de laser, pois ao iluminar o ambiente para fazer a gravação a recepção de áudio foi totalmente afetada devido a interferência causada pela luz.
Terminado o esquema de ligação, vamos prosseguir na preparação do áudio para ser adicionado no micro cartão SD. Para fazer a conversão do áudio vamos utilizar o Audacity. Faça o download do programa a partir do link abaixo:
Após o download do programa faça a instalação do mesmo em seu computador. Terminado a instalação, abra o programa e clique no menu “Ficheiro” e “Abrir…”:
Na janela que abrir, procure pelo áudio MP3 que vai ser convertido em WAV e clique em “Abrir”:
Com o áudio aberto no programa, aperte “Ctrl + A” para selecionar toda a faixa de áudio e em seguida clique no menu “Faixas” e “Faixa Estéreo para Mono”:
Em seguida digite 11500 na opção “Taxa de Projecto (Hz)”, aperte “Ctrl + A” novamente para selecionar toda a faixa de áudio, clique no menu “Faixas” e “Mudar Taxa de Amostragem…”:
Na janela que abrir, confira se está definido 11500 e clique em OK:
Novamente clique em “Ficheiro” e “Exportar Áudio…”:
Na janela que abrir, selecione a opção “Outros ficheiros sem compressão”, clique em “Opções” e uma nova janela será aberta. Em “Cabeçalho” selecione a opção “WAV (Microsoft)”, em “Codificação” selecione a opção “Unsigned 8 bit PCM” e clique em OK para salvar o arquivo de áudio:
Após salvar, uma janela será aberta, basta clicar em OK e fechar o Audacity. O arquivo de áudio pode ficar com um pouco de ruído, logo, se você quiser pode limpar o ruído no próprio Audacity ou em algum outro programa (lembre-se de manter as configurações exigidas para o arquivo de áudio).
O arquivo de áudio WAV já está preparado.
Utilize um leitor de micro cartão SD, insira o micro cartão nele e insira na USB do PC. Formate o cartão em FAT32 e em seguida copie para ele o arquivo de áudio WAV que foi exportado do Audacity. Coloque o nome do arquivo de “audio” (sem aspas).
OBS: utilizei um micro cartão de 8GB classe 4.
Remova o leitor de micro cartão SD do computador, remova o micro cartão do leitor e o insira no Módulo Leitor de Micro SD Card.
Conecte o cabo USB no Arduino (1) e no computador para fazer o envio do código responsável pela leitura do arquivo de áudio que está no cartão de memória e envio dos dados para a serial.
O código para fazer a leitura do cartão de memória está disponível nos exemplos da biblioteca SD que é nativa da IDE do Arduino, contudo, o código é pré configurado para ler um arquivo TXT. O exemplo em questão está com o nome de “DumpFile” dentre os exemplos da biblioteca.
Abaixo você pode copiar e colar na IDE do Arduino o código já modificado para execução do arquivo de áudio:
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 |
#include <SPI.h> #include <SD.h> const int chipSelect = 10; void setup() { // Open serial communications and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } Serial.print("Inicializando o SD card..."); // make sure that the default chip select pin is set to // output, even if you don't use it: pinMode(SS, OUTPUT); // see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { Serial.println("Cartao falhou ou nao esta presente"); // don't do anything more: return; } Serial.println("cartao inicializado."); // open the file. note that only one file can be open at a time, // so you have to close this one before opening another. SDFile dataFile = SD.open("audio.wav"); // if the file is available, write to it: if (dataFile) { while (dataFile.available()) { Serial.write(dataFile.read()); } dataFile.close(); } // if the file isn't open, pop up an error: else { Serial.println("Erro ao abrir o audio"); } } void loop() { } |
No menu “Ferramentas” selecione a opção “Placa” e selecione o “Arduino/Genuino Uno”:
Ainda no menu “Ferramentas”, selecione a opção “Porta” e marque a porta COM em que sua placa foi alocada:
Veja que no meu caso a placa foi alocada na COM5, porém, o seu Arduino pode ter sido alocado em uma COM de outro valor. Caso não saiba em qual porta COM sua placa foi alocada, basta retornar no menu Iniciar do Windows, acessar a opção Dispositivos e Impressoras e verificar a porta em que seu Arduino está conectado, retornar na IDE e selecionar a porta COM.
Feito as configurações, clique no botão para enviar o código ao Arduino e aguarde o carregamento.
Desconecte o cabo USB do Arduino (1) e conecte o cabo no Arduino (2) para fazer o envio do código responsável por interpretar os dados (áudio) recebidos na serial e reproduzir no alto falante.
Durante as pesquisas e estudos que fiz para execução desta prática, me deparei com diversos códigos e bibliotecas. Nos testes que fiz, a solução mais simples que encontrei para interpretar os dados recebidos na serial e reproduzir estes dados no alto falante, foi um pacote de códigos chamado audioStreamArduino.
Dentre os códigos fornecidos pelo pacote audioStreamArduino, vamos precisar apenas de um e que pode ser acessado no link abaixo:
Código audioStreamArduino audioSerial.ino
Abaixo você pode copiar o mesmo código que está disponível no link acima e em seguida colar na IDE do Arduino:
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 |
/* Streaming Audio Coded by Idan Regev Adapted from Matthew Vaterlaus http://forum.arduino.cc/index.php?topic=8817.0 Second Adapted largely from Michael Smith's speaker_pcm. <michael@hurts.ca> Plays 8-bit PCM audio on pin 11 using pulse-width modulation. For Arduino with Atmega at 16 MHz. The audio data needs to be unsigned, 8-bit, 8000 Hz. Although Smith's speaker_pcm was very well programmed, it had two major limitations: 1. The size of program memory only allows ~5 seconds of audio at best. 2. To change the adudio, the microcontroller would need to be re-programmed with a new sounddata.h file. StreamingAudio overcomes these limitations by dynamically sending audio samples to the Arduino via Serial. It uses a 1k circular buffer for the audio samples, since the ATMEGA328 only has 2k of RAM. For chips with less RAM, the BUFFER_SIZE variable can be reduced. The only limit on length is the number of samples must fit into an long integer. (ie: 4,294,967,295 samples). At 8000 samples / second, that allows 8,947 minutes of audio. Even this could be overcome if needed. (The only reason to have the number of samples is to know when to turn the speaker off.) Remote Host ----------- 1. Sends 10 bytes of data representing the number of samples. Each byte is 1 digit of an unsigned long. 2. Each time the host recieves a byte it sends the next 128 audio samples to fill the Arduino's receive buffer. */ #include <stdint.h> #include <avr/interrupt.h> #include <avr/io.h> #include <avr/pgmspace.h> #define SAMPLE_RATE 8000 #define BUFFER_SIZE 128 #define TRANSFER_SIZE 64 void startPlayback(); void stopPlayback(); long powlong(long x, long y); void reset(); unsigned long sounddata_length=0; unsigned char sounddata_data[BUFFER_SIZE]; int BufferHead=0; int HalfBufferSize=BUFFER_SIZE/2; int BufferTail=0; unsigned long sample=0; unsigned long BytesReceived=0; unsigned long Temp=0; unsigned long NewTemp=0; int ledPin = 13; int speakerPin = 11; int Playing = 0; //Interrupt Service Routine (ISR) // This is called at 8000 Hz to load the next sample. ISR(TIMER1_COMPA_vect) { //If not at the end of audio if (sample < sounddata_length) { //Set the PWM Freq. OCR2A = sounddata_data[BufferTail]; //If circular buffer is not empty if (BufferTail != BufferHead) { //Increment Buffer's tail index. if (++BufferTail >= BUFFER_SIZE) BufferTail = 0; //BufferTail = ((BufferTail+1) % BUFFER_SIZE); //Increment sample number. sample++; }//End if }//End if else //We are at the end of audio { //Stop playing. stopPlayback(); }//End Else }//End Interrupt void startPlayback() { //Set pin for OUTPUT mode. pinMode(speakerPin, OUTPUT); //---------------TIMER 2------------------------------------- // Set up Timer 2 to do pulse width modulation on the speaker // pin. //This plays the music at the frequency of the audio sample. // Use internal clock (datasheet p.160) //ASSR = Asynchronous Status Register ASSR &= ~(_BV(EXCLK) | _BV(AS2)); // Set fast PWM mode (p.157) //Timer/Counter Control Register A/B for Timer 2 TCCR2A |= _BV(WGM21) | _BV(WGM20); TCCR2B &= ~_BV(WGM22); // Do non-inverting PWM on pin OC2A (p.155) // On the Arduino this is pin 11. TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0); TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0)); // No prescaler (p.158) TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); //16000000 cycles 1 increment 2000000 increments //-------- * ---- = ------- // 1 second 8 cycles 1 second //Continued... //2000000 increments 1 overflow 7812 overflows //------- * --- = ----- // 1 second 256 increments 1 second // Set PWM Freq to the sample at the end of the buffer. OCR2A = sounddata_data[BufferTail]; //--------TIMER 1---------------------------------- // Set up Timer 1 to send a sample every interrupt. // This will interrupt at the sample rate (8000 hz) // cli(); // Set CTC mode (Clear Timer on Compare Match) (p.133) // Have to set OCR1A *after*, otherwise it gets reset to 0! TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12); TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10)); // No prescaler (p.134) TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // Set the compare register (OCR1A). // OCR1A is a 16-bit register, so we have to do this with // interrupts disabled to be safe. OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000 //Timer/Counter Interrupt Mask Register // Enable interrupt when TCNT1 == OCR1A (p.136) TIMSK1 |= _BV(OCIE1A); //Init Sample. Start from the beginning of audio. sample = 0; //Enable Interrupts sei(); }//End StartPlayback void stopPlayback() { // Disable playback per-sample interrupt. TIMSK1 &= ~_BV(OCIE1A); // Disable the per-sample timer completely. TCCR1B &= ~_BV(CS10); // Disable the PWM timer. TCCR2B &= ~_BV(CS10); digitalWrite(speakerPin, LOW); }//End StopPlayback //Use the custom powlong() function because the standard //pow() function uses floats and has rounding errors. //This powlong() function does only integer powers. //Be careful not to use powers that are too large, otherwise //this function could take a really long time. long powlong(long x, long y) { //Base case for recursion if (y==0) { return(1); }//End if else { //Do recursive call. return(powlong(x,y-1)*x); }//End Else } void setup() { //Set LED for OUTPUT mode pinMode(ledPin, OUTPUT); //Start Serial port. If your application can handle a //faster baud rate, that would increase your bandwidth //115200 only allows for 14,400 Bytes/sec. Audio will //require 8000 bytes / sec to play at the correct speed. //This only leaves 44% of the time free for processing //bytes. Serial.begin(115200); Serial.println("GO"); //PC sends audio length as 10-digit ASCII //While audio length hasn't arrived yet while (Serial.available()<10) { //Blink the LED on pin 13. digitalWrite(ledPin,!digitalRead(ledPin)); delay(100); } digitalWrite(ledPin,1); //Init number of audio samples. sounddata_length=0; //Convert 10 ASCII digits to an unsigned long. for (int i=0;i<10;i++) { //Convert from ASCII to int Temp=Serial.read()-48; //Shift the digit the correct location. NewTemp = Temp * powlong(10,9-i); //Add the current digit to the total. sounddata_length = sounddata_length + NewTemp; }//End for //Tell the remote PC/device that the Arduino is ready //to begin receiving samples. Serial.println(sounddata_length); Serial.println(uint8_t(TRANSFER_SIZE)); //There's data now, so start playing. //startPlayback(); Playing =0; }//End Setup void loop() { //If audio not started yet... if (Playing == 0) { //Check to see if the first 1000 bytes are buffered. if (BufferHead >= HalfBufferSize) { Playing=1; startPlayback(); }//End if }//End if //While the serial port buffer has data while (Serial.available()>0) { //If the sample buffer isn't full if (((BufferHead+1) % BUFFER_SIZE) != BufferTail) { //Store the sample freq. sounddata_data[BufferHead] = Serial.read(); //Increment the buffer's head index. BufferHead = (BufferHead+1) % BUFFER_SIZE; //Increment the bytes received BytesReceived++; }//End if //if the Serial port buffer has room if ((BytesReceived % TRANSFER_SIZE) == 0) { //Tell the remote PC how much bytes you want. if ((sounddata_length - BytesReceived) < TRANSFER_SIZE) { Serial.println(uint8_t(sounddata_length - BytesReceived)); } else { Serial.println(uint8_t(TRANSFER_SIZE)); } // Serial.print("!"); // Serial.println(sounddata_data[BufferHead]); //Serial.println("@"); }//End if }//End While }//End Loop |
No menu “Ferramentas” selecione a opção “Placa” e selecione o “Arduino/Genuino Uno” caso não esteja configurado. Ainda no menu “Ferramentas”, selecione a opção “Porta” e marque a porta COM em que seu segundo Arduino foi alocado.
OBS: antes de clicar no botão para enviar o código ao Arduino (2), desconecte o cabo jumper do pino RX, caso contrário o código vai apresentar erro no carregamento.
Clique no botão para enviar o código ao Arduino e aguarde o carregamento. Terminado, conecte ao pino RX o jumper que você havia desconectado.
Agora você pode manter o cabo USB conectado ao Arduino (2) e no Arduino (1) pode conectar outro cabo USB e conectar ao computador ou pode usar uma fonte externa de até 12VDC para alimentar a placa. Com ambas as placas alimentadas, conecte na tomada a fonte externa que está alimentando o LM386.
Se tudo estiver certo, imediatamente você vai escutar o áudio sendo reproduzido no alto falante. Inserindo um obstáculo entre o laser emissor e o receptor de laser você estará interrompendo a transmissão. Removendo o obstáculo, a transmissão é reestabelecida e o áudio volta a ser reproduzido no alto falante. No LM386 há um trimpot para ajuste do volume do som reproduzido no alto falante.
Veja no vídeo abaixo o resultado final desta prática:
No player abaixo você pode escutar o áudio original em formato MP3 que utilizei e fazer uma comparação com o áudio do vídeo:
Dentre as opções de comunicação sem fio entre dois ou mais Arduino, há algumas bem mais eficientes e seguras que o laser e que proporcionariam uma qualidade bem superior ao final desta prática. Para transmitir dados importantes entre dois Arduino utilizando laser, esta forma apresentada na postagem não seria a ideal, pois poderia haver perda / violação de dados. Na transmissão de áudio conforme foi feito nesta prática, mesmo que haja perdas de dados, ainda assim vamos conseguir escutar a música sem perceber estas perdas.
Mediante a proposta desta postagem e mesmo que uma série de fatores possam afetar este tipo de comunicação, o objetivo foi alcançado com satisfação.
Abaixo vou deixar os links do material que pesquisei e que foi a base para criação desta postagem:
http://highlowtech.org/?p=1963
https://www.youtube.com/watch?v=MCTqC2-AN7o
http://playground.arduino.cc/Code/PCMAudio
https://github.com/idanre1/audioStreamArduino
http://tmrh20.blogspot.com/2012/06/arduino-wav-playback-from-sd-card-new.html
https://www.instructables.com/id/Arduino-Encoded-and-Modulated-Laser-and-Infrared-S/
Gostou deste tutorial? Então deixa seu comentário, dúvida ou sugestão aí embaixo!
Loja online: https://www.masterwalkershop.com.br
Fan page no Facebook: https://www.facebook.com/masterwalkershop
Nos ajude a espalhar conhecimento clicando no botão de compartilhar (f Like) que está mais abaixo.
Obrigado e até a próxima!
Seu feedback é muito importante! Que tal dar uma nota para esta postagem?! Faça sua avaliação aqui embaixo.
Postagem anterior: Componentes Passivos – Resistor – Parte 2
Próxima postagem: Como usar com Arduino – Módulo Leitor de Micro SD Card
Fiquei bobo com esse projeto! Muito interessante!
Quero fazer um parecido, mas enviar sem fio pela comunicação serial, seria praticamente a mesma coisa, mas ligar um módulo sem fio na serial? É que no meu caso, quero fazer tipo uma conferência de voz, seriam vários dispositivos conectados e conversando ao mesmo tempo.