Hallo zusammen,
ich programmiere momentan eine kleine Steuerung und stehe vor einem
Problem wo ich nicht weiß wie ich es behebe.
Folgende Situation: Der Benutzer drückt einen Taster, wodurch ein
Interrupt ausgelöst wird.
1
intmain(void)
2
{
3
[...]
4
5
GICR|=(1<<INT2);
6
MCUCSR|=(1<<ISC2);
7
sei();
8
9
[...]
10
}
11
12
ISR(INT2_vect)
13
{
14
PORTA=PORTC=0x00;
15
PORTA=0b01000000;
16
17
_delay_ms(SHORT_DELAY);
18
19
GICR|=0b00010000;
20
21
while(PINB!=0b00000100)
22
{
23
24
}
25
26
PORTA=0xFF;
27
_delay_ms(SHORT_DELAY);
28
}
In der Schleife wird abgefragt, ob der Taster, der zuvor den Interrupt
ausgelöst hat nochmals betätigt wurde, wodurch die ISR-Funktion
verlassen werden soll.
Nach dem 2ten Betätigen des Tasters wird allerdings direkt wieder in die
ISR-Funktion gesprungen (also der Interrupt ausgelöst). Weiß jmd. wie
ich das verhindern kann?
Viele Grüße
sentinel schrieb:> Nach dem 2ten Betätigen des Tasters wird allerdings direkt wieder in die> ISR-Funktion gesprungen (also der Interrupt ausgelöst). Weiß jmd. wie> ich das verhindern kann?
man müsste das Flag löschen, was zum auslösen führt.
ABER:
so etwas macht man nicht. Das Konzept solltest du gleich vergessen. in
einer ISR macht man keine Warteschleifen rein. Auch die Abfrage des
Taster macht in der ISR meist wenig sinn, mache es in der Main und schon
ist das Problem weg.
sentinel schrieb:> while (PINB != 0b00000100)> {>> }
Was ist PINB? Zwar noch nie gehört, aber das hört sich eher nach einem
PIN an bzw. einem Bit, nicht einem ganzen Byte.
Zudem, wie schon geschrieben wurde, könnte man einen Merker setzen.
So nebenbei:
Eine ISR sollte kurz gehalten werden. Schleifen usw sollten wenn möglich
vermieden werden.
DomeG schrieb:> Interrupt am Anfang der ISR abschalten und am Ende wieder einschalten...
Unsinn. und bringt auch nichts. Interrupt sind immer in einer ISR
gesperrt (beim einem Atmel). Und nach den aktivieren würde er ein 2.mal
auslösen.
Grundsätzlich ist es sehr empfehlenswert, Taster zu entprellen. Such
mal hier nach "Entprellung". Peter Danegger wird sich freuen. :-)
Aber darüber hinaus, ist es problematisch, Taster überhaupt an
Interrupts zu betreiben. Und dann sind delays und while-Schleifen auch
ganz "pfui, bäh" in ISRs. ;-)
Aber das sind hier nicht Deine primären Probleme:
Während das Programm (die ISR), nach dem ersten Tastendruck auf den
zweiten wartet, wird - bewirkt eben durch dieses zweiten Tastendruck -
auch der Interrupt ein zweites Mal aktiv (resp. das entsprechende
Interrupt-Flag gesetzt).
Weil zu diesem Zeitpunkt noch die Abarbeitung der ISR aufgrund des
ersten Ereignisses erfolgt, wird die ISR nach Verlassen ein zweites
Mal aufgerufen.
Das willst Du natürlich nicht.
Das aber ergibt auch genau den Anhaltspunkt für die Lösung Deines
Problems.
Kurz: Wenn der Interrupt, ohne das man etwas besonderes schreiben muss,
sowieso zweimal ausgelöst wird, einmal beim ersten und einmal beim
zweiten Tastendruck, warum dann in der ISR für den ersten Tastendruck,
den zweiten vorsehen?
Anders ausgedrückt: Der Mechanismus, der jedesmal, also bei beiden
Tastendrücken eine gesonderte Reaktion hervorruft ist schon vorhanden.
Der Interrupt eben. Du brauchst nicht, mittels Software einen weiteren
Mechanismus erfinden, der unmittelbar mit dem ersten Tastendruck
verknüpft, auch den zweiten Tastendruck verarbeitet. Das täte der zweite
Interrupt (der hier unerwünscht auftritt) ohnehin.
OK. Was ist also die Lösung?
Du merkst Dir einfach im Interrupt, in einem Flag (denk' ich an volatile
in der Nacht ...), dass die Taste gedrückt wurde. In der Main-Funktion
wertest Du dieses Flag aus. Damit ist Deine ISR sehr kurz, was man, als
Daumenregel, vorziehen sollte.
Probier das mal. - Aber, wie schon ganz oben geschrieben, nur zu
Übungszwecken - Stand der Technik, oder sagen wir mal: "das übliche und
bewährte Muster" ist "Entprellung" und "ohne Interrupts für Tasten".
Peter II schrieb:> Unsinn. und bringt auch nichts. Interrupt sind immer in einer ISR> gesperrt (beim einem Atmel)
Da sollte jemand noch einmal über die Lehrbücher...
Bitflüsterer schrieb:> Während das Programm (die ISR), nach dem ersten Tastendruck auf den> zweiten wartet, wird - bewirkt eben durch dieses zweiten Tastendruck -> auch der Interrupt ein zweites Mal aktiv (resp. das entsprechende> Interrupt-Flag gesetzt).
True Story. Das wäre die korrektur zu Peter's aussage
sentinel schrieb:> Weiß jmd. wie> ich das verhindern kann?
Indem man so einen Scheiß nicht macht.
Delays gehören gar nicht in das Programm schon gar nicht in die ISR.
Und die Logik auf einen 2. Tastendruck zu warten gehört über eine
Statusvariable in die Main Schleife und nicht in die ISR.
Entprellung wurde schon gesagt.
Arbeite hier die Grundlagen unter AVR-Grundlagen und AVR durch:
http://www.mikrocontroller.net/articles/Hauptseite
Hi
Wieder einmal das Thema Ich habe einen Kontakt in einer ISR-abgefragt.
Warum? Eine ISR ist dazuda, Signale nicht zuverpassen. Wenn ndu dein
Programm mit Warteschleifen aufbaust, kann das gut passieren, das pollen
eben so manches übersieht. Darumm läßt mann einen Controller auch immer
frei laufen und wenn es etwas gibt, was eine Zeit erfordert, nutzt man
den Timer. Darum gibt es auch EVA,, Einlesen, Verarbeiten und Ausgeben.
Montakte können problemlos im Eingabeabschnitt gepollt werden. Da werden
sie dann auch entprellt und als gültige Signale abgelegt. Nun kann man
entscheiden, ob eine weitere Eventsteuerung mittels Jobflags aufgesetzt
werden soll, sprich Flankenauswertung. Z.B. Du hast ene VAriable namens
Ablage. In jedem Durchlauf prüfst du mit einer ExclusivOder, ob neue
Signaleingänge zu den abgelegten unterschiedlich sind Mit einer 1 ist
ein Unterschied detektiert. Nun nimmst du diese 1 und prüfst, ob der
neue Wert auf 1 steht (AND), dann hast du die Flanke von 0 nach 1. Oder
du prüfst, ob der alte Wert 1 war, dann hast du die Flanke von 1 nach 0.
Nach dieser Prüfung kopierst du den neuen Wert n die Ablage, um im
nächsten Zyklus wieder auf ein Ereignis zu prüfen. Die Ergebnisbits sind
dann die Auslöser deiner Aktion. Nach der Bearbeitung werden sie
gelöscht. Erst, wenn wieder ein Ereignis auftritt, wird die Bearbeitung
erneut durchgeführt. Die Interrupteingänge sind viel zu wertvoll für
Kontaktbehaftete Eingänge. Klar, bei einem kleinen Impuls, so bei 5 bis
10 msek. Signaldauer, da sieht es dann wieder anders aus. Aber da
erfasst du auch nur das Signal und setzt ein Ereignisbit, um dieses dann
in der Main abzuarbeiten. Daher gebe ich keinen Rat, wie du die ISR
verbiegen musst, damit dein Vorhaben Erfolg hat. Denk mal drüber nach.
Gruß oldmax