Abend,
ich bin gerade dabei ein kleines Programm für den Atmega zu schreiben,
aber verzweifle an den ganzen Enprellgeschichten :(
Hier mal mein Code, das Problem ist, dass er nach 2,5 Sekunden wieder
ausgelöst wird
Während eine ISR ausgeführt wird, speichert sich der Controller alle
weiteren Interrupts und führt sie nachher aus.
Durch das Prellen des Tasters wird INT0 mehrmals ausgelöst, kann aber
nur einmal alle 2,5s ausgeführt werden. Daher wird der Interrupt zweimal
nacheinander ausgelöst.
Abhilfe würde vermutlich bringen, in der ISR INT0 abzuschalten und am
Ende wieder zu aktivieren.
Und 2,5s Wartezeit in einer ISR macht man normalerweise auch nicht...
Ok, ein Versuch einer Erklärung, was passiert.
1. Der Interrupt wird ausgelöst. Das interne Flag für die
Interruptquelle wird zurückgesetzt.
2. Das Interruptflag im SREG wird gelöscht (dafür sorgt der Compiler).
3. Das bisschen Code vor dem delay wird abgearbeitet, dann beginnt das
Delay
4. Der Taster prellt, das Flag für den INT0 wird gesetzt, wegen
gesperrten Interrupts wird die ISR nicht nochmal aufgerufen.
5. Das Delay ist zuende nach 2,5 sec
6. Die Interrupts werden global wieder aktiviert (dafür sorgt der
Compiler) und die ISR verlassen
7. INT0 steht an und Interrupts sind aktiv -> ISR wird angesprungen
Klar warum das alles eine schlechte Idee ist, was du da vorhast?
Mal angenommen, der TE ist nicht des Wahnsinns, sondern es ist nur zur
Übung und nicht zur Verwendung in einem realen Programm.
Dann muss nach dem delay_ms() das Flag für INT0 rückgesetzt werden, denn
das wurde zwar beim Aufruf der Interrupt-Routine automatisch
rückgesetzt, danach aber gleich wieder durch Prellen gesetzt. Deshalb
kommt der Interrupt gleich wieder.
BeYourself schrieb:
> aber verzweifle an den ganzen Enprellgeschichten :(
Wobei denn konkret?
Hier z.B. mit einem Demoprogramm, welches die Entprellschritte im
1s-Takt anzeigt:
http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=1801> Hier mal mein Code, das Problem ist, dass er nach 2,5 Sekunden wieder> ausgelöst wird
Wirklich ein sehr schönes Beispiel, warum man doch besser eine
Entprellroutine nehmen sollte.
Peter
Abend nochmal,
hab mir mal den Link angeschaut und versucht, das ganze auf einem
Atmega8 zum laufen zu bringen. Anstatt dem Timer1 habe ich es so
versucht, dass der zweite Timer verwendet wird (Den 16bit-Timer verwende
ich schon in meinem Programm). Leider passiert nichts, wenn ich PB0 oder
PB1 auf GND oder VCC ziehe :(
Und mein Code oben wollte nicht in einem "richtigen" Programm verwenden,
sondern habe die Zeit erstmal einmal erhöht, um auszuschließen, dass die
Zeit zwischen zwei Interrupts nicht zu schnell vorbeigeht.
Hier mal mein Versuch, der auch noch eine Warnung ausspuckt:
../tasten_entrpellen.c:112: warning: overflow in implicit constant
conversion
Den Compiler habe ich mit "--std=c99" gestartet.
Werde mich dann morgen/heute nochmal dransetzen
MFG BeYourself
BeYourself schrieb:
> Hier mal mein Versuch, der auch noch eine Warnung ausspuckt:> ../tasten_entrpellen.c:112: warning: overflow in implicit constant> conversion
Ja, da hat er auch recht.
Es ist ja explizit als Demo gedacht, damit man an den LEDs die einzelnen
Phasen der Entprellung mitverfolgen kann.
In der Praxis is 1s Entprelltakt völliger Unsinn, da nimmt man etwa
2ms..50ms. Und dann paßt der Reloadwert auch in 8Bit rein.
Peter
Ahem, Chef... das hier funktioniert nicht:
TIMSK |= (0<<OCIE1A);
Es müsste lauten:
TIMSK &= ~(1<<OCIE1A);
Vielleicht ist das der ganze Fehler weil Du den Timer nicht
ausgeschaltet hast.
Soo, ich habe mich nochmal dran gesetzt und möchte euch meine Lösung
natürlich nicht vorenthalten ;-)
Erstmal hier meine Anpassung für Peter Danneggers Entprellmethode für
einen Atmega8 und den 2. Timer:
key_state=~KEY_PIN;// no action on keypress during reset
77
sei();
78
79
for(;;){// main loop
80
//display_debounce_key0();
81
82
if(get_key_press(1<<KEY0)){// LED on
83
LED_PORT=0xFF;
84
}
85
86
if(get_key_press(1<<KEY1)){// LED1 = toggle on keypress
87
LED_PORT^=1<<LED0;
88
LED_PORT^=1<<LED1;
89
LED_PORT^=1<<LED3;
90
LED_PORT^=1<<LED4;
91
}
92
}
93
}
@Igor:
Da hat du auch wieder recht, dass hat zwar glaubig mal funktioniert, ist
aber auch nicht gerade schön, habe ich jetzt mal geändert.
Um noch einmal auf die Warnung zu sprechen zu kommen: Ich habe mich dann
mal für die 2ms entschieden und es entsprechen angepasst:
1
TCCR2|=1<<CS22;// divide by 64
2
OCR2=6;
Bis jetzt funktioniert wieder alles und ich kann mal ein wenig
weiterschreiben. Als nächstes muss ich gucken, wie ich verschiedene
Variablen und Befehle vom PC oder einem anderen Controller (über RS/TWI)
in den Controller bekomme.
Ich sage noch einmal danke für eure Mithilfe
BeYourself