Sida 1 av 1
Frekvensproblem
Postat: 4 april 2007, 12:40:03
av JBV
Jag sitter och försöker få en timer på en AVR ATMega88 med 20 MHz kristall att fungera i ordning.
Utdrag ur koden:
Kod: Markera allt
void TIMER_Init()
{
TCCR2B |= _BV(CS20);
TIMSK2 |= _BV(TOIE2);
TCNT2 = 0;
}
ISR(TIMER2_OVF_vect)
{
Counter++;
if(Counter >= 72000)
{
USART_Transmit('x');
Counter = 0;
}
}
När jag sitter vid terminalpogrammet och klockar 20 st "x" så får jag ~17,5 sekunder istället för 20 som det borde vara! Såvitt jag förstått ska man få overflow 72000 ggr i sekunden @ 20MHz Är den siffran fel? Det är ju ändå hela 12,5% fel (vilket ger 81000Hz).
Postat: 4 april 2007, 13:20:22
av Millox
Om du har en prescale på 256 (antar jag, den är närmast iaf) får du:
20e6./256 = 78125
interrupt per sekund. Du räknar upp till 72000 vilket ger längden
72000./78125 = 0.9216 'x' per sekund.
vilket ger:
0.9216 .* 20 = 18.4 sekunder för 20 st 'x'. Ungefär där du hamnar va?
Du ska räkna upp till 78125 istället. Dock rekommenderar jag dig att öka upp prescalen något så du hamnar på tal som kan beskrivas iaf med 16 bitar.
Postat: 4 april 2007, 13:51:06
av JBV
Aha, då är det "AVR App" som driver med mig hehe. Jag har valt prescaler 1 och får: TCCR2B |= _BV(CS20); och overflow freq: 72000.00 Hz för 20Mhz
Gäller väl att klura ut hur man ställer in prescale korrekt då!
Postat: 4 april 2007, 14:39:26
av Marta
Skall det vara en klocka? Behöver Du bara en sekunds upplösning och det inte gör något med lite gitter så dra ner interruptfrekvensen till c:a 5/s. Du bränner av massor av CPU på ingenting, speciellt som det är s.k. högnivåspråk Du använder. Du kan få hur hög precision som helst även vid denna låga frekvens.
Postat: 4 april 2007, 14:53:41
av Millox
Um, ja så blir det förstås. Iom att du använder overflow-interruptet får du automagiskt division med 256 (8-bitars timer), men uträkningen är fel iaf. ska vara 78.... som jag skrev.
Annars tycker jag du ska göra såhär:
Använd timer1 och aktivera compare match-interruptet. Ställ in prescalern på 512 eller 1024 (beroende på vad som finns, kommer inte ihåg om 512 finns) och ladda compare-registret med 19531. Du får då en match ungefär varje sekund. Felet blir nånstans i storleksordningen 1,3 sekunder per 28 timmar. Räcker den noggrannheten blir det bra, annars får du ta till andra lösningar, typ mata in korrektion i overflow-interruptet (+1 var fjärde varv)
Postat: 4 april 2007, 15:05:32
av JBV
Jag ska köra en funktion i 2-3000 Hz och en i 1-500 Hz så det går inte så bra!
Som det ser ut nu har jag gjort såhär:
Kod: Markera allt
#define TimerFrequency 78125
#define PIDFrequency (1 / 2000) * TimerFrequency
#define FaultFrequency (1 / 100) * TimerFrequency
long PIDCounter = 0;
long FaultCounter = 0;
char PIDLoopFlag = 0;
char FaultLoopFlag = 0;
void TIMER_Init()
{
TCCR2B |= _BV(CS20); //Enable timer2 @ 78125 Hz
TIMSK2 |= _BV(TOIE2); //Enable timer2 overflow interrupt
TCNT2 = 0; //Set timer2 to 0
}
ISR(TIMER2_OVF_vect)
{
PIDCounter++;
if(PIDCounter >= PIDFrequency)
{
PIDLoopFlag = 1;
PIDCounter = 0;
}
FaultCounter++;
if(FaultCounter >= FaultFrequency)
{
FaultLoopFlag = 1;
FaultCounter = 0;
}
}
Sen kollar jag i en evig loop i main om Fault- och PIDLoopFlag är 1 och kör respektive funktion.
Postat: 4 april 2007, 15:11:43
av Millox
Dela ner så du matchar i typ 5000 Hz eller så då, (prescaler 1 värde 4000) så får du compare match i 5000 Hz och då kan du köra varannan så blir det 2500 Hz och var tionde för 500 Hz. Då blir det dessutom exakt.
Postat: 4 april 2007, 16:01:23
av JBV
Jag låter det vara sådär tills vidare

Har mycket annat jag vill få igång innan jag börjar fila på detaljerna hehe
Postat: 4 april 2007, 23:27:49
av $tiff
>> JBV
Koden i ditt första inlägg kan vara dålig, inte så konstigt om tajmingen int stämmer. Hur är funktionen " USART_Transmit()" konstruerad? Om funktionen tar mer än, låt säga 150 instruktioner, så kan interrupten ta längre tid än timern tar på sig att räkna ner. På så sätt kan du lätt missa massa räknande på countern.
Postat: 4 april 2007, 23:35:58
av JBV
Det var bara ett test i första inlägget... När jag ändrade från 72000 till 78125 blev det bättre

Men jag förstår absolut vad du menar!
Transmit funktionen ser ut såhär:
Kod: Markera allt
void USART_Transmit(unsigned char data)
{
while (!(UCSR0A & (1<<UDRE0)));
UDR0 = data;
}
Nu ser det ut såhär och fungerar perfekt!
Kod: Markera allt
ISR(TIMER2_OVF_vect)
{
PIDCounter++;
if(PIDCounter >= PIDFrequency)
{
PIDLoopFlag = 1;
PIDCounter = 0;
}
FaultCounter++;
if(FaultCounter >= FaultFrequency)
{
FaultLoopFlag = 1;
FaultCounter = 0;
}
}
Postat: 5 april 2007, 02:38:44
av cykze
JBV skrev:Aha, då är det "AVR App" som driver med mig hehe. Jag har valt prescaler 1 och får: TCCR2B |= _BV(CS20); och overflow freq: 72000.00 Hz för 20Mhz
Gäller väl att klura ut hur man ställer in prescale korrekt då!
Med "AVR App" syftar du då på mitt program "AVR Wizard"?
Postat: 5 april 2007, 11:00:41
av JBV
Möjligt, minns inte vart jag laddade hem det, men filen och titelraden heter "avr_app.exe"