AVR-baserad stämapparat
AVR-baserad stämapparat
Jag har länge tänkt att bygga mig en egen stämapparat för att få en pryl som fungerar på det sätt jag själv vill. Jag hittade det här AVR-programmet för ett tag sedan och tänkte att jag skulle utgå ifrån det och anpassa det efter mina önskemål. http://www.myplace.nu/avr/gtuner/gtuner.c
Jag är ganska grön när det gäller mikroprocessorprogrammering och kan, trots många funderingsförsök, inte fatta hur programmet räknar ut vilken frekvens AVR:en får in.
Skulle någon vänlig själ kunna översätta algoritmen för samplingen till svenska och förklara lite hur det fungerar? Det skulle underlätta en del...
//BN
Jag är ganska grön när det gäller mikroprocessorprogrammering och kan, trots många funderingsförsök, inte fatta hur programmet räknar ut vilken frekvens AVR:en får in.
Skulle någon vänlig själ kunna översätta algoritmen för samplingen till svenska och förklara lite hur det fungerar? Det skulle underlätta en del...
//BN
En kort sammanfattning:
Programmet användet timer0 (overflow interrupt) som tidsreferens (här: 172.8 kHz). Sedan räknar den tiden det tar för din mätpinne (I/O) att gå från låg till hög, d.v.s mäter tiden för 32 perioder med tidsreferensen (timern).
Överallt finns det tester för att avbryta om det uppenbart är ett helt galet mätvärde.
Sedan kommer det magiska med siffrorna.
Ett snitt dras ur de 32 ackumulerade periodtiderna. Därefter jämförs de med tabellerna som deklareras i början av programmet.
Först letar den upp vilken sträng som ligger närms till hands för frekvenen i fråga, sedan kollar den vilken ton du försöker spela, om det är en exakt match eller bara nästan.
Den kan alltså inte kolla vilken sträng du spelar på, det krävs betydligt mer sofistikerade algoritmer för det (som inte en AVR pallar med realtid). Däremot är den (förhoppningsvis) bra på att gissa vilken ton du försöker spela. Om du kopplar till lite fler LED kan du nog lätt visa vilken ton som matchas närmst. Du bör även lätt kunna lägga till fler grader av frekvensavvikelse om så önskas.
Programmet användet timer0 (overflow interrupt) som tidsreferens (här: 172.8 kHz). Sedan räknar den tiden det tar för din mätpinne (I/O) att gå från låg till hög, d.v.s mäter tiden för 32 perioder med tidsreferensen (timern).
Överallt finns det tester för att avbryta om det uppenbart är ett helt galet mätvärde.
Sedan kommer det magiska med siffrorna.
Ett snitt dras ur de 32 ackumulerade periodtiderna. Därefter jämförs de med tabellerna som deklareras i början av programmet.
Först letar den upp vilken sträng som ligger närms till hands för frekvenen i fråga, sedan kollar den vilken ton du försöker spela, om det är en exakt match eller bara nästan.
Den kan alltså inte kolla vilken sträng du spelar på, det krävs betydligt mer sofistikerade algoritmer för det (som inte en AVR pallar med realtid). Däremot är den (förhoppningsvis) bra på att gissa vilken ton du försöker spela. Om du kopplar till lite fler LED kan du nog lätt visa vilken ton som matchas närmst. Du bör även lätt kunna lägga till fler grader av frekvensavvikelse om så önskas.
Tackar ödmjukast för hjälpen!
Nu tror jag att jag förstår hur det fungerar. Jag missade att man faktiskt får periodtiden i "pinne_låg till pinne_hög"-övergången. Jag var helt insnöad på att man skulle räkna hur många övergångar/pulser man skulle få under en fördefinierad tid, även om det så här i efterhand förefaller mycket smartare att göra på det andra sättet.
Tack än en gång för hjälpen!
En liten fråga till dock:
I detta kodavsnitt
Kommer break:en avbryta exekveringen av while-satsen eller for-satsen?
//BN
Nu tror jag att jag förstår hur det fungerar. Jag missade att man faktiskt får periodtiden i "pinne_låg till pinne_hög"-övergången. Jag var helt insnöad på att man skulle räkna hur många övergångar/pulser man skulle få under en fördefinierad tid, även om det så här i efterhand förefaller mycket smartare att göra på det andra sättet.
Tack än en gång för hjälpen!
En liten fråga till dock:
I detta kodavsnitt
Kod: Markera allt
// sample loop
for (i=0;i<32;i++)
{
while (bit_is_set(PINB,1)) // ignore hi->lo edge transitions
if (count_hi > 80) // skip if no edge is seen within
break; // a reasonable time
}
//BN
- JimmyAndersson
- Inlägg: 26593
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Jag tänkte också förslå FFT, men det kanske inte riktigt funkar på en 2323:a?!
Jimmy: är det någon specifik applikation du syftar på?! Gäller det t.ex. DTMF-avkodning så finns det ju andra sätt... känner man till vilka möjliga frekvenser man kan få in (som med DTMF) så sätter man enklast upp ett bandpassfilter för varje tänkbar ton och kollar var man har signal..
Jimmy: är det någon specifik applikation du syftar på?! Gäller det t.ex. DTMF-avkodning så finns det ju andra sätt... känner man till vilka möjliga frekvenser man kan få in (som med DTMF) så sätter man enklast upp ett bandpassfilter för varje tänkbar ton och kollar var man har signal..
- JimmyAndersson
- Inlägg: 26593
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
"Jimmy: är det någon specifik applikation du syftar på?!"
Nä, jag var mest nyfiken på teorin om hur man gör. Men jag har en idé om ett framtida projekt där jag behöver läsa av frekvenserna från en insignal som består av 3-4 samtidiga toner från ett instrumet.
FFT var en bra idé. Kräver visserligen ganska mycket "räknekapacitet" av både mig och någon processor. Det finns ju lite olika FFT-algoritmer, men jag vet inte om någon 8-bitars PIC-krets på 40MHz skulle orka någon sådan algoritm och mata ut frekvenserna på någon utgång (seriellt) samtidigt.
Med tanke på att jag bygger mycket ljud-prylar så borde jag verkligen lära mig att programmera DSP...
Nu tänker jag kanske inte tillräckligt "stort" men:
DTMF-standarden kräver att det är en skillnad i volym mellan de tonerna som spelas samtidigt. Sedan bygger det ju på att dessa toner är kända. Det innebär att det *måste* vara fler än en ton som avkodas för att man ska kunna använda DTMF.
Skulle Goertzel's algorithm fungera på flera samtidiga frekvenser som har lika hög amplitud? Den tycker jag är *betydligt* lättare än FFT, som jag knappt kan alls.
Det här med bandpassfilter gav mig en idé. Man behöver då ingen FFT eller Goertzel-algorithm för att separera frekvenserna: Man sätter ett bandpassfilter för varje möjlig frekvens. Med "lite" elektronik och D/A-omvandlare kopplat till en PIC kan man då få en 1a eller 0a för varje frekvens. T.ex:
D/A-omvandlaren ger ju förstås en analog signal in till PIC-kretsen, men visar man detta binärt så borde det bli som i tabellen ovan.
edit: Glömde skriva att varje utgång på bandpassfiltren kopplas till varsin ingång på D/A-omvandlaren.
Förstår ni hur jag menar?
Det borde väl fungera?
Nä, jag var mest nyfiken på teorin om hur man gör. Men jag har en idé om ett framtida projekt där jag behöver läsa av frekvenserna från en insignal som består av 3-4 samtidiga toner från ett instrumet.
FFT var en bra idé. Kräver visserligen ganska mycket "räknekapacitet" av både mig och någon processor. Det finns ju lite olika FFT-algoritmer, men jag vet inte om någon 8-bitars PIC-krets på 40MHz skulle orka någon sådan algoritm och mata ut frekvenserna på någon utgång (seriellt) samtidigt.
Med tanke på att jag bygger mycket ljud-prylar så borde jag verkligen lära mig att programmera DSP...

Nu tänker jag kanske inte tillräckligt "stort" men:
DTMF-standarden kräver att det är en skillnad i volym mellan de tonerna som spelas samtidigt. Sedan bygger det ju på att dessa toner är kända. Det innebär att det *måste* vara fler än en ton som avkodas för att man ska kunna använda DTMF.
Skulle Goertzel's algorithm fungera på flera samtidiga frekvenser som har lika hög amplitud? Den tycker jag är *betydligt* lättare än FFT, som jag knappt kan alls.

Det här med bandpassfilter gav mig en idé. Man behöver då ingen FFT eller Goertzel-algorithm för att separera frekvenserna: Man sätter ett bandpassfilter för varje möjlig frekvens. Med "lite" elektronik och D/A-omvandlare kopplat till en PIC kan man då få en 1a eller 0a för varje frekvens. T.ex:
Kod: Markera allt
Möjliga toner: G F E D C
0 0 0 0 1 = Tonen C spelas
0 0 0 1 0 = Tonen D spelas
0 0 0 1 1 = Tonerna C och D spelas samtidigt.
osv..
edit: Glömde skriva att varje utgång på bandpassfiltren kopplas till varsin ingång på D/A-omvandlaren.
Förstår ni hur jag menar?
Det borde väl fungera?