Sommario:

Riproduzione di file audio audio (Wav) con un Arduino e un DAC: 9 passaggi
Riproduzione di file audio audio (Wav) con un Arduino e un DAC: 9 passaggi

Video: Riproduzione di file audio audio (Wav) con un Arduino e un DAC: 9 passaggi

Video: Riproduzione di file audio audio (Wav) con un Arduino e un DAC: 9 passaggi
Video: Acquisizione audio con ADC, sintetizzatore audio con Arduino • Progetto 1000 2024, Luglio
Anonim
Riproduzione di file audio audio (Wav) con un Arduino e un DAC
Riproduzione di file audio audio (Wav) con un Arduino e un DAC
Riproduzione di file audio audio (Wav) con un Arduino e un DAC
Riproduzione di file audio audio (Wav) con un Arduino e un DAC
Riproduzione di file audio audio (Wav) con un Arduino e un DAC
Riproduzione di file audio audio (Wav) con un Arduino e un DAC

Riproduci file wav audio dalla tua scheda SD Audino. Questo Instructable ti mostrerà come un file wav sulla tua SdCard può essere riprodotto attraverso un semplice circuito a un altoparlante.

Il file wav deve essere mono a 8 bit. Non ho avuto problemi a riprodurre file a 44 KHz.

Sebbene non sia ad alta fedeltà, la qualità del suono è molto soddisfacente.

Il monitor seriale viene utilizzato per selezionare il file. I file devono trovarsi in una cartella chiamata adlog.

Questa istruzione segue da un progetto precedente in cui ho salvato le registrazioni wav sulla SdCard:

Il circuito utilizza un economico convertitore digitale-analogico (DAC) a 8 bit e un amplificatore audio a chip singolo.

Le sezioni chiave per l'impostazione degli interrupt sono state tratte dall'eccellente articolo di Amanda Ghassaei:

Passaggio 1: requisiti

Requisiti
Requisiti
Requisiti
Requisiti

Arduino- Uso il Mega, tuttavia non c'è motivo per cui Uno non dovrebbe funzionare.

SdCard reader- il programma è configurato per: MicroSD Breakout Board Regulated with Logic Conversion V2

Vedi questa istruzione per i dettagli di configurazione della SdCard:

DAC0832 LCN- un eccellente convertitore da digitale ad analogico a 8 bit- Poche sterline.

Amplificatore operazionale LM386 N-1 - economico come chip

Presa per chip a 20 vie

Presa per chip a 8 vie

Alimentazione a 9 volt: una batteria andrà bene.

LM336 2,5 V di riferimento di tensione

Condensatore 10uF * 3 (qualsiasi tensione superiore a 9V)

Resistenza da 10 ohm

Condensatore da 50nF- (o da qualche parte vicino a 47nF, 56nf, 68nf- lo farà)

Condensatore 220uF

Altoparlante da 64 ohm

Potenziometro lineare 10K

Cavo per collegare le 8 linee dati tra Arduino e il circuito-

Su Uno gli 8 collegamenti sono in linea, sul Mega sono in coppia.

Sul Mega ho usato un cavo a nastro a 10 vie con un connettore IDC a 10 vie. (2 fili sono di ricambio)

Connettori presa per 0V, 9V e DAC out

Striscia di rame, saldatura, filo, taglierine ecc

Passaggio 2: le specifiche

Le specifiche
Le specifiche

Seriale impostato a 115200 baud.

È disponibile il supporto per la scheda breakout MicroSD di Hobbytronics che utilizza un Mega. La selezione del chip e le altre porte cambieranno tra Mega e Uno.

I file Wav devono esistere in una directory chiamata adlog- Sentiti libero di nominarlo qualcos'altro e riorganizzare la codifica necessaria.

Il file wav deve essere mono a 8 bit. Ho testato fino a 44KHz.

Il monitor seriale visualizza i file wav nella cartella adlog. I nomi dei file vengono inviati dalla riga di output del monitor.

La dimensione del file è limitata solo dalla dimensione della scheda SD.

Passaggio 3: iniziare

Iniziare
Iniziare

Collega il lettore di schede SD. Queste sono le connessioni per il Mega.

0, 5V

CLK al pin 52

D0 al pin 50

D1 al pin 51

CS al pin 53

(Vedere il sito Web dei fornitori per la connessione alla porta Uno)

Dovrai testare che la tua scheda funzioni in questa fase: usa gli script forniti dal venditore.

Dobbiamo fare un piccolo circuito

Invieremo un flusso di byte audio da Arduino.

Questi numeri sono compresi tra 0 e 255. Rappresentano la tensione.

Il silenzio è 127-128.

255 è il cono dell'altoparlante duro in un modo.

0 è il cono dell'altoparlante duro al contrario.

Quindi l'audio viene registrato come numeri salvati, che creano tensioni variabili, che creano coni di altoparlanti in movimento.

Possiamo inviare i numeri su 8 linee su Arduino, contemporaneamente, utilizzando una "porta".

Se inseriamo le 8 linee in un convertitore digitale-analogico, fa quello che dice sulla scatola e produce una tensione analogica proporzionale al numero digitale.

Tutto ciò che dobbiamo fare è trasferire la tensione su un piccolo amplificatore operazionale e poi su un altoparlante.

Passaggio 4: il piccolo circuito

Il Piccolo Circuito
Il Piccolo Circuito
Il Piccolo Circuito
Il Piccolo Circuito
Il Piccolo Circuito
Il Piccolo Circuito
Il Piccolo Circuito
Il Piccolo Circuito

Il DAC0832 LCN

Questo è un convertitore digitale-analogico a 8 bit superbo ed economico. (DAC)

Può essere completamente controllato con una serie di dati trattenuti, linee di campionamento dati.

Oppure può essere configurato per eseguire tutto automaticamente in "Flusso attraverso il funzionamento".

Per citare il manuale:

La semplice messa a terra di CS, WR1, WR2 e XFER e il collegamento di ILE alto consentono a entrambi i registri interni di seguire gli ingressi digitali applicati (flow-through) e di influenzare direttamente l'uscita analogica DAC.

OK, quattro connessioni al chipset sono basse e una a 9V - facile.

Non vogliamo che vengano fuori tensioni negative, quindi il manuale dice che dovremmo usare la "modalità di commutazione della tensione" e forniscono il diagramma.

Tutto quello che dobbiamo fare è sostituire un piccolo amplificatore audio invece di quello che suggeriscono.

L'amplificatore audio LM386-N

Il manuale dell'amplificatore fornisce un diagramma delle parti minime, fornendo un guadagno di 20 (troppo per noi, ma ha un controllo del volume).

Tutto ciò che dobbiamo fare è aggiungere un condensatore tra il DAC e l'amplificatore in modo da amplificare solo i segnali CA.

Dobbiamo anche aggiungere un paio di condensatori vicino al pin di alimentazione di ciascuno dei nostri chip, altrimenti avremo un ronzio dalla nostra alimentazione a 9V.

Passaggio 5: tira fuori il saldatore

Tira fuori il saldatore
Tira fuori il saldatore
Tira fuori il saldatore
Tira fuori il saldatore
Tira fuori il saldatore
Tira fuori il saldatore

Poiché il circuito è semplice, non intendo dare un account colpo su colpo.

Ecco alcune indicazioni:

  • Preparare un pezzo di striscia di rame di almeno 28 per 28 fori. (Sì, lo so che i chirurghi del cervello possono rimpicciolirlo)
  • Se intendi montarlo con le viti, permettile all'inizio!
  • Montare i chip sulle prese. Inserire i chip solo quando tutto è stato controllato.
  • Tenere i cavi di ingresso lontani dall'uscita.
  • Rispettare la corretta polarità per i condensatori.
  • Fare riferimento allo schema per la vista di base del riferimento di tensione LM336. La gamba di regolazione non viene utilizzata e può essere tagliata.
  • Da notare la connessione diretta al pin 8 del DAC- È molto utile per i test.
  • Mi sono collegato all'Audino con un cavo a nastro e un connettore IDC a 10 vie.
  • Su Uno le connessioni sono in linea retta: potresti scoprire che disporre le 8 connessioni di ingresso in un'unica linea retta ti consente di collegarti ad Arduino con un connettore a 8 vie acquistato e già pronto,

Al termine, controlla la saldatura e controlla gli spazi tra le piste di rame.

Trovo molto utile una lama per seghetto da taglio junior da 36 tpi per eliminare i detriti. Rimuovo i perni di posizionamento della lama e faccio scorrere la punta della lama nel binario- Ovviamente la lama non è in un telaio.

Passaggio 6: test del DAC

Testare il DAC
Testare il DAC

Lascia la connessione tra il circuito e l'Arduino disattivata.

Imposta il controllo del volume sul tuo circuito a metà.

Accendi l'alimentazione a 9 V CC al tuo nuovo circuito.

Controlla che il circuito sia ok- Non posso assumermi alcuna responsabilità per il tuo circuito!

Spegni

Collega il tuo circuito ad Arduino.

Sul Mega utilizzare i pin 22-29. (PORTA) Non confondere i due pin 5V sopra!

Su Uno utilizzare i pin 0-7. Questo è PORTD

Collega lo 0V del tuo alimentatore allo 0V di Arduino.

Accendere.

Apri questo programma di test DAC_TEST

Per l'ONU, sostituire tutti i riferimenti a PORTA con PORTD

Sostituisci DDRA con DDRD: questa istruzione imposta tutte e 8 le linee per l'output in una volta sola. Questo è il registro della direzione dei dati.

Imposta il tuo monitor seriale a 115200.

Collegare un voltmetro tra l'uscita DAC e OV

Il programma imposterà l'uscita a 255 - tutte le linee attive - tensione massima.

Uscita 128- metà tensione massima.

Uscita 0- tensione zero (o probabilmente quasi zero).

Quindi passerà bit per bit: 1, 2, 4, 8, 16, 32, 64, 128

La tensione dovrebbe aumentare costantemente.

Se la tensione diminuisce mentre il numero aumenta, probabilmente hai due dei fili di interconnessione invertiti.

Dovresti anche sentire l'altoparlante fare clic silenziosamente mentre la tensione cambia

Passaggio 7: lettura dell'intestazione Wav

Leggere l'intestazione Wav
Leggere l'intestazione Wav

I file Wav vengono salvati con una frequenza e una dimensione dei dati specificate.

Queste informazioni sono contenute in un'intestazione di 44 byte all'inizio di un file wav.

Sebbene alcuni software estendano l'intestazione (dopo il byte 35), rendendo più difficile l'individuazione della posizione della dimensione dei dati.

Per leggere l'intestazione creiamo un buffer e copiamo l'inizio del file.

La frequenza è memorizzata in 4 byte a partire da 24 byte nel file.

// legge la frequenza specificata nell'intestazione del file wav

byte headbuff[60]

filetemp.seek(0);

tempfile.read(headbuf, 60);

retval=headbuf[27];

retval=(retval<<8) | headbuf[26];

retval=(retval<<8) | headbuf[25];

retval=(retval<<8) | headbuf[24];

Serial.print(F("Frequenza file"));

Serial.print(retval);

Il modo migliore per trovare le informazioni sulla dimensione dei dati è cercare la parola "dati" nell'intestazione.

Quindi estrai i 4 byte che lo seguono, che compongono il valore lungo

retval lungo non firmato;

int mypos=40;

for (int i=36; i<60;i++) {

if (headbuf == 'd') {

if(headbuf[i+1]=='a') {

if(headbuf[i+2]=='t') {

if(headbuf[i+3]=='a') {

// finalmente ce l'abbiamo

mypos=i+4;

io=60;

}

}

}

}

}

tempfile.seek(mypos);

retval=headbuf[mypos+3];

retval=(retval<<8) | headbuf[mypos+2];

retval=(retval<<8) | headbuf[mypos+1];

retval=(retval<<8) | headbuf[mypos];

OK, abbiamo la lunghezza e la frequenza dei dati!

I dati audio seguono i 4 byte che costituiscono il valore della lunghezza dei dati.

Passaggio 8: Interrompi, Interrompi…

Interrompi, Interrompi…
Interrompi, Interrompi…

Utilizziamo le informazioni sulla frequenza per creare un'interruzione software a o vicino alla frequenza richiesta.

L'interrupt non può essere sempre impostato con precisione, ma è sufficiente. La frequenza letta dal file viene passata alla subroutine setintrupt.

void setintrupt(float freq){float bitval=8; // 8 per timer a 8 bit 0 e 2, 1024 per timer 1 byte

setocroa=(16000000/(freq*bitval)) - 0,5;

// Il valore setocroa richiede una sottrazione di -1. Tuttavia, aggiungendo 0,5 round allo 0,5. più vicino

// La risoluzione del timer è limitata

// In definitiva determinato dalla grandezza di bitval

cli(); // disabilita gli interrupt// imposta l'interrupt del timer2

TCCR2A = 0; // imposta l'intero registro TCCR2A a 0

TCCR2B = 0; // lo stesso per TCCR2B

TCNT2 = 0; // inizializza il valore del contatore a 0

// imposta il registro delle corrispondenze di confronto per gli incrementi di frequenza (hz)

OCR2A = setocroa; // = (16*10^6) / (frequenza*8) - 1 (deve essere <256)

// attiva la modalità CTC

TCCR2A |= (1 << WGM21); // Imposta il bit CS21 per 8 prescaler

TCCR2B |= (1 << CS21); // abilita l'interruzione del confronto del timer

// TIMSK2 |= (1 << OCIE2A); // funziona, così come la riga seguente

sbi(TIMSK2, OCIE2A); // abilita l'interrupt sul timer 2

sei(); // abilita gli interrupt

I lettori più esigenti avranno notato sbi(TIMSK2, OCIE2A)

Ho impostato un paio di funzioni (acquisite da Internet) per l'impostazione e la cancellazione dei bit di registro:

// Definisce per cancellare i bit di registro#ifndef cbi

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

#finisci se

// Definisce per l'impostazione dei bit di registro

#ifndef sbi

#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

#finisci se

Queste funzioni forniscono una semplice chiamata per impostare o cancellare l'interrupt.

Quindi l'interruzione è in esecuzione, cosa possiamo fargli fare?

Passaggio 9: interruzioni e doppio buffering

Interrupt e doppio buffering
Interrupt e doppio buffering
Interrupt e doppio buffer
Interrupt e doppio buffer

A 22 Khz viene emesso un byte di dati audio ogni 0,045 ms

512 byte (la dimensione del buffer) vengono letti in 2,08 ms.

Quindi il buffer non può essere letto dalla SDCard in un ciclo di scrittura.

Tuttavia, 512 byte vengono scritti sulla porta in 23,22 ms.

Quindi tutto ciò che dobbiamo fare è impostare un nuovo file letto ogni volta che il buffer si svuota e abbiamo abbastanza tempo per ottenere i dati prima che sia richiesto un nuovo blocco di dati… Supponendo di utilizzare due buffer, svuotandone uno mentre ne riempiamo un altro.

Questo è il doppio buffering.

La lettura del file verrà rallentata dall'interruzione ripetuta, ma verrà eseguita.

Ho impostato due buffer da 512 byte chiamati bufa e bufb.

Se il flag è già vero leggiamo da porta altrimenti leggiamo da portb

Quando la posizione del buffer (bufcount) raggiunge la dimensione del buffer (BUF_SIZE 512) impostiamo un flag chiamato readit a true.

La routine void loop cerca questo flag e avvia un blocco di lettura:

if(readit){if (! aready){

// avvia la lettura del blocco SDCard su bufa

tempfile.read(bufa, BUF_SIZE);

} altro {

// avvia il blocco SDCard letto su bufb

tempfile.read(bufb, BUF_SIZE);

}

readit=falso;

}

Al termine, la routine contrassegna readit=false.

All'interno della routine di interrupt dobbiamo controllare che il ciclo void sia terminato controllando se readit== false.

Stando così le cose, segnaliamo che è necessaria un'altra lettura e attiviamo il flag aready per cambiare buffer.

Se la SDcard sta ancora leggendo, dobbiamo tornare indietro di una lettura (counter--; bufcount--;) e uscire dall'interrupt per riprovare più tardi. (I clic nel segnale di uscita audio implicano che ciò si è verificato.)

Quando tutti i dati vengono letti, l'interruzione viene annullata, la porta viene reimpostata al valore di media tensione di 128 e il file audio viene chiuso.

Prima di eseguire lo script dac2.ino per la prima volta, imposta il volume al 50%. Questo sarà troppo rumoroso, ma è meglio del 100%!

Se il controllo del volume funziona al contrario, scambia i cavi alle estremità opposte del potenziometro da 10K.

Fammi sapere come suona.

Consigliato: