Forum: Mikrocontroller und Digitale Elektronik Timer0 wie benutzt man ihm


von Wojtek S. (wojtek)


Lesenswert?

Hallo habe eine Frage wie ich den Teimer0 benutzen kann?
Ich habe den teimer0 initialisiert dass er alle 16 ms einen Overflow 
erzeugt. Ich möchte eine Diode alle 3 Sekunden an und wider aus 
schalten.
Nun ist meine Frage wie kriege ich das hin?
Habe hier im Tutorium gelesen dass wenn ein Overflow kommt dann wird in 
TIFR Register T0V0 auf Null gesetzt. Bedeutet für mich der Teimer0 ist 
wieder aus.
Muss ich den Timer jetzt 3s/16ms=187,5 mal neu starten. Nun habe ich das 
auch gemacht und die Diode leuchtet und leuchtet.
kann mir jemand sagen was ich falsch mache ?
hier mein Quelltext


#include "avr/io.h"
#include "iom128.h"

#define  _AVR_ATMEGA128_  1
#define OSCSPEED  16000000    /* in Hz */

void PORT_Init()
{
  PORTA = 0b00000000;    DDRA = 0b01000000;  //Relay set as output (Bit6 
= 1)
  PORTB = 0b00000000;    DDRB = 0b00000000;
  PORTC = 0b00000000;    DDRC = 0b11110111;
  PORTD = 0b11000000;    DDRD = 0b00001000;  //TX set as output (Bit3 = 
1)
  PORTE = 0b00000000;    DDRE = 0b00110000;  //Buzzer set as output 
(Bit4 = 1, Bit5 = 1)
  PORTF = 0b00000000;    DDRF = 0b00000000;
  PORTG = 0b00000000;    DDRG = 0b00000000;
}

void init_timer0()
  {
  TCCR0  |= 0b00000111;
  TCNT0 = 6;
  TIMSK |= 0b00000001;
  }

int main()
{
while(1)
 {
  int i,j;
  for (i=0; i<175; i++)
   {
    init_timer0();
    PORTA = PORTA | 0b11000000;
   }
  for (j=0; j<175; j++)
   {
    init_timer0();
    PORTA = PORTA & 0b00000000;
    }
 }
}

von Justus S. (jussa)


Lesenswert?

Wojtek Szopieraj wrote:
> Hallo habe eine Frage wie ich den Teimer0 benutzen kann?
> Ich habe den teimer0 initialisiert dass er alle 16 ms einen Overflow
> erzeugt. Ich möchte eine Diode alle 3 Sekunden an und wider aus
> schalten.
> Nun ist meine Frage wie kriege ich das hin?
> Habe hier im Tutorium gelesen dass wenn ein Overflow kommt dann wird in
> TIFR Register T0V0 auf Null gesetzt. Bedeutet für mich der Teimer0 ist
> wieder aus.

nein..wo liest du denn das bitte raus??

und im Moment machst du mit dem Timer auch gar nichts, außer ihn am 
laufenden Band eine "Initialisierung"...

von Wojtek S. (wojtek)


Lesenswert?

habe das gelesen in
"http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Timer-Bitzahlen_verschiedener_AVR.27s";
Bei den Timer

"Um nun also den Timer0 in Betrieb zu setzen und ihn mit einer Frequenz 
von 1/1024-tel des CPU-Taktes zählen zu lassen, schreiben wir die 
folgende Befehlszeile:

    TCCR0 |= (1<<CS00)|(1<<CS02);

Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen. 
Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf 
0 wird das Timer Overflow Flag TOV0 im Timer Interrupt Flag 
TIFR-Register gesetzt und, falls so konfiguriert, ein entsprechender 
Timer-Overflow-Interrupt ausgelöst und die daran gebundene 
Interrupt-Routine abgearbeitet. Das TOV Flag lässt sich durch das 
Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder 
zurücksetzen. "

Habe ich da etwas falsch verstanden.

wie starte ich den Timer dan? Es reicht ja 1 mal den timer zu 
initialisieren.

von Justus S. (jussa)


Lesenswert?

Wojtek Szopieraj wrote:
> habe das gelesen in
> 
"http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Timer-Bitzahlen_verschiedener_AVR.27s";
> Bei den Timer
>
> "Um nun also den Timer0 in Betrieb zu setzen und ihn mit einer Frequenz
> von 1/1024-tel des CPU-Taktes zählen zu lassen, schreiben wir die
> folgende Befehlszeile:
>
>     TCCR0 |= (1<<CS00)|(1<<CS02);
>
> Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen.
> Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf
> 0 wird das Timer Overflow Flag TOV0 im Timer Interrupt Flag
> TIFR-Register gesetzt und, falls so konfiguriert, ein entsprechender
> Timer-Overflow-Interrupt ausgelöst und die daran gebundene
> Interrupt-Routine abgearbeitet. Das TOV Flag lässt sich durch das
> Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder
> zurücksetzen. "
>
> Habe ich da etwas falsch verstanden.

ja

> wie starte ich den Timer dan? Es reicht ja 1 mal den timer zu
> initialisieren.

Der Timer wird durch das setzen von TCCR0 automatisch gestartet. Und 
wenn man sonst wweiter nichts einstellt, würde er ewig im Hintergrund 
weiterlaufen. Beim Erreichen des Maximalwerts (bei 16Mhz und Prescaler 
1024 1/61 s) wird dann das Interruotflag gesetzt. Das tut erstmal 
nichts, nur wenn das der Overflow-Interrupt aktiviert ist. Dann springt 
er in die zugehörige Interrupt-Routine (siehe Tut), wo du dann darauf 
reagieren kannst (der Timer läuft in der Zwischenzeit weiter). In dieser 
Routine könntest du zB eine selbst definierte Zählvariable hochzählen 
lassen und die dann in der Hauptroutine auswerten, zB um die 3 Sekunden 
zu messen...

von Johannes M. (johnny-m)


Lesenswert?

Wojtek Szopieraj wrote:
> Nun ist meine Frage wie kriege ich das hin?
> Habe hier im Tutorium gelesen dass wenn ein Overflow kommt dann wird in
> TIFR Register T0V0 auf Null gesetzt. Bedeutet für mich der Teimer0 ist
> wieder aus.
Erstens wird es nicht auf 0 gesetzt, sondern auf 1. Auf 0 wird es erst 
wieder gesetzt, wenn der dazugehörige Interrupt Handler ausgeführt wird. 
Wenn ohne Interrupt gearbeitet wird, dann muss das Flag von Hand 
gelöscht werden.

Zweitens geht dadurch nicht der Timer aus. Der läuft so lange weiter, 
bis er über die CS-Bits im TCCR0 anghalten wird.

> Muss ich den Timer jetzt 3s/16ms=187,5 mal neu starten.
Nein. Siehe oben.

> #include "iom128.h"
Was soll dieses #include? Was für eine Datei soll das sein? Du hast doch 
oben schon die avr/io.h eingebunden. Die genügt völlig.

> #define  _AVR_ATMEGA128_  1
Und was soll das?

> #define OSCSPEED  16000000    /* in Hz */
Wenn schon, dann bitte F_CPU nennen. Damit können dann auch eventuelle 
Header was anfangen.

> void init_timer0()
>   {
>   TCCR0  |= 0b00000111;
>   TCNT0 = 6;
>   TIMSK |= 0b00000001;
>   }
Bitte schau Dir mal den Artikel zum Thema Bitmanipulation an und 
benutze die Bitnamen. Das kann so keiner vernünftig lesen.

Außerdem ist ein Timer-Vorladen keine gute Idee. Für solche Dinge haben 
die Timer den CTC-Modus. Aber OK, für den Anfang kann man es so 
machen...

> int main()
> {
> while(1)
>  {
>   int i,j;
>   for (i=0; i<175; i++)
>    {
>     init_timer0();
>     PORTA = PORTA | 0b11000000;
>    }
>   for (j=0; j<175; j++)
>    {
>     init_timer0();
>     PORTA = PORTA & 0b00000000;
>     }
>  }
> }
Wie oben schon gesagt, es ist Unsinn, den Timer ständig neu zu 
initialisieren.

Aber das größte Problem ist, dass Du nirgends etwas mit dem Timer 
machst! Das Überlauf-Ereignis wird nirgends ausgewertet. Wie soll denn 
auf die Weise irgendetwas passieren? Die LED geht zwar vermutlich 
ständig aus und an, aber so schnell, dass Du es nicht sehen kannst. Es 
wird jedes Mal 175 mal der Timer initialisiert und dann die LED 
umgeschaltet.

von Wojtek S. (wojtek)


Lesenswert?

wass muss ich dann noch machen um den timer zu benutzen,
gibt es irgendowo ein einfaches beispiel ??

von Hannes Lux (Gast)


Lesenswert?

> wass muss ich dann noch machen um den timer zu benutzen,

In der Init:
- Timer einschalten (Vorteiler wählen)
- Timer-Interrupt freigeben
- Interrupts global freigeben (I-Flag setzen, SEI)

In der ISR:
- Zählvariable herunterzählen
- bei Zählerstand 0 Aktion ausführen und Zählvariable auf Startwert
  setzen
- falls die Aktion etwas umfangreicher ist, dann stattdessen einen
  Merker setzen, den die Mainloop abfragt, löscht und die Aktion
  ausführt
- ISR möglichst kurz halten, also keine komplexen Funktionen aufrufen

> gibt es irgendowo ein einfaches beispiel ??

Von mir nicht, ich werkele nur in ASM.

...

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.