Atmega8 / Timer / Problem

#363844
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 ?
Moderator Persönliche Seite #363848
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).
#363849
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?
Moderator Persönliche Seite #363850
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren