Forum: Mikrocontroller und Digitale Elektronik Timer0 mit Interrupt (ATMega8) - Denkfehler im Code?


von Clemens B. (Gast)


Lesenswert?

Hallo,

mein Ziel ist es timer0 für 20ms(3,6864MHz Quarz) laufen zu lassen, und 
in der ISR zu deaktivieren.
Die LED ist laut Oszi immer an. Wieso?
Ich bin für alle Hinweise und Erklärungen dankbar.

Das ist der Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "Header/timer.h"
4
5
#define TIMER0_LAEUFT     !(TIFR & (1<<TOV0))
6
7
int main(void)
8
{
9
  DDRB |= (1<<PB2);
10
  timer0_init();
11
  sei();
12
13
  while(1)
14
  {
15
    PORTB  &= ~(1<<PB2);
16
    TIMER0_START
17
18
    while(TIMER0_LAEUFT)
19
    {
20
      PORTB  |= (1<<PB2);
21
    }
22
  }
23
}
1
#ifndef HEADER_TIMER_H_
2
#define HEADER_TIMER_H_
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
7
#define TIMER0_START TCCR0 |= ((1<<CS02) | (1<<CS00));  // prescaler 1024 -> 3600Hz
8
#define TIMER0_STOP TCCR0 &= ~((1<<CS02) | (1<<CS00));
9
10
void timer0_init(void);
11
ISR(TIMER0_OVF_vect);
12
13
#endif /* HEADER_TIMER_H_ */
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "../Header/timer.h"
4
5
void timer0_init(void)
6
{
7
  TCNT0 = 0x48;  // 3600Hz / 72 = 50Hz -> 20ms. TCNT0 = 0x48 (183 =255-72)
8
  TIMSK |= (1<<TOIE0);
9
  TCCR0 &= ~((1<<CS02) | (1<<CS01) | (1<<CS00));  // timer0 deaktiviert initialisieren
10
                          // mit Makro "timer0_start" (siehe timer.h) im Code starten
11
}
12
13
ISR(TIMER0_OVF_vect)
14
{
15
  TCNT0 = 0x48;  // preload Wert fuer 20ms bei 3,6kHz
16
  TIMER0_STOP
17
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Clemens B. schrieb:
> Die LED ist laut Oszi immer an.
Welche LED und was bedeutet "an"?

von Oliver S. (oliverso)


Lesenswert?

Wenn du den Timer in deiner Hauptschleife immer wieder einschaltest, was 
meinst du, wie lange der nach einem Interrupt aus bleibt?

Oliver

von Clemens B. (Gast)


Lesenswert?

Sorry, an PB2 ist die LED angeschlossen. An der liegt dauerhaft high an, 
sprich es hängt hier im Code:
1
 while(TIMER0_LAEUFT)
2
    {
3
      PORTB  |= (1<<PB2);
4
    }

von Clemens B. (Gast)


Lesenswert?

Oliver S. schrieb:
> Wenn du den Timer in deiner Hauptschleife immer wieder
> einschaltest, was
> meinst du, wie lange der nach einem Interrupt aus bleibt?
>
> Oliver
1
#define TIMER0_LAEUFT     !(TIFR & (1<<TOV0))
2
3
while(TIMER0_LAEUFT)

Diese while Schleife sollte er doch erst nach der ISR verlassen oder 
nicht?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Clemens B. schrieb:
> while(TIMER0_LAEUFT)
>
> Diese while Schleife sollte er doch erst nach der ISR verlassen oder
> nicht?

 Ja, und ?
1
    PORTB  &= ~(1<<PB2);   // LED AUS   --+ Wieviel Zeit
2
    TIMER0_START           //             | vergeht
3
                           //             | zwischen
4
    while(TIMER0_LAEUFT)   //             | diesen
5
    {                      //             | zwei
6
      PORTB  |= (1<<PB2);  // LED AN    --+ Befehlen ?
7
    }

von Oliver S. (oliverso)


Lesenswert?

Clemens B. schrieb:
> Diese while Schleife sollte er doch erst nach der ISR verlassen oder
> nicht?

Diese while-Schleife wird niemals verlassen. Die ISR funkt zwar 
dazwischen, aber danach geht's munter im while-Kreis weiter.

Oliver

von Clemens B. (Gast)


Lesenswert?

Oliver S. schrieb:
> Clemens B. schrieb:
>> Diese while Schleife sollte er doch erst nach der ISR verlassen oder
>> nicht?
>
> Diese while-Schleife wird niemals verlassen. Die ISR funkt zwar
> dazwischen, aber danach geht's munter im while-Kreis weiter.
>
> Oliver

Ach verdammt stimmt, da ist der Denkfehler. Danke!

von Clemens B. (Gast)


Lesenswert?

Ps. Für den Fall, dass es irgendwann mal jemanden hilft. Ich hab es 
jetzt so gelöst und es läuft wie erwartet:
1
#define TIMER0_LAEUFT   TCCR0 && 0x05

Kann geschlossen werden.
Danke nochmal.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Clemens B. schrieb:
> es läuft wie erwartet:
> #define TIMER0_LAEUFT   TCCR0 && 0x05
Tatsächlich mit dem logischen &&?
Dann wäre es das selbe wie
#define TIMER0_LAEUFT   TCCR0
(denn 0x05 ist immer "true" und kann für ein logisches Und ignoriert 
werden)
Und damit muss nur irgendein Bit im TCCR0 gesetzt sein, dass auch 
TIMER0_LAEUFT "true" ist...

von Clemens B. (Gast)


Lesenswert?

Lothar M. schrieb:
> Clemens B. schrieb:
>> es läuft wie erwartet:
>> #define TIMER0_LAEUFT   TCCR0 && 0x05
> Tatsächlich mit dem logischen &&?
> Dann wäre es das selbe wie
> #define TIMER0_LAEUFT   TCCR0
> (denn 0x05 ist immer "true")
> Und damit muss nur irgendein Bit im TCCR0 gesetzt sein, dass auch
> TIMER0_LAEUFT "true" ist...

Natürlich das bitweise UND. Vorm posten prüfe ich nächstes Mal..

von Falk B. (falk)


Lesenswert?

@Clemens B. (Gast)

>Natürlich das bitweise UND. Vorm posten prüfe ich nächstes Mal..

Eine gute Idee. Außerdem sollte man derartige Makros IMMER mit einer 
Klammer versehen, damit es nicht zu komischen Nebeneffekten kommt, wenn 
das Makro in einem komplexeren Ausdruck eingesetzt wird und dort 
höherpriorisierte Operatoren angewendet werden. Aber deine Makro ist 
immer noch nicht wasserdicht. Warum prüfst du nicht einfach alle drei 
CSx Bits? Und wenn man es ordentlich und direkt verständlich schreiben 
will, nimmt man die Bitnamen und keine magic numbers.

Siehe Bitmanipulation und
Strukturierte Programmierung auf Mikrocontrollern.

Also eher so.
1
#define TIMER0_LAEUFT   ( TCCR0 & ((1<<CS02) | (1<<CS01) | (1<<CS00)) )

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Clemens B. schrieb:
> Ps. Für den Fall, dass es irgendwann mal jemanden hilft. Ich hab es
> jetzt so gelöst und es läuft wie erwartet:
> #define TIMER0_LAEUFT   TCCR0 && 0x05
>
> Kann geschlossen werden.
> Danke nochmal.

 Was läuft wie erwartet ?

    PORTB  &= ~(1<<PB2);

 Diesen Befehl kannst du ruhig weglassen, absolut nutzlos.

 Somit ist deine LED praktisch immer an (oder aus) - je nachdem wie
 du das angeschlossen hast - wozu das Ganze ?

von Jim M. (turboj)


Lesenswert?

Marc V. schrieb:
> Was läuft wie erwartet ?
>
>     PORTB  &= ~(1<<PB2);
>
>  Diesen Befehl kannst du ruhig weglassen, absolut nutzlos.

Wieso? Der löscht doch zuverlässig das PB2 Bit. Und mit 'nem guten Oszi 
hätte man das sogar gesehen...

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Nebenfrage:

Clemens B. schrieb:
> #define TIMER0_LAEUFT     !(TIFR & (1<<TOV0))

Dieses Define wird bei jedem Aufruf im Programm erneut hergeleitet?
Hätte jetzt erwartet, daß der Wert Rechts beim Compilieren berechnet 
wird und danach Timer0_Laeuft eine Konstante ist - hätte nebenbei auch 
erklärt, warum nicht aus dem While raus gegangen wird.

Vll. sollte ich doch Mal in C rein schnuppern :/

MfG

von Falk B. (falk)


Lesenswert?

@ Patrick J. (ho-bit-hun-ter)

>> #define TIMER0_LAEUFT     !(TIFR & (1<<TOV0))

>Dieses Define wird bei jedem Aufruf im Programm erneut hergeleitet?

Ja logisch! Es ist eine Bitmanipulation eines Steuerregisters.

>Vll. sollte ich doch Mal in C rein schnuppern :/

Tu das.

von Clemens B. (Gast)


Lesenswert?

@Falk
Da hast du vollkommen recht, die Leerzeichen zwischen den äußersten 
Klammern hatte ich vorher nie gemacht, ansonsten mache ich das identisch 
;) schöner Tipp zur besseren Lesbarkeit.
So habe ich mein define aktuell, das CS01 Bit wird bei mir nie gesetzt.
1
#define TIMER0_LAEUFT   ( TCCR0 & ((1<<CS02) | (1<<CS00)) )

@Marc
So wie Jim schon erkannt hat. Es ist ein reiner Funktionstest. Und bei 
meinem Oszi geht's bis 2ns runter, mehr als ausreichend und den Puls zu 
sehen der entsteht..

@Patrick
#define ist eine sogenannte Präprozessor Direktive:
https://de.wikibooks.org/wiki/C-Programmierung:_Präprozessor

Erhöht halt die Lesbarkeit im Code(richtig angewandt). Dazu kommt das 
was Falk geschrieben hat.

von Clemens B. (Gast)


Lesenswert?

@Falk
Da hast du vollkommen recht, die Leerzeichen zwischen den äußersten 
Klammern hatte ich vorher nie gemacht, ansonsten mache ich das identisch 
;) schöner Tipp zur besseren Lesbarkeit.
So habe ich mein define aktuell, das CS01 Bit wird bei mir ja nie 
gesetzt.
1
#define TIMER0_LAEUFT   ( TCCR0 & ((1<<CS02) | (1<<CS00)) )

@Marc
So wie Jim schon erkannt hat. Es ist ein reiner Funktionstest. Und bei 
meinem Oszi geht's bis 2ns runter, mehr als ausreichend und den Puls zu 
sehen der entsteht..

@Patrick
#define ist eine sogenannte Präprozessor Direktive:
https://de.wikibooks.org/wiki/C-Programmierung:_Präprozessor

Erhöht halt die Lesbarkeit im Code(richtig angewandt). Dazu kommt das 
was Falk geschrieben hat.

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.