Forum: Mikrocontroller und Digitale Elektronik Rechenfehler Timerberechnung, Mega128


von Karlheinz D. (kdruschel)


Lesenswert?

Hi Leuts, ich habe hier irgendwie einen Rechenfehler, vielleicht kann 
mir jemand helfen:
Ich habe einen Mega128 mit 16 MHz Quarz. Nun möchte ich Timer2 so 
konfigurieren, dass im Abstand von 1 ms ein Interrupt (ich habe mal den 
Compare genommen) ausgelöst wird. Zum Test lasse ich mal eine LED 
blinken. Prinzipiell funktioniert der Code, aber das mit der 1 ms haut 
nicht hin. Derzeit blinkt die LED vielleicht alle 500 ms (geschätzt). 
Ich rechne folgendermaßen:
Bei 16 MHz stelle ich einen Prescaler von 128 ein, womit ich bei 125 kHz 
bin. Das entspricht einer Periodendauer von 8 µs. Wenn ich dann bis 125 
zähle bin ich bei genau 1 ms.
Wo liegt mein Rechenfehler ?

int main()
{
  DDRG = 0xff;   // fuer die LED

  // CTC-Mode einstellen
  TCCR2 =0;
  TCCR2 |= (1<<WGM21) | (0<<WGM20);

  // Prescaler einstellen 128
  TCCR2 |= (1<<CS00) | (1<<CS02);

  // CTC-Vergleichswert
  OCR2 = 125;
  // Compare-Interrupt aktivieren
  TIMSK |= (1<<OCIE2);
  liveled = 0;
  sei();

  while (1)
  {
      // LiveLED steuern
      if (liveled > 0)
      {
          liveled = 0;
    PORTG ^= (1<<PG4);
            }
  }
  return 1;
}

ISR(TIMER2_COMP_vect)
{
  liveled++;
}

von spess53 (Gast)


Lesenswert?

Hi

>Bei 16 MHz stelle ich einen Prescaler von 128 ein,

Hat der Timer nicht.

TCCR2 |= (1<<CS00) | (1<<CS02);   <- Fehler

Abgesehen, das es CS20/CS22 heissen muss, stellt das beim Timer2 einen 
Vorteiler von 1024 ein.

MfG Spess

von Karlheinz D. (kdruschel)


Lesenswert?

Stimmt. Aber wenn ich über 64 gehe und bis 250 zähle passiert gar nix 
mehr.
int main()
{

  DDRG = 0xff;

  // 16 bit Counter
//  TCNT2 = 65536-125;    /* aktuellen Zaehlerstand setzen */

  // Einstellungen definieren
//  TCCR2 = 0;

  // Takt = CPU Takt / 128
//  TCCR2 |= (1<<CS00) | (1<<CS02);

  // Normalmode
//  TCCR2 |= (0<<WGM00) | (1<<WGM01) | (0<<COM01) | (0<<COM00);

  // Enable Overflowinterrupt
//  TIMSK |= (1<<TOIE2);
//  TIMSK |= (1<<OCIE0A);

  // CTC-Mode einstellen
  TCCR2 =0;
  TCCR2 |= (1<<WGM21) | (0<<WGM20);

  // Prescaler einstellen 64
  TCCR2 |= (1<<CS20) | (1<<CS21) | (0<<CS22);

  // CTC-Vergleichswert
  OCR2 = 250;
  // Compare-Interrupt aktivieren
  TIMSK |= (1<<OCIE2);
  // Hilfszaehler loeschen
  liveled = 0;
  sei();

  while (1)
  {

    // LiveLED steuern
    if (liveled > 1000)
    {
      liveled = 0;
      PORTG ^= (1<<PG4);
    }
  }
  return 1;
}

von spess53 (Gast)


Lesenswert?

Hi

Wenn mich meine rudimentären C-Kenntnisse nicht täuschen, sollte 
'liveled' volatile sein.

MfG Spess

von Karlheinz D. (kdruschel)


Lesenswert?

sorry, habe ich vergessen einzublenden. Das ist sie, daran kann es ja 
auch nicht liegen, denn mit anderen Timereinstellungen blinkt sie ja 
auch. Aber eben nicht in der richtigen Zeit.

von Karlheinz D. (kdruschel)


Lesenswert?

ok, aber wenn ich das mache:
    if (liveled > 10)
    {
      liveled = 0;
      PORTG ^= (1<<PG4);
    }
dann sehe ich ihn wieder blinken, also muß doch irgendwas an meiner 
Rechnung nicht stimmen!!!

von spess53 (Gast)


Lesenswert?

Hi

Poste doch einfach mal ein komplettes Programm und nicht nur Fragmente.

Noch ein Hinweis: 'OCR2 = 250;' ist nicht richtig. In der Formel ist 
noch ein '-1' enthalten. Also 249.

MfG Spess

von Karlheinz D. (kdruschel)


Lesenswert?

volatile uint8_t liveled=0;

int main()
{

  DDRG = 0xff;

  // CTC-Mode einstellen
  TCCR2 =0;
  TCCR2 |= (1<<WGM21) | (0<<WGM20);

  // Prescaler einstellen 64
  TCCR2 |= (1<<CS20) | (1<<CS21) | (0<<CS22);

  // CTC-Vergleichswert
  OCR2 = 250;
  // Compare-Interrupt aktivieren
  TIMSK |= (1<<OCIE2);
  // Hilfszaehler loeschen
  liveled = 0;
  sei();

  while (1)
  {

    // LiveLED steuern
    if (liveled > 10)
    {
      liveled = 0;
      PORTG ^= (1<<PG4);
    }
  }
  return 1;
}



ISR(TIMER2_COMP_vect)
{
  liveled++;
}

Bitte, aber ich denke wie gesagt an einen Denkfehler bei mir :-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

liveled wirkt dann als Softwarezähler. Angenommen dein Timer stimmt 
jetzt mit 1ms, dann toggelst du alle 11 ms. Das ist fast 100 Hz. Das ist 
schon schwer zu sehen. Je weiter du liveled zählen lässt, desto 
langsamer und besser sichtbar blinkt die LED.

von pi (Gast)


Lesenswert?

Wie ist denn nach dem letzten SW Stand die Blinkdauer?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Stefan B. schrieb:

> Das ist
> schon schwer zu sehen.

Wenn es gut sichtbar ist, dann läuft der µC nicht mit 16 MHz. [[AVR 
Fuses]] prüfen.

von spess53 (Gast)


Lesenswert?

Hi

Wenn 'volatile uint8_t liveled=0;' schon immer drin war kann (in deinem 
1.Programm)  'if (liveled > 1000)' nicht funktionieren. 'liveled' kann 
maximal 255 sein.

MfG Spess

von pi (Gast)


Lesenswert?

spess53 schrieb:
> Wenn 'volatile uint8_t liveled=0;' schon immer drin war ...

Das ist einer der tieferen Gründe warum man hier immer vollständigen 
Code posten soll.

von Karlheinz D. (kdruschel)


Lesenswert?

Oh shit, bin ich doof. Da hast Du natürlich recht, aber leider hilft es 
nix.
Der aktuelle Stand ist so, dass die Led ca. alle 1.5 s blinkt. Bei 
folgendem Code:

volatile uint16_t liveled=0;

int main()
{

  DDRG = 0xff;

  // CTC-Mode einstellen
  TCCR2 =0;
  TCCR2 |= (1<<WGM21) | (0<<WGM20);

  // Prescaler einstellen 64
  TCCR2 |= (1<<CS20) | (1<<CS21) | (0<<CS22);

  // CTC-Vergleichswert
  OCR2 = 250;
  // Compare-Interrupt aktivieren
  TIMSK |= (1<<OCIE2);
  // Hilfszaehler loeschen
  liveled = 0;
  sei();

  while (1)
  {

    // LiveLED steuern
    if (liveled > 100)
    {
      liveled = 0;
      PORTG ^= (1<<PG4);
    }
  }
  return 1;
}

/////////////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////////////
ISR(TIMER2_COMP_vect)
{
  liveled++;
}

von spess53 (Gast)


Lesenswert?

Hi

Hast du die Fuses überprüft?

MfG Spess

von Karlheinz D. (kdruschel)


Lesenswert?

Ok, das war´s :-) lol, stand auf internem RC statt auf externem Quarz.
1000Dank für die Sonntags-Nachhilfe :-)

Greets

von spess53 (Gast)


Lesenswert?

Hi

>Ok, das war´s :-) lol, stand auf internem RC statt auf externem Quarz.
>1000Dank für die Sonntags-Nachhilfe :-)

Der Hinweis kam schon von Stefan.

MfG Spess

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.