Hallo, ich möchte mit einem Taster 3 LED's ein- und ausschalten. Ich nutze den Interrupt 0 an PORTD.2. Ich habe versucht den Taster zu entprellen! Leider funktioniert es nicht richtig. Die LED's gehen oft beim loslassen des Taster aus oder andersrum oder reagieren gar nicht. Könnt ihr mir helfen? Vielen Dank schonmal... Stefan //---------------------------------------------------------------------- // Titel : externer Interrupt 0 & Entprellung (Ein- und Ausschalter) //---------------------------------------------------------------------- // Funktion : 3 LED's werden über Taster ein- und ausgeschalten // Schaltung : Taster 1 an PORTD.2, LED's an PORTB.0-2 //---------------------------------------------------------------------- // Prozessor : ATmega8, 3.6864 MHz // Sprache : C // Datum : 07.06.2008 // Version : 1.0 // Autor : Stefan //---------------------------------------------------------------------- #define F_CPU 3686400 #include <avr\io.h> #include <inttypes.h> #include <avr\interrupt.h> #include <util/delay.h> //---------------------------------------------------------------------- volatile unsigned char buffer; // globale Variable volatile unsigned char toggle; // globale Variable //---------------------------------------------------------------------- SIGNAL(SIG_INTERRUPT0){ if(toggle == 0b00000001){ _delay_ms(50); // entprellen _delay_ms(50); buffer = 0b00000111; toggle = 0b00000000; } else if(toggle == 0b00000000){ _delay_ms(50); // entprellen _delay_ms(50); buffer = 0b00000000; toggle = 0b00000001; } } //====================================================================== main(){ DDRB = 0xff; // PortB = Output PORTB = 0xff; // alle LEDs ON DDRD = 0x00; // PortD = Input PORTD = 0b00000100; // pull-up GICR = 0x40; // enable external int0 Bit 6 MCUCR = 0x02; // falling egde: int0 Bit 1 sei(); // enable interrupts toggle = 0b00000001; do { PORTB = buffer; } while (true); // Mainloop } //======================================================================
Auch wenn du in deiner ISR Wartezeiten drinn hast, ändert das nichts an der Tatsache, dass der µC mit jedem Prellen eine erneute Interruptanforderung registriert. Wenn das Programm zu diesem Zeitpunkt in der ISR steckt, dann wird diese Anforderung nicht einfach ignoriert sondern registriert und abgearbeitet, wenn der Prozessor aus der ISR wieder herauskommt. Warum verwendest du nicht einfach diese Tasten-Einlese-und-Entprell- ISR zusammen mit einerm Systemtimer? http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29 Die ist 100% zuverlässig.
Hmmm... Ich versteh das Programm von deinem Link nicht so ganz. Ich bin noch ein absoluter Anfänger. Kann man mein Programm nicht einfach ein bissel abändern, so das es funktioniert??
Stefan Z. wrote: > SIGNAL(SIG_INTERRUPT0){ ... > _delay_ms(50); // entprellen Grrr, brauchbare Interrupthandler sehen anders aus. Da rotiert ja Konrad Zuse mit 10.000U/min im Grabe. Solch monströse Rechenzeitvergeudung hätte er nicht mal auf seinem Relais-Rechner zugelassen. Peter
bzw. kann ich nicht irgendwie einstellen, das Interrupts während der Abarbeitung eines interrupts unterbunden werden?
Stefan Z. wrote: > Hmmm... Ich versteh das Programm von deinem Link nicht so ganz. Ich bin > noch ein absoluter Anfänger. Kann man mein Programm nicht einfach ein > bissel abändern, so das es funktioniert?? Nein, ein bissel abändern hilft nicht, man muß es richtig machen. Ein bissel falsch ist immer noch falsch. Ich sehe ein, daß man als Anfänger Probleme hat, die Funktionsweise eines Interrupts zu verstehen. Lies Dir im Datenblatt durch, welche Bedingungen erfüllt sein müssen, damit ein Interrupthandler ausgeführt wird. Diese Bedingungen müssen nicht gleichzeitig erfüllt werden. Insbesondere das Interrupt Pending Flag kann schon viel früher gesetzt werden (z.B. während gerade ein Interrupthandler in Arbeit ist). Peter
Tasten nimmt man auf den Timer. Alle 10ms werden die Tasten gelsesen und erst wenn zwei mal hintereinander derselbe Wert da ist wird er akzeptiert.
Hallo, Nie lange im Interrupt verbleiben! Ein Interrupt hat so kurz wie moeglich und so kurz wie noetig zu sein! Wenn du es aber wirklich so machen moechtestm, musst du am Ende der Routine das Flag fuer die ISR wieder loeschen. Das Flag fuer die ISR(Interrupt 0) findest du im Interrupt Flag register. Am Ende des Datenblatts ist eine grosse Tabelle. Da hat Peter vollkommen Recht, so eine Routine im Interrupt ist absolut nosens. Da ein Interrupt hoehere Prioritaet als der Code der Hauptschleife des Programmes wird das Programm unterbrochen und der Interrupt abgearbeitet. Wenn du da jetzt nur mit einem Delay eine Zeit abwartest (was nichts weiter macht als zaehlen bis ein Wert welcher der Delayzeit entspricht, erreicht ist) wird dein Hauptprogramm nicht fortgesetzt. Was das sich dann spaeter in deinem Programm bemerkbar macht, das reaktionen ausgeloest durch mehrere Taster, sehr spaet erfolgen. Bei einem wirst du das noch nicht so mitbekommen, aber bald :), wenn du dann die Schaltung erweiterst. Mit freundlichen Gruessen Daniel
Hi, danke für die die Beiträge. Was ich eigentlich vorhabe: Ich habe 2 Taster zur Verfügung. Der Eine soll mein Programm Starten(weitermachen)/Stoppen(anhalten) der zweite Taster soll das Programm reseten. Zum Reseten nutz ich einfach den Reset Taster meines Eval Boards. Dieses Programm funkioniert sehr gut--> /*********************************************************************** */ /* */ /* Debouncing 8 Keys */ /* Sampling 4 Times */ /* With Repeat Function */ /* */ /* Author: Peter Dannegger */ /* danni@specs.de */ /* */ /*********************************************************************** */ http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29 Aber ich verstehe nicht so ganz wie die Repeat Funktion funktioniert bzw. wie ich sie aus dem Code entferne. (bzw. ich bin grade dabei) Kann ich mit dem Code während des gesammten Programms einen Interrupt auslösen? Hab ich das richtig verstanden, dass der Timer läuft und ein Port PIN während des gesammten Hauptprogramms abgefragt wird, und dann die Funktion (im Beispiel LED on/off) auslöst?
Ich kenne zwar nur Peters ASM-Version der Entprellung, die C-Version dürfte aber (fast) ganauso arbeiten... Die Entprellung funktioniert etwa so: Im Timer-Interrupt (alle etwa 10ms) wird - der Port (das Register PINx) eingelesen, - invertiert, da die Taster L-aktiv sind, - Änderung erkannt und Prellzähler bedient, - wenn Prellzähler überläuft (4 Runden lang neuer Zustand gegenüber vorher), dann wird * der neue Zustand übernommen, * ein Bit in einem Merker gesetzt (Taste wurde betätigt), * der Repeat-Zähler heruntergezählt... Bei Ablauf des Repeat-Zählers wird dieser auf den Startwert (der kann unterschiedlich für erste Wiederholung und folgende Wiederholungen sein) gesetzt und eine weitere Aktion ausgelöst, also entweder durch Setzen des Bits im Tastendruckmerker ein erneuter Tastendruck simuliert oder ein anderer Merker für andere Zwecke gesetzt. Die Mainloop fragt nun die Tastendruck-Merker ab und verzweigt bei gesetztem Merker zu der Routine, die die gewünschte Aktion ausführt. Diese Routine löscht den Merker (das Bit) und führt die Aktion aus. In ASM heißen Peters Tastendruck-Merker "key_press" (eine Taste wurde gedrückt, jedes Bit repräsentiert eine andere Taste) und "key_state" (entprellter Zustand zum Vergleich mit den Neuwerten). In C dürften die Variablen ähnlich heißen. ...
Ich mach das jeweils sogar noch einfacher. Im timerinterrupt eine Boolean setzen : Timercame=1 Im schnellen Hauptprogramm abfragen ob der timer gekommen ist : if (timercam==1) { .. entprell .. .. timercame=0; }
3358 wrote: > Ich mach das jeweils sogar noch einfacher. > > Im timerinterrupt eine Boolean setzen : Timercame=1 > > Im schnellen Hauptprogramm abfragen ob der timer gekommen ist : > > if (timercam==1) { > .. entprell .. > .. > timercame=0; } Das wird nie funktionieren... (da Timercame und Timercam zwei völlig unterschiedliche Variablen sind...) Aber Spaß beiseite, wenn ich die Entprellvariablen im RAM füren muss und noch weitere Interrupts aktiv sind, dann läuft die Entprellung auch bei mir in der Mainloop, synchronisiert über einen Merker von einem Timer-Interrupt. ...
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.