HI
Mein Interrupt 0 ist durch ein Taster gesteuert.
Ich möchte die variable "press" inkrementieren, wenn der Taster nur
kurz gedrückt ist.
Wenn der Taster jedoch 2sec lang gedrückt wurde, soll auf dem Port C
(LED's) 0xAA ausgegeben werden!
Nun mein Problem:
Ich simuliere das Programm im AVR Studio und die while Schlaufe
funktioniert nur, wenn ich darin kein Delay aufrufe!
Wieso ist das so?
THANKS
SIGNAL(SIG_INTERRUPT0)
{
unsigned char s;
_delay_loop_2(60000); //entprellen
_delay_loop_2(60000);
_delay_loop_2(20000);
TIMSK = (0<<TOIE0); //Timer0 abschalten
do
{
_delay_loop_2(10000); // 10ms Delay
int_flag = bit_is_set(PIND,3);
PORTC = int_flag;
s++;
}
while ( (int_flag >= 1) && (s <= 200) );
if (s >= 200)
{
PORTC = 0xAA;
}
else
{
press++;
address = press * 1000;
if (press >= 15) press = 0;
PORTC = ~press;
TIMSK = (0<<TOIE0);
}
GIFR = (1<<INTF0);
}
Interruptroutinen macht man so kurz wie möglich. Delays verbieten
sich damit automatisch.
Benutze einen Timer dafür, den Du aus dem Interrupt nur anschiebst
bzw. Software-Timer.
Also die ersten Delay's (140ms) sind Warteroutinen, damit der Taster
entprellt ist...
Danach wird im "normal" - Betrieb des Tasters nur noch ein 10ms Delay
dazu addiert! also 150ms! (ansonsten prellt mein Taster)
Wenn dann aber der Taster 2sec lange gedrückt wird, soll mein uC in den
Sleep Modus (OFF) versetzt werden!
Sollte man das wirklich nicht mit Delays machen?
(Ich glaube es liegt daran, dass ich eine Variable (s) in der ISR
definiert habe!
Ja, man sollte das wirklich nicht mit delays machen.
Laß einen Timer z. B. alle 10 ms ticken, dort kannst Du das
dranhängen. Damit lassen sich dann beliebige Vielfache von 10 ms als
Verzögerungen realisieren, auch die Entprellung selbst.
Ich habe sowas auch schon gemacht, allerdings ist das Projekt nie
wirklich fertig geworden (daher mag ich es nicht veröffentlichen).
Aber genau diese Aufgabe, unterschiedliche Funktionalität je nachdem,
ob Taster kurz oder lange gedrückt, habe ich damit realisiert.
Genau so.
Also Timer-IRQ kurz genug. Dann Taste bei jedem IRQ prüfen, bei
gedrückter Taste Flag setzen. Bei jedem folgenden IRQ Zähler
hochzählen.
Falls Taste nicht mehr gedrückt, wenn der Zähler kleiner als die
Prellzeit ist, Flag löschen.
Ansonsten weiterzählen und weiterprüfen. Wenn dann die Taste wieder
losgelassen wird, Zähler überprüfen und wenn kleiner 2s dann Flag für
einfachen Tastendruck setzen oder aber für 2s-Tastendruck.
Eins nur noch: es empfiehlt sich, einen externen Interrupt innerhalb
der Interruptroutine als allererstes mal abzuschalten, ansonsten
bekommst Du aufgrund des Tastenprellens X Stück davon ausgeliefert.
Erst nach Ablauf der Entprellzeit schaltest Du ihn dann wieder zu.
Ggf. kann man ihn dann auch ,negiert' zuschalten und das Ganze
herumdrehen, dann bekommst Du ein Ereignis geliefert, wenn der Nutzer
die Taste wieder losläßt (und mußt danach natürlich die Negation
wieder negieren ;-).
Aber das Prinzip ist richtig, in der Interruptroutine macht man nur
das, was wirklich zeitkritisch ist, für den Rest setzt man ein Flag
und macht es später in der Hauptschleife (`volatile' nicht
vergessen!).
Erstmal vielen vielen Dank für die vielen Ideen.
So wie ich das jetzt verstehe, muss ich in der Interruptroutine
folgendes machen:
1. Interrupt ausschalten
2. Taster_flag = 1
3. entprellzeit abwarten (delay) -> wie lange ist das üblicherweise?
4. Interrupt wieder einschalten
In der Timer routine mache ich folgendes:
1. zähler inkrementieren
2. Taster - Pin einlesen
3. Timer zurückstellen
Im Hauptprogramm
Endlosschlaufe, die verlassen wird, wenn der Taster losgelassen wird,
oder der Zähler auf dem Endwert ist...
Funktioniert das so? -> Vorallem das Entprellen würde mich wunder
nehmen, denn jetzt habe ich ja wieder ein Delay in der ISR.
Ich würde den externen IRQ gar nicht nutzen. Port einfach per IO
abfragen. In der Timer-IRQ, und dann jeden Durchlauf abfragen.
Und in der Hauptschleife den MC in den idle-Mode schicken, wird durch
die timer-IRQs jeweils aufgeweckt und falls dann ein Flag gesetzt
wurde, dann wird die entsprechende Routine aufgerufen.
Externen Interrupt kann man schon nehmen, aber eben nicht dort warten.
Ungefähr so:
Timer-Interrupt tickt alle 10 ms und sieht nach, was alles an
Aufträgen da ist. Diese werden abgearbeitet. (Bei mir in einer
verketteten Liste, aber das ist ziemlich aufwendig und braucht
außerdem malloc().)
Externer Interrupt läuft ein, klemmt sich erstmal ab, und gibt einen
Auftrag für den Timerinterrupt nach 20 ms (was effektiv heißt,
irgendwas zwischen 10 und 20 ms) auf.
Der Timer-Auftrag prüft, ob die Taste wirklich noch gedrückt ist.
Wenn nicht -> alles Spaß, zurück über "Los!". Wenn ja: registrieren
des negierten Interrupts (Loslassen der Taste), neuer Zeitgeberauftrag
um festzustellen, ob die Taste lange gedrückt worden ist.
Je nachdem, ob nun zuerst das Ereignis "Taste losgelassen" oder
"langer Zeitgeber" eintrifft, werden die weiteren Aktionen ausgelöst.
> also das mit dem negierten Interrupt pack ich nicht ganz?
Wie ich oben schon mal schrob: Du registrierst den Interrupt auf der
jeweils entgegengesetzten Flanke. Wenn also anfangs die H->L Flanke
den Interrupt ausgelöst hat (Taster gegen Masse), dann regisrierst Du
danach (nach Ablauf der Entprellzeit) einen, der auf die L->H Flanke
reagiert, damit bekommst Du ein Ereignis gemeldet, wenn der Taster
wieder losgelassen wird.
@Jörg Wunsch:
Ich verfolge diesen Thread sehr aufmerksam, da es für mich einiges zu
lernen gibt. In einen obigen Beitrag hast Du geschrieben: 'volatile
nicht vergessen'. Kannst Du das bitte genauer erklären?
Besten Dank Tipper
Ich staune immer wieder, wie aufwendig und fehleranfällig Leute eine
Tastenentprellung und Abfrage hinkriegen, nur weil sie unbedingt den
völlig ungeeigneten externen Interrupt verwenden wollen.
Am sichersten und einfachsten ist und bleibt doch der Timerinterrupt:
http://www.mikrocontroller.net/forum/read-4-20549.html
Peter
Sehe ich genauso wie Peter.
Wer seine Tasten im Timer-IR abfragt (alle 10 - 20ms), wird die
Probleme mit Tastenprellen bald nicht mehr verstehen können.
Tasten an IR-Eingängen machen für mich dann Sinn, wenn mit diesen
Tasten die CPU aus dem Sleep geweckt werden soll.
Stefan