Forum: Mikrocontroller und Digitale Elektronik INT0 Endlosschleife


von dag (Gast)


Lesenswert?

Guten Tag,
mein Problem ist, dass ich den externen Interrupt Int0 mit einem Taster
beschaltet habe und bei längerem gedrückthalten des Tasters, dieser
nicht aus seiner Routine wieder rausspringt.

Derzeit bin ich soweit, dass bei kurzem betätigen des Tasters der
Interrupt sauber abgearbeitet wird.
Wenn ich den Taster jedoch länger (1-2 Sekunden) gedrückt halte,
kehrt er nicht mehr aus der Routine zurück.

Ich programmiere in C.
Was kann ich dagegen machen?

Danke für eure Hilfe.

von crazy horse (Gast)


Lesenswert?

Tja, wie wärs mit ein paar Programmschnipseln? Hellseher gibts nicht
mehr, zumindest nicht hier.

von dag (Gast)


Lesenswert?

OK, hier die Interruptroutine

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
   Mittelwert();          //Mittelwertsberechnung
   zero=(int) mw;         //Übergabe des Mittelwertes (mw) an zero
   return;
}

mw und zero sind globale int variablen

Danke

von crazy horse (Gast)


Lesenswert?

wofür soll das return gut sein?

von Peter D. (peda)


Lesenswert?

"Was kann ich dagegen machen?"


Taster generell im Timerinterrupt abfragen und vor allen Dingen
entprellen (z.B. siehe Codesammlung "Tasten entprellen -
Bulletproof").



Peter

von dag (Gast)


Lesenswert?

Hallo,
@crazy horse
ohne dem return; funktioniert es nicht einmal bei
kurzem betätigem des Tasters.
Soll heisen, er bleibt in der Routine (Endlosschleife)
Warum weis ich nicht.

@peter
ich hab den Taster am INT0 angeschlossen und wollte ihn nun auch
nutzen.
Das mit dem Tasten entprellen ist eine gute Idee. Ich blicke aber nicht
ganz durch bei deinem angegebenem Link.
Ich programmiere in C mit CodeVisionAVR.

Ist es richtig, dass prinzipiell nur nachgesehen werden muß, ob die
Taste länger gedrückt ist?

Danke

von Peter D. (peda)


Lesenswert?

@Dag,

Das Entprellen funktioniert so, daß 4 mal hintereinander der gleiche
Tastenzustand anliegen muß, erst dann wird er auch übernommen. Die
Entprellzeit ist somit 4* Interruptaufrufzeit.

Danach wird dann noch der Wechsel von Losgelassen nach Gedrückt erkannt
und das entsprechende Bit gesetzt. Dauerdrücken schadet also nichts.


Ein "return;" am Ende darf keinerlei Einfluß haben, sonst ist da was
oberfaul am Compiler.
Es sei denn, Du hast ihn mit irgendwelchen "#define"-Schweinereien
verwirrt.


Wenn man in einem Interrupt Unterfunktionen aufruft, sollte man auch
ganz genau wissen, was man da tut. Sonst ist das nämlich nur
Rechenzeitverschwendung.


Peter

von dag (Gast)


Lesenswert?

Danke

das mit dem return war falsch von mir.
habe es schon wieder entfernt.

Habe mir jetzt mal ein paar werte über die uart ausgelesen.
Wie es aussieht, arbeitet er den Interrupt ordentlich ab.
Kehrt aber nicht wieder ins Hauptprogramm zurück.

Anmerkung: der Interrupt wird bei mir, solange ich den taster gedrückt
halte, ständig abgearbeitet (wiederholung)

von dag (Gast)


Lesenswert?

Nochmal
wie mache ich ein solches entprellen in C.

Wenn ich das richtig verstanden habe, muß also vor der
Interruptroutine schon geschaut werden, wie lange die taste gedrückt
ist.
interrupt [EXT_INT0] void ext_int0_isr(void)
{
 char d;

 d=d+1;
 if (d>5)
 {
    Mittelwert();
    zero=(int) mw;
    d=0;
 }
}
eine solche Ergänzung reicht wohl nicht, oder?

Danke

von Khani (Gast)


Lesenswert?

Frage : Sperrt der oben genannte C-Schnipsel den Interrupt 0 beim
Eintreten in die Interrupt-Service-Routine (ISR). Wenn nicht (passierte
mir schon mal im Assmebler), dann wird die ISR wieder von einem
Interrupt unterbrochen, welcher dann wieder die ISR aufruft und da
passiert dann wieder das selbe. Der Effekt war am Ende ein
Stack-Overflow und die Rücksprungaddresse ins Hauptprogramm war
überschrieben. Damit kreiste der Prozessor um den Rücksprung in immer
wieder eine ISR. (in Assembler war das mal der Befehl "cli" oder ?)

Grüße, Daniel

von dag (Gast)


Lesenswert?

Hallo,
ist eine gute Anregung. Daran dachte ich auch schon, weis aber nicht,
ob die ISR gesperrt wird.
Wenn nicht, würde das nämlich meine Anzeigen bestätigen, dass bei
längerem drücken der Stack irgendwan überläuft.

Wenn mir jemand sagen könnte, wie man das in C sperrt, würde es mir
sicherlich weiterhelfen.

Danke

von Khani (Gast)


Lesenswert?

Hi nochmal

zur Not mit einem Assemblereinwurf á la

asm{
cli
}
ISR- Getue
asm{
sei
}

Ich weiß allerdings nicht, wie man genau Assembler in die C-Funktion
einbindet - schau mal in der Hilfe nach "asm" oder so ähnlich. Aber
Obacht : 'cli' sperrt ALLE Interupts. (mit 'sei' enabelt man sie
wieder). Korrigiert mich bitte, wenn ich was falsches sage, meine
Erfahrungen auf diesem Gebiet sind, dass es so funktioniert - kann aber
auch Zufall sein.
(Semaphoren oder Zähler, die solche simulieren scheinen hie nicht
angemessen zu sein.)

Grüße, Daniel

von crazy horse (Gast)


Lesenswert?

macht man auch in C am besten mit inline-Assemblerbefehl.
Allerdings ist es nicht nötig, da beim Eintritt in eine ISR weitere
Ints ersteinmal gesperrt sind, es sei denn, man gibts sie extra mit
"sei" frei. Normalerweise wird aber eine ISR nicht von einer anderen
unterbrochen.  Während der ISR-Laufzeit werden allerdings andere Ints
in den entsprechenden flags gespeichert, nach reti und einem Befehl im
unterbrochenen Programmteil wird dann der nächste anhängige Int
ausgeführt, stehen mehrere an, wird entsprechend der Prioritäten
abgearbeitet.
Gibt man in einer ISR das globale I-flag frei, muss man höllisch
aufpassen, damit es zu keinem Kuddel-Muddel kommt, der stack ist
schneller voll, als man denkt, da viele Compiler viel zu viel auf dem
Stack sichern, so richtig mit der Sense drüber, ob die Register nun
gebraucht werden oder nicht.
Kostet nebenbei auch Laufzeit.
Bei zeitkritischen Sachen nehm ich mir dann gern das Listing zu Hand
und sichere nur das, was beim gegenwärtigen Programm auch gesichert
werden muss.

#pragma savereg- //automatische Sicherung aus
#asm
 push r30 //sichern r30
 in r30, sreg
 push r30  //sichern sreg
 push r31  //sichern r31
#endasm
das eigentlich C-ISR-Programm, welches r30 und r31 benutzt
#asm
 pop r31
 pop r30
 out sreg, r30
 pop r30
#endasm
#pragma savereg+ // automatische Sicherung wieder an

von dag (Gast)


Lesenswert?

Danke für eure Tips.

Programm läuft jetzt soweit ganz gut.
Habe aber auch das Auslösen des Int0 geändert,
von Low Level auf Falling Edge .
Damit wird der Interrupt nur 1 mal ausgelöst und abgearbeitet.
Daher hat man nicht ganz so viele Probleme mit dem Stack.

Die Berechnung des Mittelwertes habe ich in die Hauptschleife verlegt,
so dass der Int0 nichts weiter macht als eine variable zu setzen.

Ich möchte mich nochmal bei allen bedanken, die mir mit Rat und Tat zur
Seite standen.

Bye

von Sebastian Schildt (Gast)


Lesenswert?

Das macht ja auch Sinn: "Falling Edge" heißt fallende Flanke, also der
INT passiert genau DANN wenn das Signal am Eingang vom High Pegel (z.B.
+5V) auf den LowPegel (0V) geht.

Das passiert dann je anch Verdrahtung, entweder wenn du den Taster
runterdrückst, oder wenn du ihn wieder loslässt.

Wenn man aber bei "LowLevel" auslöst, dann wird vermutlich IMMER
(ganz Mist sien, habe nicht nachgelesen) wenn ein Low Level anliegt der
Interrupt ausgelöst. Wenn dann die ISR die Interrupts nicht sperrt,
birhct also alles zusammen, weil der MC zu schnell ist und die ISR viel
zu oft aufruft:
Oh ein Low Pegel->ISR||oh immer noch LOW->ISR||cool Low -> ISR

=> Stack Overflow.

Entprellen kann nat. trtzdem noch nötig sein glaube ich, denn wenn der
Taster "Prellt" kann er natprlich auch öfter ne "Falling Edge" am
Pin auslösen.

Ich denke so oder so ähnlich kann man sich das erklären. Könnte baer
auch falsch sein - Soo viel Plan habe ich noch nicht :-)

MfG

Sebastian

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
Noch kein Account? Hier anmelden.