Frekvensproblem

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Frekvensproblem

Inlägg 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).
Millox
Inlägg: 559
Blev medlem: 10 december 2005, 22:10:43
Ort: Östhammar

Inlägg 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.
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg 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å!
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg 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.
Millox
Inlägg: 559
Blev medlem: 10 december 2005, 22:10:43
Ort: Östhammar

Inlägg 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)
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg 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.
Millox
Inlägg: 559
Blev medlem: 10 december 2005, 22:10:43
Ort: Östhammar

Inlägg 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.
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg 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
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg 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.
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg 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;
  }
}
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg 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"?
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Möjligt, minns inte vart jag laddade hem det, men filen och titelraden heter "avr_app.exe"
Skriv svar