www.mikrocontroller.net

Forum: Compiler & IDEs Atmega8 / Timer / Problem


Autor: Thomas L. (tom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo :) Ich bins schon wieder (ja, derzeit bin ich leider wirklich
lästig).

Ich habe einen Atmega8, welcher mit 1MHz läuft mit folgendem Code
versehen:

---snip---
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>

volatile uint8_t timerStartValue = 155; // Reload Value for Timer0

volatile uint8_t primaryRun = 0;
volatile uint8_t secondaryRun = 0;

// Interrupt Service Routine every 100 Cycles
ISR(TIMER0_OVF_vect)
{
  /* Test for each second: */
  primaryRun++;
  if (primaryRun == 100)
  {
    primaryRun = 0;
    secondaryRun++;
  }

  if (secondaryRun == 100)
  {
    secondaryRun = 0;
    PORTB = !(PORTB);
  }
}

int main(void)
{
  // Set PortB as output (we only need pins 0...2)
  PWM_PORT_DIRECTION = 0x00;
  PWM_PORT = 0x00;

  // Set values for Timer 0: No Prescaler, Timer start, Preload
  TCCR0 |= (1 << CS00);
  TCNT0 = timerStartValue;
  TIMSK |= (1 << TOIE0);

  // Enable global interrupts and wait
  sei();
  while(1);
}

---snip---

Im Prinzip funktioniert das auch, aber nicht mit dem Timing das ich
gerne hätte. Wenn ichs richtig berechnet hätte, müsste er jede Sekunde
einmal toggeln. Tut er jedoch nicht. Er toggelt zwar, aber nur alle 2,3
Sekunden (habe 10 mal getoggelt und es hat etwa 23 Sekunden gedauert).

Ich habe 1 000 000 Takzyklen / Sekunde. Meine Methode stellt sicher,
dass also 10 000 Zyklen mal getoggelt wird (100 * 100). Das heisst
doch, ich muss einfach bei jedem 100sten Taktzyklus toggeln. Also setze
ich den TCNT0 auf 155 ... er rennt hoch bis 255, dann kommt der Overflow
- das wären doch 100 Zyklen - oder denke ich falsch ?

Autor: Thomas L. (tom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, natürlich wird meine Methode nicht alle 10000 Zyklen toggeln,
aber sie muss 10 000 mal aufgerufen werden, bis sie toggelt.

Autor: Thomas L. (tom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, natürlich hatte ich die Zeile mit TCNT0 = timerStartValue;
ausgekommentiert (in meinem Testwahn). Leider stimmt es jedoch noch
immer nicht ganz genau (auch wenns schon recht nahe kommt).

Autor: Thomas L. (tom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, habs nochmal ausgemessen ...
20 Toggles dauern 24 Sekunden - also ein Faktor von 1,2 .. das kann
doch nicht die Ungenauigkeit des internen Takts sein, oder ?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> das kann doch nicht die Ungenauigkeit des internen Takts sein, oder?

Nein, aber der Overhead, bis die Overflow-Routine vom Timer 0 gerufen
wird, schließlich lässt du den ja mit Volldampf laufen.

Tu dir einen Gefallen und benutze einen Timerkanal, der CTC-Modus
(clear timer on compare match) beherrscht, dann führt die Hardware den
Reset des Timers beim Erreichen eines bestimmten Zählerstandes ohne
Verzögerung aus.  Falls es Timer 0 sein muss, dann erwäge einen
ATmega88 statt des ATmega8 zu benutzen, der kann das auch auf Kanal 0
(und ist ansonsten der designierte Nachfolger des ATmega8).

Wenn's unbedingt Kanal 0 mit ATmega8 sein muss, dann mach den
Vorteiler größer und zirkele aus, wieviel ``fuzz'' du auf den
Ladewert
draufschlagen musst, damit das Timing stimmt.  Dennoch wirst du einen
gewissen Jitter in Kauf nehmen müssen, insbesondere dann, wenn es im
System noch andere Interruptquellen gibt (sodass zumindest zeitweise
die Interrupts blockiert sind).

Autor: Thomas L. (tom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also verstehe ich das so richtig:
Meine Lösung: Wenn bei mir der Overflow auftritt, dann wird die ISR
aufgerufen, ausgeführt und dann erst der Timer wieder neu gestartet?

Wenn ich nun also Timer1 nehme (ich habe leider nut Atmega8 da), könnte
ich den CTC Modus nutzen (WGM12->1), würde in OCR1A einen Wert schreiben
und das würde funktionieren? Oder habe ich das jetzt falsch verstanden?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Meine Lösung: Wenn bei mir der Overflow auftritt, dann wird die ISR
> aufgerufen, ausgeführt und dann erst der Timer wieder neu gestartet?

Es müssten erst einige Befehle der ISR abgearbeitet werden, bis der
TCNT0 zurückgesetzt werden kann.  Ohne Prescaler bedeutet ,einige
Befehle' aber auch, dass der Timer bereits um einiges weitergezählt
hat.

Warum Konkunktiv?  Du hast ja ganz und gar vergessen, am Anfang von
TIMER0_OVF_vect TCNT0 überhaupt wieder auf timerStartValue zu setzen.
Übrigens wäre timerStartValue eher ein #define wert, auf keinen Fall
aber eine aufwändige `volatile'-Variable.  Auch primaryRun und
secondaryRun haben keine Notwendigkeit, sie mit `volatile' zu
verumständlichen.

(Sorry, habe mir den Code vorhin nicht richtig angeguckt.)

> Wenn ich nun also Timer1 nehme (ich habe leider nut Atmega8 da),
> könnte ich den CTC Modus nutzen (WGM12->1), würde in OCR1A einen
> Wert schreiben und das würde funktionieren?

So ungefähr ja.  Der Unterschied ist, dass die CTC-Logik positiv ist,
der Zähler zählt also von 0 bis OCR1A und wird dann von der Hardware
auf 0 rückgesetzt.  Die Overflow-Logik ist negativ (wenn man sie zur
Verkürzung der Zählweite benutzen will), d. h. du lädst den Zähler auf
(256 - Zählweite) vor und wartest den Überlauf ab.

Autor: Thomas L. (tom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also die volatile Lösung war nur eine quick n dirty lösung. Das Setzen
des TCNT hatte ich nur vergessen, mitzukopieren (steht aber eh 2
Postings drunter).

Dank dir auf jeden Fall mal. Ich werde es jetzt mal mit dem CTC vom
8bit Timer2 probieren :)

Herzlichen Dank nochmals derweil :)

Autor: Thomas L. (tom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
omg jetzt bin ich baff ...
Hat auf Anhieb funktioniert. Erstes Mal das Programm reingeschrieben,
geht ...

Dank dir vielmals :) So macht das Spaß :)

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.