www.mikrocontroller.net

Forum: Compiler & IDEs Timer und Interrupts


Autor: Henrik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich weiß, dass es zu dem Thema schon etliche Beiträge gibt, aber 
irgendwie bin ich daraus, und aus dem Tutorial nicht schlau geworden.

Ich will mit einem 16bit Timer und Interrupts eine LED zum blinken 
bringen.
Alle halbe Sekunde an und aus.

Dafür hab ich dann nen 16bit Timer programmiert, dass der in dieser zeit 
einen overflow hat.

Daran hab ich dann ein ISR gekoppelt, also ISR(TIMER1_OVF_vect).
Drinnen dann ein Programm, dass wenn die Lampe an ist, sie ausschaltet, 
und wenn sie aus ist, wieder einschaltet.

Leider tut sich auf dem Mikrocontroller rein gar nichts.

Hier meinm Programm:

#include<avr/io.h>
#include<stdint.h>
#include<avr/interrupt.h>
#ifndef F_CPU
#define F_CPU 1000000UL
#endif
#include<util/delay.h>
#ifndef__OPTIMIZE__
#endif


volatile uint8_t timer;

ISR(TIMER1_OVF_vect)
{ if (timer==0)
     {DDRB = (1<<DDB0);
      timer = 1;
     }
  if (timer==1)
     {DDRB = (0<<DDB0);
      timer = 0;
      }
}

int main ()
{
TCCR1B |= (0<<CS12) | (1<<CS11) | (0<<CS10);
timer = 0;
sei();

while(1) {



}
cli();
return 0;
}


Wäre toll, wenn mir da jemand helfen könnte, das Programm so zu 
korrigieren, dass es danach dann funktioniert!

Gruß und Danke im Voraus
Henrik

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du musst den Interrupt auch lokal über das dazugehörige Enable-Bit 
freigeben.

BTW: Um welchen µC handelt es sich eigentlich?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Außerdem änderst du im Interrupt nicht den Output, sondern wechselst die 
Datenrichtung.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst wrote:
> Außerdem änderst du im Interrupt nicht den Output, sondern wechselst die
> Datenrichtung.
...was aber, zumindest wenn die LED High-Side angeschlossen ist, auch 
funktionieren dürfte...

Allerdings ist das im Allgemeinen tatsächlich Unsinn. Im 
AVR-GCC-Tutorial und auch im AVR-Tutorial sind solche Sachen 
eigentlich sehr gut beschrieben (v.a. der Unterschied der einzelnen 
Register der Ports usw.). Wenn Du (OP) da nicht schlau draus geworden 
bist, dann hast Du es nicht gründlich genug gelesen. Ein bisschen Geduld 
muss man schon mitbringen...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BTW: Dein Interrupt Handler lässt sich in einer einzigen Zeile 
unterbringen und die Variable timer ist ebenfalls überflüssig.
ISR(TIMER1_OVF_vect)
{ 
    DDRB ^= 1 << DDB0; //Aber wie oben gesagt: DDRx ist eigentlich nicht ganz korrekt...
}
Aber das nur ganz am Rande. Erst mal die grundlegenden Probleme in 
Angriff nehmen...

Die Timer haben übrigens i.d.R. Compare-Einheiten, mit denen sich 
bestimmte Pins ganz ohne Interrupt umschalten lassen. Ein Timer-Overflow 
ist für solche Sachen eh keine gute Wahl, zumal Du damit auf die Weise 
nie einen genauen 1Hz-Takt bekommst...

Autor: Melvin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ISR(TIMER1_OVF_vect)
{ if (timer==0)
     {DDRB = (1<<DDB0);
      timer = 1;
     }
  if (timer==1)
     {DDRB = (0<<DDB0);
      timer = 0;
      }
}
Du hast hier schon einen Logik-Fehler drin. Du testest in der ersten 
if-Anweisung, ob timer gleich Null ist. Dann wird eine Eins geschrieben 
und timer wird auf Eins gesetzt. In der nächsten if-Anweisung wird 
getestet, ob timer gleich Eins ist (ist true, weil du timer ja gerade 
auf Eins gesetzt hast!!) und es wird sofort wieder eine Null 
geschrieben.. Dann wird timer wieder auf Null gesetzt und das Spiel 
beginnt beim nächsten Mal von vorne.. es werden also immer beide 
Anweisungen ausgeführt und am Ende wird die Null geschrieben.

Ich glaube, man kann das lösen, indem du aus der zweiten if-Anweisung 
eine else-if-Anweisung machst, aber da ich nicht so C-sicher bin, weiß 
ich nicht, ob es diese Anweisung da gibt..
Zumindest hoffe ich, dass ihr versteht, was ich sagen wollte :-)

Gruß,
Melvin

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Melvin wrote:
> Ich glaube, man kann das lösen, indem du aus der zweiten if-Anweisung
> eine else-if-Anweisung machst, aber da ich nicht so C-sicher bin, weiß
> ich nicht, ob es diese Anweisung da gibt..
Gibt es (ohne Bindestrich allerdings...), aber an dieser Stelle wäre 
wenn überhaupt ein einfaches else angebracht. Schließlich schließen 
sich die Bedingungen gegenseitig aus...

Aber, wie schon oben angedeutet, ist die ganze if -Abfrage Käse...

Autor: John Go (johngo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interruptroutinen sind immer etwas schwieriger zu testen als normale 
Funktionen. Ich baue deren Programmcode daher meist zuerst in eine 
normale Funktion ein, um das eigentliche Funktionieren des Codes zu 
überprüfen. Den zeitlichen verzögerten Aufruf der Funktion simuliere ich 
mit einer delay Funktion, z.B.

while(1)
{
   ledBlinker();

   delay(10000);
}

Und erst wenn das funktioniert, mache ich eine IR draus oder ich rufe 
die Funktion einfach in der IR auf, und erst dann schalte ich Timer und 
Interrupts ein.

Und nochmals, wie auch schon @sternst sagte, das Outputregister heißt 
PORTB und nicht DDRB, denn DDRB ist das DataDirectionRegister, mit du 
nur einmal am Programmanfang (und nicht wiederholt in der IR) festlegts, 
ob du den Port als Ausgang oder Eingang verwenden wills.

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.