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.
Tja, wie wärs mit ein paar Programmschnipseln? Hellseher gibts nicht mehr, zumindest nicht hier.
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
"Was kann ich dagegen machen?" Taster generell im Timerinterrupt abfragen und vor allen Dingen entprellen (z.B. siehe Codesammlung "Tasten entprellen - Bulletproof"). Peter
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
@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
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)
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
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
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
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.