Stereoljud med Arduino (7 / 7 steg)
Steg 7: Enkel panorering krets med Arduino
stereo stekpanna 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 sinus, centrerad på 127, 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 index1 = 0; //index att retreive värden fom array "sine"
byte index2 = 0; //index att retreive värden fom array "sine"
booleska kanal = 0. //state 0 skickar till en kanal, 1 skickar till andra kanalen
int pan; //value från pan pott
int panA, //pan värde att skicka till DACA
int panB, //pan värde att skicka till DACB
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älla in timer1 avbrott på ~88.2kHz (2 * 44,1 kHz)
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 = 180, / / = (16 * 10 ^ 6) / (88200 * 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
lågt inställd CS pin
digitalWrite(CS,LOW);
}
ISR(TIMER1_COMPA_vect) {//timer1 avbrott ~88.2kHz att skicka ljuddata (faktiskt på 88.398 kHz)
PORTB | = B00000100; //digitalWrite (WR, hög); //hold utgångar - så nya DAC data få inte skickas förrän vi är redo
om (kanal) {
PORTD = (sine[index1]*panA) >> 7, //send sine till digital stift 0-7 med panA amp
PORTB & = B11111110; //digitalWrite (outputSelector, låg); //select DACA
index1 ++, //increment indexvärde av en
om (index1 == 100) {//reset index om det når 100
index1 = 0;
}
}
annat {
PORTD = (sine[index2]*panB) >> 7, //send sine till digital stift 0-7 med panB förstärkare
PORTB | = B00000001; //digitalWrite (outputSelector, hög); //select DACB
index2 ++, //increment indexvärde av en
om (index2 == 100) {//reset index om det når 100
index2 = 0;
}
}
PORTB & = B11111011; //digitalWrite (WR, låg); //enable utgång igen
kanalen ^ = 1; //toggle kanal
}
void checkPan() {
panorera = analogRead(A0);
panorera = pan >> 3; //convert från 10 bit till 7-bitars (0-127)
panA = pan;
panB = 127-pan;
}
void loop() {
checkPan();
göra andra saker här
}
Denna kod utgångar 440hz sinustoner ut båda stereoutgångarna. När potentiometern slås ända åt sidan, en av utgångarna på maximal amplitud och den andra kommer att platt-line på 0 (fig 2). Som potentiometern vänds åt andra hållet, amplituden för en kanal kommer att gå och den andra kommer att gå fram till den kanal som var tidigare platt-foder är på full amplitud och den andra kanalen är vid 0 (Fig. 3-6).
Denna kod är ganska enkelt, men den använder några knep för att maximera effektiviteten som jag ska förklara lite längre här. Som i steg 4, har jag ersatt alla kommandon som digitalWrite() med PORTB & = och PORTB | = kommandon. Jag gjorde detta enbart för hastighet skäl (när du arbetar med 88kHz avbryter, du behöver arbeta snabbt), och kommentarerna av varje av dessa fodrar ger deras motsvarande Arduino bibliotek kommando. till exempel linjen:
PORTB & = B11111011;
är lika med:
digitalWrite(WR,LOW);
där WR = digital stift 10
Mer information om hur dessa kommandon fungerar kan hittas på Arduino webbplats. Funktionen checkPan() kontrollerar status för pan potentiometern. Eftersom det inte är avgörande för att mäta denna pott på en hög frekvens, ringde jag bara funktionen i de viktigaste loop() i stället för avbrottet. Innehållet i checkPan() upprepas nedan:
panorera = analogRead(A0);
panorera = pan >> 3; //convert från 10 bit till 7-bitars (0-127)
panA = pan;
panB = 127-pan;
Först ställs variabel pannan utdata från analogRead(A0). Funktionen analogRead() returnerar alltid ett nummer mellan 0 och 1023 - en 10 bitars nummer. Jag trodde inte så hög upplösning var nödvändiga för vad jag gjorde, så jag sänkte upplösningen av detta nummer ner till 7 bitar i den andra raden att göra det lite mer hanterbart. Nu istället för att vara ett tal mellan 0 och 1023, har pan skalats ner för att passa mellan 0 och 127. Jag gjorde detta med en enkel bit SKIFT, du kan även göra detta med några division, eller Mappa funktion, de har alla samma slutresultatet (men lite SKIFT är det snabbaste sättet att göra detta). Nu när jag har pan, ett värde mellan 0 och 127, jag gjorde några enkel subtraktion för att beräkna amplituderna att skicka till DACA och DACB och dessa värden tilldelas panA och panB.
I rutinen avbrott ersättas I enkelt sine utdata från steg 4:
PORTD = sine [index2];
med en produktion som har skalats:
PORTD = (sine[index2]*panB) >> 7.
denna linje är funktionellt ekvivalent med följande:
PORTD = (sinus [index2] * panB) / 127;
men eftersom den använder en bit SKIFT istället för division, är det mycket effektivare. Detta är mycket viktigt i hög frekvens avbrott, i själva verket, raden ovan kommer att sakta ner avbrottet så mycket att det inte kommer att kunna köra fullt ut innan det är dags för en ny avbryta att starta. Använda denna bit SKIFT trick är det enda sättet att få koden att fungera korrekt.