Hallo, folgendes Programm sollte eigentlich eine LED mit einem Sekundentakt ein bzw. auschalten. Der Timer wurde so gesetzt, dass er mit einem 1024 des Systemtakt aufwärtszählt. Leider bleibt die LED immer an. An was kann das liegen ? Ich habe auch schon die Vergleichswerte in der Interruptroutine erhöht - führt jedoch auch zu keinem sichtbaren Unterschied. Bin für jede Hilfe dankbar. #include <avr/io.h> #include <avr/interrupt.h> #include <avr\signal.h> volatile unsigned short ledon = 1; void main(void) { outp (0x02,DDRB); outp ((1<<CS02) | (0<<CS01) | (1<<CS00), TCCR0); sbi(TIMSK,TOIE0);/* enable TIMER0 OVI */ //timer_enable_int(1 << TOIE0); sei (); while (1) {} } SIGNAL(SIG_OVERFLOW0) { if (ledon < 4000) { ledon ++; cbi(PORTB,1); // -> LED ON } else { ledon ++; sbi(PORTB,1); // -> LED OFF if (ledon > 8000) ledon = 0; } } :::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Beobachtungen: -> Interrupt wird genau einmal aufgerufen, jedoch anschliessend nicht mehr ( meiner Meinung nach ) -> die Interruptroutine werden häufiger als jede 1/4000 sekunde aufgerufen ( jedoch auch bei Anpassung der Vergleichswerte keine sichtbare Veränderung des Programms )
> Interrupt wird genau einmal aufgerufen, jedoch anschliessend nicht > mehr ( meiner Meinung nach ) Hast Du auch wirklich lange genug gewartet? ;-) Du schreibst nicht, welchen Takt Du benutzt, gehen wir mal von 4 MHz aus. $ echo 'scale=5; (4000*256*1024)/4000000' | bc 262.14400 Das wäre die halbe Periode Deiner LED, als die Einschaltdauer, mehr als 4 Minuten... Generelle Bemerkungen: > #include <avr\signal.h> Bitte Vorwärtsschrägstriche benutzen, sonst geht's nur unter DOS^H^H^HWindows. > volatile unsigned short ledon = 1; Das `volatile' wäre hier gar nicht notwendig, da die Variable ja nur innerhalb der ISR benutzt wird. > void main(void) Das widerspricht dem C-Standard und wäre nur mit der Compiler-Option -ffreestanding erlaubt. Die wiederum verhindert andere Optimierungen auf Bibliotheksebene, die manchmal sinnvoll sein können. int main(void) ist besser. > outp (0x02,DDRB); inp() und outp() bitte nicht mehr benutzen. > if (ledon < 4000) { > ledon ++; Ziemlich umständlich geschrieben meiner Meinung nach. Hier meine Version (ungetestet). Zeit ist nicht exakt eine Sekunde, aber das hängt am Ende von Deinem CPU-Takt ab. #include <inttypes.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #define LEDPIN PB2 #define CPUCLK 4000000UL static void ioinit(void) { DDRB = _BV(LEDPIN); /* * LED am Anfang einschalten, falls Ausgang H-aktiv ist: */ /* PORTB = _BV(LEDPIN); */ TCCR0 = _BV(CS02) | _BV(CS00); /* CPUCLK / 1024 */ TIMSK = _BV(TOIE0); sei(); } SIGNAL(SIG_OVERFLOW0) { static uint8_t cnt; if (++cnt == (uint8_t)(CPUCLK / (1024UL * 256))) { cnt = 0; PORTB ^= _BV(LEDPIN); } } int main(void) { ioinit(); for (;;) ; /* NOTREACHED */ return 0; } Mögliche Verfeinerung: In dieser einfachen Applikation kann es sich lohnen, statt einer Speicherstelle ein Register für cnt zu benutzen. Die Deklaration von cnt innerhalb der Interruptroutine ersetzen durch register uint8_t cnt asm("r2") = 0; auf globalem Niveau.
Hallo Jörg, dein Programm funktioniert prächtig. Lediglich PB2 muss zu PB1 geändert werden. Was die Wartezeit betrifft hattest du Recht - ich habe die Werte in meinem Programm angepasst und siehe da es funktioniert doch :). Ich habe vergessen dass der Timer auf 256 zählt. Ziemlich bescheuert eigentlich, aber ich habe im Moment noch keine serielle Schnittstelle, deshalb fällt das Debuggen ziemlich schwer. Ich habe mir beinahe gedacht, dass eine Bemerkung zum Aufbau des Quellcodes kommt. Gewöhnlicherweise programmiere ich nicht so umständlich. Wieso steht jeweils _bv vor der Benutzung einiger Konstanten ? vielen Dank für deine Hilfe !!! mfG Harald
> Lediglich PB2 muss zu PB1 geändert werden. Ja sorry, das hatte ich vermasselt, nicht richtig geguckt. > Wieso steht jeweils _bv vor der Benutzung einiger Konstanten (Es ist übrigens _BV() -- C unterscheidet zwischen Groß- und Kleinschreibung!) Wofür der Name BV steht, weiß keiner mehr so richtig. ;-) ``bit value'' oder sowas. Es setzt die als Paramter übergebenen Bitnummer in einen Integer-Wert um, den man einem Register zuweisen kann, als Bitmaske benutzen o. ä. Das ist nichts anderes als das Herumschieben eines 1-bits: #define _BV(x) (1 << (x)) es sieht nur (meiner Meinung nach) ein bißchen übersichtlicher aus im Quellcode. Wenn Du portabel zu anderen C-Compilern bleiben willst, darfst Du es aber nicht benutzen, da es diesen Makro dort nicht gibt.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.