Inhaltsverzeichnis:

Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC - Gunook
Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC - Gunook

Video: Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC - Gunook

Video: Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC - Gunook
Video: 3 Options for Playing Audio on Arduino 2024, November
Anonim
Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC
Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC
Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC
Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC
Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC
Abspielen von Audio-Sounddateien (Wav) mit einem Arduino und einem DAC

Spielen Sie die WAV-Datei Audio von Ihrer Audino-SD-Karte ab. Dieses Instructable zeigt Ihnen, wie eine WAV-Datei auf Ihrer SdCard über eine einfache Schaltung zu einem Lautsprecher abgespielt werden kann.

Die wav-Datei muss 8-Bit-Mono sein. Ich hatte kein Problem damit, 44-kHz-Dateien abzuspielen.

Die Klangqualität ist zwar nicht Hi-Fidelity, aber sehr zufriedenstellend.

Der serielle Monitor wird verwendet, um die Datei auszuwählen. Die Dateien müssen sich in einem Ordner namens adlog befinden.

Dieses instructable folgt aus einem früheren Projekt, in dem ich WAV-Aufnahmen auf der SdCard gespeichert habe:

Die Schaltung verwendet einen billigen 8-Bit-Digital-Analog-Wandler (DAC) und einen Single-Chip-Audioverstärker.

Wichtige Abschnitte zum Einrichten von Interrupts wurden dem ausgezeichneten Artikel von Amanda Ghassaei entnommen:

Schritt 1: Anforderungen

Anforderungen
Anforderungen
Anforderungen
Anforderungen

Arduino- Ich benutze den Mega, es gibt jedoch keinen Grund, warum der Uno nicht funktionieren sollte.

SdCard-Leser – das Programm ist konfiguriert für: MicroSD Breakout Board Reguliert mit Logic Conversion V2

Siehe diese Anleitung für SdCard-Setup-Details:

DAC0832 LCN - ein ausgezeichneter 8-Bit-Digital-Analog-Wandler - Ein paar Pfund.

LM386 N-1 Operationsverstärker - billig wie Chips

20-poliger Chipsockel

8-fach Chip-Sockel

9-Volt-Netzteil - eine Batterie reicht.

LM336 2,5 V Spannungsreferenz

10uF Kondensator * 3 (jede Spannung über 9V)

10 Ohm Widerstand

50nF Kondensator – (Oder irgendwo in der Nähe von 47nF, 56nf, 68nf – reicht aus)

220uF Kondensator

64-Ohm-Lautsprecher

10K Linearpotentiometer

Kabel zum Verbinden der 8 Datenleitungen zwischen dem Arduino und der Schaltung-

Beim Uno liegen die 8 Anschlüsse in einer Linie, beim Mega sind sie paarweise.

Auf dem Mega habe ich 10-Wege-Flachbandkabel mit einem 10-Wege-IDC-Header verwendet. (2 Drähte sind Ersatz)

Buchsenanschlüsse für 0V, 9V und DAC-Ausgang

Kupferstreifenplatine, Lötzinn, Draht, Cutter usw.

Schritt 2: Die Spezifikationen

Die Spezifikationen
Die Spezifikationen

Seriell auf 115200 Baud eingestellt.

Das Hobbytronics MicroSD Breakout Board mit Mega wird unterstützt. Die Chipauswahl und andere Ports ändern sich zwischen Mega und Uno.

Die Wav-Dateien müssen in einem Verzeichnis namens adlog existieren. Sie können es gerne anders benennen und die erforderliche Codierung neu anordnen.

Die wav-Datei muss 8-Bit-Mono sein. Ich habe bis 44KHz getestet.

Der Serial Monitor zeigt die wav-Dateien im Ordner adlog an. Dateinamen werden von der Monitorausgabezeile gesendet.

Die Dateigröße ist nur durch die SdCard-Größe begrenzt.

Schritt 3: Erste Schritte

Einstieg
Einstieg

Schließen Sie den SD-Kartenleser an. Das sind die Anschlüsse für den Mega.

0, 5V

CLK an Pin 52

D0 an Pin 50

D1 an Pin 51

CS an Pin 53

(Siehe Lieferanten-Website für Uno-Port-Verbindung)

Sie sollten zu diesem Zeitpunkt testen, ob Ihre Karte funktioniert. Verwenden Sie die vom Anbieter bereitgestellten Skripte.

Wir müssen eine kleine Runde machen

Wir werden einen Stream von Audiobytes vom Arduino senden.

Diese Zahlen liegen zwischen 0 und 255. Sie repräsentieren die Spannung.

Stille ist 127-128.

255 ist ein harter Lautsprecherkegel.

0 ist der Lautsprecherkonus hart in die andere Richtung.

Audio wird also als gespeicherte Zahlen aufgezeichnet, die unterschiedliche Spannungen erzeugen, die sich bewegende Lautsprecherkegel erzeugen.

Wir können die Zahlen aus 8 Zeilen gleichzeitig auf dem Arduino senden, indem wir einen "Port" verwenden.

Wenn wir die 8 Leitungen in einen Digital-Analog-Wandler einspeisen, tut er, was er verspricht und erzeugt eine analoge Spannung, die proportional zur digitalen Zahl ist.

Alles, was wir dann tun müssen, ist die Spannung an einen kleinen Operationsverstärker und dann an einen Lautsprecher zu packen.

Schritt 4: Die kleine Schaltung

Der kleine Kreislauf
Der kleine Kreislauf
Der kleine Kreislauf
Der kleine Kreislauf
Der kleine Kreislauf
Der kleine Kreislauf
Der kleine Kreislauf
Der kleine Kreislauf

Der DAC0832 LCN

Dies ist ein hervorragender, billiger 8-Bit-Digital-Analog-Wandler. (DAC)

Es kann mit einem Array von Data-Hold- und Data-Sample-Leitungen vollständig gesteuert werden.

Oder es kann so eingestellt werden, dass alles automatisch im "Durchlaufbetrieb" erledigt wird.

Um das Handbuch zu zitieren:

Durch einfaches Erden von CS, WR1, WR2 und XFER und Verbinden von ILE hoch können beide internen Register den angelegten digitalen Eingängen folgen (Durchfluss) und direkt auf den DAC-Analogausgang wirken.

OK das sind vier Anschlüsse zum Chipsatz Low und einer auf 9V - easy.

Wir wollen keine negativen Spannungen, daher sagt das Handbuch, dass wir den "Spannungsschaltmodus" verwenden sollten, und sie liefern das Diagramm.

Alles, was wir tun müssen, ist einen kleinen Audioverstärker anstelle des vorgeschlagenen zu ersetzen.

Der LM386-N Audioverstärker

Das Handbuch des Amps enthält ein Diagramm der minimalen Teile - mit einer Verstärkung von 20 (viel zu viel für uns - aber es hat einen Lautstärkeregler).

Alles, was wir tun müssen, ist einen Kondensator zwischen dem DAC und dem Verstärker hinzuzufügen, damit wir nur AC-Signale verstärken.

Wir müssen auch ein paar Kondensatoren in der Nähe des Versorgungspins jedes unserer Chips hinzufügen, sonst bekommen wir ein Brummen von unserer 9V-Versorgung.

Schritt 5: Holen Sie den Lötkolben heraus

Hol den Lötkolben raus
Hol den Lötkolben raus
Holen Sie den Lötkolben raus
Holen Sie den Lötkolben raus
Holen Sie den Lötkolben raus
Holen Sie den Lötkolben raus

Da die Schaltung einfach ist, beabsichtige ich nicht, eine Schlag-für-Schlag-Rechnung zu geben.

Hier einige Hinweise:

  • Bereiten Sie ein Stück Kupferstreifenplatte mit mindestens 28 mal 28 Löchern vor. (Ja, ich weiß, dass Gehirnchirurgen es kleiner machen können)
  • Wenn Sie die Montage mit Schrauben beabsichtigen, berücksichtigen Sie diese am Anfang!
  • Montieren Sie die Chips auf Sockeln. Setzen Sie die Chips erst ein, wenn alles überprüft wurde.
  • Halten Sie die Eingangsdrähte vom Ausgang fern.
  • Beachten Sie die richtige Polarität der Kondensatoren.
  • Die Grundansicht der Spannungsreferenz LM336 finden Sie im Diagramm. Das verstellbare Bein wird nicht verwendet und kann geschnitten werden.
  • Beachten Sie die direkte Verbindung zu Pin 8 des DAC- Es ist sehr nützlich zum Testen.
  • Ich habe den Audino mit Flachbandkabel und einem 10-poligen IDC-Stecker angeschlossen.
  • Auf dem Uno sind die Anschlüsse in einer geraden Linie - Sie werden möglicherweise feststellen, dass Sie durch die Anordnung der 8 Eingangsanschlüsse in einer einzigen geraden Linie eine Verbindung zum Arduino mit einem gekauften, vorgefertigten 8-Wege-Anschluss herstellen können.

Wenn es fertig ist, überprüfen Sie die Lötung und überprüfen Sie die Lücken zwischen den Kupferbahnen.

Ich finde ein Junior-Hacksägeblatt mit 36 tpi sehr nützlich, um Schmutz zu beseitigen. Ich entferne die Fixierstifte der Klinge und schiebe die Spitze der Klinge in die Schiene. Offensichtlich befindet sich die Klinge nicht in einem Rahmen.

Schritt 6: Testen des DAC

Testen des DAC
Testen des DAC

Lassen Sie die Verbindung zwischen dem Schaltkreis und dem Arduino ausgeschaltet.

Stellen Sie den Lautstärkeregler Ihres Schaltkreises auf Mitte.

Schalten Sie die 9-V-Gleichstromversorgung Ihres neuen Stromkreises ein.

Überprüfen Sie, ob die Schaltung in Ordnung ist - ich kann keine Haftung für Ihre Schaltung übernehmen!

Ausschalten

Verbinden Sie Ihre Schaltung mit dem Arduino.

Verwenden Sie beim Mega die Pins 22-29. (PORTA) Verwechseln Sie nicht die beiden 5V-Pins oben!

Verwenden Sie beim Uno die Pins 0-7. Das ist PORTD

Verbinden Sie die 0V Ihres Netzteils mit den 0V des Arduino.

Einschalten.

Öffnen Sie dieses Testprogramm DAC_TEST

Ersetzen Sie für die UNO alle Verweise auf PORTA durch PORTD

DDRA durch DDRD ersetzen – dieser Befehl setzt alle 8 Leitungen auf einmal auf die Ausgabe. Dies ist das Datenrichtungsregister.

Stellen Sie Ihren seriellen Monitor auf 115200 ein.

Schließen Sie ein Voltmeter zwischen dem DAC-Ausgang und OV. an

Das Programm setzt den Ausgang auf 255 - alle Leitungen an - maximale Spannung.

Ausgang 128 – halbe maximale Spannung.

Ausgang 0 - Nullspannung (oder wahrscheinlich fast Null).

Es geht dann bitweise: 1, 2, 4, 8, 16, 32, 64, 128

Die Spannung sollte stetig ansteigen.

Wenn die Spannung zurückfällt, während die Zahl ansteigt, sind wahrscheinlich zwei der Verbindungsdrähte vertauscht.

Sie sollten auch ein leises Klicken des Lautsprechers hören, wenn sich die Spannung ändert

Schritt 7: Lesen des Wav-Headers

Lesen des Wav-Headers
Lesen des Wav-Headers

Wav-Dateien werden mit einer bestimmten Häufigkeit und Datengröße gespeichert.

Diese Informationen sind in einem 44-Byte-Header am Anfang einer wav-Datei enthalten.

Obwohl einige Software den Header (nach Byte 35) erweitert, ist es schwieriger, die Position der Datengröße zu finden.

Zum Lesen des Headers erstellen wir einen Puffer und kopieren den Anfang der Datei.

Die Frequenz wird in 4 Bytes ab 24 Bytes in der Datei gespeichert.

// Lesehäufigkeit im WAV-Dateiheader angegeben

Byte-Headbuf[60]

tempfile.seek(0);

tempfile.read(headbuf, 60);

retval=headbuf[27];

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

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

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

Serial.print (F ("Dateifrequenz"));

Serial.print (reval);

Die Informationen zur Datengröße finden Sie am besten, indem Sie in der Kopfzeile nach dem Wort "Daten" suchen.

Dann extrahiere die 4 Bytes danach, die den langen Wert bilden

langes Reval ohne Vorzeichen;

int mypos=40;

für (int i=36; i<60;i++) {

if (headbuf == 'd') {

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

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

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

// endlich haben wir es

mypos=i+4;

i=60;

}

}

}

}

}

tempfile.seek(mypos);

retval=headbuf[mypos+3];

retval=(retval<<8) | Kopfball[Mypos+2];

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

retval=(retval<<8) | Kopfball [Mypos];

OK, wir haben die Datenlänge und -frequenz!

Die Audiodaten folgen den 4 Bytes, aus denen der Datenlängenwert besteht.

Schritt 8: Unterbrechen, unterbrechen…

Unterbrechen, unterbrechen…
Unterbrechen, unterbrechen…

Wir verwenden die Frequenzinformationen, um einen Software-Interrupt mit oder in der Nähe der erforderlichen Frequenz zu erstellen.

Der Interrupt lässt sich nicht immer genau einstellen, reicht aber aus. Die aus der Datei gelesene Frequenz wird an die Unterroutine setintrupt übergeben.

Void setintrupt (float freq) {float bitval = 8; // 8 für 8-Bit-Timer 0 und 2, 1024 für Timer 1 Byte

setocroa=(1600000/(Häufigkeit*Bitwert)) – 0,5;

// Der Setocroa-Wert erfordert eine Subtraktion von -1. Hinzufügen von 0,5 Runden zu den nächsten 0,5

// Die Auflösung des Timers ist begrenzt

// Letztendlich bestimmt durch die Größe von Bitval

cli(); // Interrupts deaktivieren // Timer2-Interrupt einstellen

TCCR2A = 0; // setze das gesamte TCCR2A-Register auf 0

TCCR2B = 0; // dasselbe für TCCR2B

TCNT2 = 0; // Zählerwert auf 0 initialisieren

// Vergleichs-Match-Register für Frequenz-(Hz-)Inkremente setzen

OCR2A = Setocroa; // = (16*10^6) / (Häufigkeit*8) - 1 (muss <256 sein)

// CTC-Modus einschalten

TCCR2A |= (1 << WGM21); // Setze CS21 Bit für 8 Prescaler

TCCR2B |= (1 << CS21); // Timer-Vergleichs-Interrupt aktivieren

// TIMSK2 |= (1 << OCIE2A); // das funktioniert, genauso wie die folgende Zeile

sbi(TIMSK2, OCIE2A); // Interrupt auf Timer 2 aktivieren

sei(); // Interrupts aktivieren

Anspruchsvolle Leser werden sbi (TIMSK2, OCIE2A) entdeckt haben

Ich habe ein paar (über das Internet erworbene) Funktionen zum Setzen und Löschen von Registerbits eingerichtet:

// Definiert zum Löschen von Registerbits#ifndef cbi

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

#endif

// Definiert zum Setzen von Registerbits

#ifndef sbi

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

#endif

Diese Funktionen bieten einen einfachen Aufruf zum Setzen oder Löschen des Interrupts.

Der Interrupt läuft, was können wir tun?

Schritt 9: Interrupts und Doppelpufferung

Interrupts und Doppelpufferung
Interrupts und Doppelpufferung
Interrupts und Doppelpufferung
Interrupts und Doppelpufferung

Bei 22 kHz wird alle 0,045 ms ein Byte Audiodaten ausgegeben

512 Byte (die Puffergröße) werden in 2,08 ms gelesen.

Der Puffer kann also nicht in einem Schreibzyklus von der SDCard gelesen werden.

Allerdings werden in 23,22 ms 512 Byte an den Port geschrieben.

Wir müssen also nur jedes Mal, wenn sich der Puffer leert, eine neue Datei einrichten und haben genug Zeit, um die Daten abzurufen, bevor ein neuer Datenblock benötigt wird… Angenommen, wir verwenden zwei Puffer und leeren einen, während wir den anderen füllen.

Dies ist eine doppelte Pufferung.

Das Lesen der Datei wird durch den wiederholten Interrupt verlangsamt, aber es wird erledigt.

Ich habe zwei 512-Byte-Puffer namens bufa und bufb eingerichtet.

Wenn das Flag richtig ist, lesen wir von porta, andernfalls lesen wir von portb

Wenn die Pufferposition (bufcount) die Puffergröße (BUF_SIZE 512) erreicht, setzen wir ein Flag namens readit auf true.

Die Schleifenroutine void sucht nach diesem Flag und startet einen Blocklesevorgang:

if(readit){if (! aredy){

// SDCard-Block in bufa einlesen

tempfile.read(bufa, BUF_SIZE);

} anders {

// SDCard-Block lesen in bufb einleiten

tempfile.read(bufb, BUF_SIZE);

}

readit=falsch;

}

Wenn sie beendet ist, kennzeichnet die Routine readit=false.

Innerhalb der Interrupt-Routine müssen wir überprüfen, ob die void-Schleife beendet ist, indem wir prüfen, ob readit== false ist.

Wenn dies der Fall ist, signalisieren wir, dass ein weiterer Lesevorgang erforderlich ist, und schalten das Bereichsflag um, um die Puffer zu wechseln.

Wenn die SD-Karte noch liest, müssen wir einen Messwert zurückverfolgen (counter--; bufcount--;) und den Interrupt beenden, um es später erneut zu versuchen. (Klicks im Audioausgangssignal weisen darauf hin, dass dies aufgetreten ist.)

Wenn alle Daten gelesen sind, wird der Interrupt abgebrochen, der Port auf den mittleren Spannungswert von 128 zurückgesetzt und die Audiodatei geschlossen.

Stellen Sie Ihre Lautstärke auf 50 % ein, bevor Sie das Skript dac2.ino zum ersten Mal ausführen. Das wird zu laut, aber besser als 100%!

Wenn Ihr Lautstärkeregler umgekehrt funktioniert, tauschen Sie die Kabel an den gegenüberliegenden Enden des 10K-Potentiometers aus.

Lass mich wissen, wie es klingt.

Empfohlen: