www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Rechenfehler Timerberechnung, Mega128


Autor: Karlheinz Druschel (kdruschel)
Datum:

Bewertung
0 lesenswert
nicht 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++;
}

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karlheinz Druschel (kdruschel)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

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

MfG Spess

Autor: Karlheinz Druschel (kdruschel)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karlheinz Druschel (kdruschel)
Datum:

Bewertung
0 lesenswert
nicht 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!!!

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karlheinz Druschel (kdruschel)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: pi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ist denn nach dem letzten SW Stand die Blinkdauer?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: pi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karlheinz Druschel (kdruschel)
Datum:

Bewertung
0 lesenswert
nicht 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++;
}

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Hast du die Fuses überprüft?

MfG Spess

Autor: Karlheinz Druschel (kdruschel)
Datum:

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

Greets

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.