Stap 3: Mono Audio-uitgang met 8 Bit DAC en 44,1 kHz Sampling Rate
Het schema voor de DAC-configuratie wordt weergegeven in Fig. 2. AGND en DGND (pin 1 en 5) sluit aan op grond van de Arduino. VDD (pin-nummer 17), OUTA (pin 2), OUTB (pin 20). RFBA (pin 3) en RFBB (pin 19) verbinden met 5V van de Arduino. WR (pin 16) verbindt met digitale pin 10, CS (pin 15) verbonden met digitale pin 9 en DACA/DACB (pin 6) verbindt met digitale pin 8. DB0-DB7 (pinnen 14-7) sluit aan op digitale pinnen 0-7. De uitgangen van de DAC zijn pin 4 (voor DACA) en 18 (voor DACB).
In het volgende stuk code gebruik ik een timer onderbreken om gegevens te verzenden naar de DAC in een tempo van ongeveer 44,1 kHz (standaard audio sampling-snelheid). Interrupts zijn routines die speciaal getimede intervallen worden uitgevoerd. Terwijl de Arduino draait commando's in de loop van de belangrijkste functie het pauzes kort voor het uitvoeren van de inhoud van ISR(TIMER1_COMPA_vect) {} met een snelheid van 44,1 kHz. Zodra de opdrachten binnen de functie worden uitgevoerd, wordt de Arduino hervat wat het deed in de loop-functie. Deze manier wij kunt eenvoudig code toevoegen aan de lus functie (check sensoren, inschakelen van LED's, etc) en niet hoeft te maken over de timing van de audio-uitgang. De volgende regels instellen de interrupt:
cli (); //stop interrupts
set timer1-interrupt op ~44.1kHz
TCCR1A = 0; / / hele TCCR1A register ingesteld op 0
TCCR1B = 0; / / zelfde voor TCCR1B
TCNT1 = 0; //initialize waarde van de teller op 0
set vergelijk wedstrijd registreren voor stappen van 1hz
OCR1A = 361; / / = (16 * 10 ^ 6) / (44100 * 1) - 1 (moet < 65536)
CTC-modus inschakelen
TCCR1B | = (1 << WGM12);
CS10 bit ingesteld voor 1 prescaler
TCCR1B | = (1 << CS10);
inschakelen van de timer vergelijk interrupt
TIMSK1 | = (1 << OCIE1A);
Sei (); //enable interrupts
Een volledige uitleg van deze lijnen wordt gegeven in mijn Arduino Timer onderbreken tutorial. Binnen de interrupt routine vinden we de volgende regels:
PORTD = zagen; //send zag uit naar de DAC via digitale pinnen 0-7
zaag ++; //increment zag waarde door een
Als (zag == 256) {//reset zag als het bereikt 256 (houdt output binnen altijd 0-255)
zagen = 0;
}
Dus telkens de interrupt routine het verzendt voert zag de waarde van de variabele"" aan de DAC. Vervolgens is de variabele saw verhoogd voor de volgende keer die de interrupt routine wordt uitgevoerd. Als zag > 255 het op nul wordt teruggesteld. In wezen de Arduino is de getallen 0 tot en met 255 te sturen naar de DAC en dan resetten terug naar 0 zodra zij 255 tot. Dit zal de uitgang van een golf van de zaag van de DAC (Fig. 7).
Ik merkte in de commentaren van de code die de interrupt routine wordt niet uitgevoerd op precies 44,1 kHz, maar zo dicht als ik kan krijgen. De werkelijke samplefrequentie is 44.199kHz (die is eigenlijk iets beter dan 44,1). Dit was te wijten aan enkele beperkingen in de setup van timer interrupts. We zullen dit nummer gebruiken om te berekenen wat info over de DAC-output:
duur van elk monster = 1/bemonsteringsfrequentie
duur van elk monster = 1/44199 Hz = 22.6us
Fig 8 toont dat een ingezoomd met het oog op de DAC zag uitvoer op een oscilloscoop. Kunt u de afzonderlijke 22.6us stappen van de Golf, net als berekend. De periode van de Golf (de lengte van één volledige zag cyclus) is:
periode = duur van elk monster * monsters per cyclus
periode = 22.6us * 256 = 5.8ms
en de frequentie:
frequentie = 1/periode
frequentie = 1/0.0058s = 172 Hz
Dit kunnen worden gezien in fig 6.
<pre>//mono saw out with 44.1kHz sampling rate //by Amanda Ghassaei //Nov 2012
De onderstaande code uitgangen een sinusgolf met behulp van de dezelfde interrupt die mij troep opwaarts boven. Arduino heeft een ingebouwde functie, maar het is te traag om uit te voeren op 44,1 kHz, zodat ik een matrix met waarden van de sinus te trekken uit tijdens elke interrupt opgeslagen. Ik liep een eenvoudige Python script (zie hieronder) voor het genereren van 100 waarden van 127+127*sin(2*3.14*t/100):
importeren van math
voor x in bereik (0, 100):
afdrukken van str(int(127+127*math.sin(2*math.pi*x*0.01)),)+str(","),
Ik deze nummers opgeslagen in een matrix "sinus" genoemd, en zet dan de volgende regel in de interrupt routine:
PORTD = sinus [index]; //send een waarde die is opgeslagen in de sinus van de matrix uit aan de DAC via digitale pennen 0-7
index ++; //increment index door een
Als (index 100 ==) {//reset index als het bereikt 100
index = 0;
}
deze regels verzenden een waarde uit de matrix "sinus", gespecificeerd door de waarde van de variabele "index", PORTD. "Index" wordt dan verhoogd met een voor de volgende cyclus. Als index > 99 het krijgt weer op nul gezet. De uitvoer van deze code is getoond in fig 9.
Aangezien ik dezelfde interrupt instellingen als de zaag-code hebt gebruikt, de duur van elk monster is hetzelfde: 22.6us (Fig. 10). Aangezien er slechts 100 monsters per cyclus voor deze sinus (vs 255 monsters per cyclus voor de saw) is de periode:
periode = duur van elk monster * monsters per cyclus
periode = 22.6us * 100 = 2.3ms
frequentie = 1/periode
frequentie = 1/0.0023s = 442 Hz
Dit kunnen worden gezien in fig 9
<pre>//mono sine out with 44.1kHz sampling rate //by Amanda Ghassaei //Nov 2012