Stereoljud med Arduino (3 / 7 steg)
Steg 3: Mono ljudutgången med 8 bitars DAC och 44,1 kHz samplingsfrekvens
Schematiskt för DAC inställningar visas i figur 2. AGND och DGND (stift 1 och 5) ansluter till Arduino marken. VDD (pin 17), OUTA (pin 2), OUTB (stift 20). RFBA (pin 3) och RFBB (pin 19) ansluta till Arduino 5V. WR (pin 16) ansluter till digital stift 10, CS (pin 15) ansluter till digital pin 9 och DACA/DACB (pin 6) ansluter till digital stift 8. DB0-DB7 (stift 14-7) Anslut till digital stift 0-7. Utgångarna från DAC är stift 4 (för DACA) och 18 (för DACB).
I följande stycke använder jag en timer avbryta för att skicka data till DAC med en hastighet av ca 44,1 kHz (standard ljud samplingsfrekvens). Avbryter är rutiner som utförs vid specifikt olika tidsintervaller. Medan Arduino körs kommandona i den huvudsakliga loop() fungera den pausar kort för att köra innehållet i ISR(TIMER1_COMPA_vect) {} i en takt på 44,1 kHz. När kommandon inuti funktionen körs, återställs Arduino vad det gjorde i funktionen loop(). Detta sätt vi kan enkelt lägga till kod till funktionen loop (kontrollera sensorer, slå på lysdioder, etc) och inte behöva oroa sig för tidpunkten för ljudutgång. Följande rader ställer avbrottet:
(CLI); //stop avbrott
Ställ in timer1 avbrott på ~44.1kHz
TCCR1A = 0; / / Ställ in hela TCCR1A register till 0
TCCR1B = 0; / / samma för TCCR1B
TCNT1 = 0; //initialize värde till 0
Set jämför match registrera för 1hz steg
OCR1A = 361; / / = (16 * 10 ^ 6) / (44100 * 1) - 1 (måste vara < 65536)
Aktivera CTC läge
TCCR1B | = (1 << WGM12);
Ange CS10 bit för 1 prescaler
TCCR1B | = (1 << CS10);
Aktivera timern jämför avbrott
TIMSK1 | = (1 << OCIE1A);
SEI (); //enable avbrott
En fullständig förklaring av dessa rader ges i min Arduino Timer avbrott tutorial. Inne i rutinen avbrott hittar vi följande rader:
PORTD = såg; //send såg att DAC genom digital stift 0-7
såg ++, //increment såg värde av en
om (såg == 256) {//reset såg om den når 256 (håller produktionen inom 0-255 alltid)
såg = 0;
}
Så varje gång avbryta rutin kör den skickar såg värdet av variabeln"" till DAC. Sedan ökas variabel sågen av en för nästa gång avbryta rutinen körs. Om sågen är > 255 det återställs till noll. I huvudsak Arduino siffrorna 0-255 till DAC och sedan återställa till 0 när den når 255. Detta kommer ut en såg våg från DAC (Fig. 7).
Jag noterade i kommentarerna i den kod som avbrott rutinen inte körs på exakt 44,1 kHz, men så nära som jag kunde få. Faktiska samplingsfrekvens är 44.199kHz (vilket är faktiskt något bättre än 44,1). Detta berodde på vissa begränsningar i inställningarna för timer avbrott. Vi kommer att använda detta nummer för att beräkna lite info om DAC produktionen:
varaktigheten av varje prov = 1/samplingsfrekvens
varaktigheten av varje prov = 1/44199 Hz = 22.6us
Fig. 8 visar en zoomad med tanke på DAC såg produktionen på ett oscilloskop. Du kan se de enskilda 22.6us steg av wave, precis som beräknat. Vinka (längden av en komplett såg cykeln) är:
period = varaktigheten av varje prov * prover per cykel
period = 22.6us * 256 = 5.8ms
och frekvens:
frekvens = 1/period
frekvens = 1/0.0058s = 172 Hz
dessa kan ses i Fig. 6.
< pre > //mono såg med 44,1 kHz samplingsfrekvens
av Amanda Ghassaei
Nov 2012
/*
* Detta program är fri programvara; Du kan vidaredistribuera det och/eller ändra
* det enligt villkoren i GNU General Public License som offentliggjorts av
* den Free Software Foundation; antingen version 3 av licensen, eller
* (på ditt alternativ) någon senare version.
*/
kontroll stift på TLC7528
#define outputSelector 8
#define CS 9
#define WR 10
byte såg = 0; //value såg våg
void setup() {
för (byte jag = 0; jag < 8; i ++) {
pinMode (i, matas); //set digital stift 0-7 som resultat
}
pinMode(outputSelector,OUTPUT);
pinMode(CS,OUTPUT);
pinMode(WR,OUTPUT);
(CLI); //stop avbrott
Ställ in timer1 avbrott på ~44.1kHz
TCCR1A = 0; / / Ställ in hela TCCR1A register till 0
TCCR1B = 0; / / samma för TCCR1B
TCNT1 = 0; //initialize värde till 0
Set jämför match registrera för 1hz steg
OCR1A = 361; / / = (16 * 10 ^ 6) / (44100 * 1) - 1 (måste vara < 65536)
Aktivera CTC läge
TCCR1B | = (1 << WGM12);
Ange CS10 bit för 1 prescaler
TCCR1B | = (1 << CS10);
Aktivera timern jämför avbrott
TIMSK1 | = (1 << OCIE1A);
SEI (); //enable avbrott
Välj utgång (låg för DACA och högt för DACB)
digitalWrite(outputSelector,LOW);
CS och WR låg att låta inkommande data från digitala stift 0-7 gå till DAC utgång
digitalWrite(CS,LOW);
digitalWrite(WR,LOW);
}
ISR(TIMER1_COMPA_vect) {//timer1 avbrott ~44.1kHz att skicka ljuddata (det är verkligen 44.199 kHz)
PORTD = såg; //send såg att DAC genom digital stift 0-7
såg ++, //increment såg värde av en
om (såg == 256) {//reset såg om den når 256 (håller produktionen inom 0-255 alltid)
såg = 0;
}
}
void loop() {
göra andra saker här
}
Koden nedan utgångar en sinusvåg med samma avbrott jag satt upp ovan. Arduino har en inbyggd sinusfunktion, men det är för långsamt att köra på 44,1 kHz, så jag lagras en värdematris sine att dra från under varje avbrott. Jag sprang en enkel Python skript (nedan) för att generera 100 värden av 127+127*sin(2*3.14*t/100):
importera matematik
x i rad (0, 100):
skriva ut str(int(127+127*math.sin(2*math.pi*x*0.01)),)+str(","),
I lagras dessa nummer i en matris kallas "sine" och sedan sätta följande rad i rutinen avbrott:
PORTD = sine [index]; //send ett värde som lagras i matrisen sinus ut till DAC genom digital stift 0-7
index ++; //increment index av en
om (index == 100) {//reset index om det når 100
index = 0;
}
dessa rader skicka ett värde från array "sinus", anges av värdet för variabeln "index", till PORTD. Sedan ökas "index" med ett för nästa cykel. Om index > 99 det får återställas till noll. Utdata från den här koden visas i fig 9.
Eftersom jag använde samma avbrott setup som såg koden, varaktigheten av varje prov är samma: 22.6us (Fig. 10). Eftersom det finns bara 100 prover per cykel för denna sinus (vs 255 prover per cykel för saw) är perioden:
period = varaktigheten av varje prov * prover per cykel
period = 22.6us * 100 = 2.3ms
frekvens = 1/period
frekvens = 1/0.0023s = 442 Hz
dessa kan ses i Fig. 9
< pre > //mono sine ut med 44,1 kHz samplingsfrekvens
av Amanda Ghassaei
Nov 2012
/*
* Detta program är fri programvara; Du kan vidaredistribuera det och/eller ändra
* det enligt villkoren i GNU General Public License som offentliggjorts av
* den Free Software Foundation; antingen version 3 av licensen, eller
* (på ditt alternativ) någon senare version.
*/
kontroll stift på TLC7528
#define outputSelector 8
#define CS 9
#define WR 10
100 värden av en cykel av sine centrerad kring 127 med en amplitud på 127
byte sine [] = {127, 134, 142, 150, 158, 166, 173, 181, 188, 195, 201, 207, 213, 219, 224, 229, 234, 238, 241, 245, 247, 250, 251, 252, 253, 254, 253, 252, 251, 250, 247, 245, 241, 238, 234, 229, 224, 219, 213, 207, 201, 195, 188, 181, 173, 166, 158, 150, 142, 134, 127, 119, 111, 103, 95, 87, 80, 72, 65 58, 52, 46, 40, 34, 29, 24, 19, 15, 12, 8, 6, 3, 2, 1, 0, 0, 0, 1, 2, 3, 6, 8, 12, 15, 19, 24, 29, 34, 40, 46, 52, 58, 65, 72, 80, 87, 95, 103, 111, 119,};
byte index = 0; //index variabel för att extrahera data från array "sine"
void setup() {
för (byte jag = 0; jag < 8; i ++) {
pinMode (i, matas); //set digital stift 0-7 som resultat
}
pinMode(outputSelector,OUTPUT);
pinMode(CS,OUTPUT);
pinMode(WR,OUTPUT);
(CLI); //stop avbrott
Ställ in timer1 avbrott på ~44.1kHz
TCCR1A = 0; / / Ställ in hela TCCR1A register till 0
TCCR1B = 0; / / samma för TCCR1B
TCNT1 = 0; //initialize värde till 0
Set jämför match registrera för 1hz steg
OCR1A = 361; / / = (16 * 10 ^ 6) / (44100 * 1) - 1 (måste vara < 65536)
Aktivera CTC läge
TCCR1B | = (1 << WGM12);
Ange CS10 bit för 1 prescaler
TCCR1B | = (1 << CS10);
Aktivera timern jämför avbrott
TIMSK1 | = (1 << OCIE1A);
SEI (); //enable avbrott
Välj utgång (låg för DACA och högt för DACB)
digitalWrite(outputSelector,LOW);
CS och WR låg att låta inkommande data från digitala stift 0-7 gå till DAC utgång
digitalWrite(CS,LOW);
digitalWrite(WR,LOW);
}
ISR(TIMER1_COMPA_vect) {//timer1 avbrott ~44.1kHz att skicka ljuddata (det är verkligen 44.199 kHz)
PORTD = sine [index]; //send ett värde som lagras i matrisen sinus ut till DAC genom digital stift 0-7
index ++; //increment index av en
om (index == 100) {//reset index om det når 100
index = 0;
}
}
void loop() {
göra andra saker här
}