Hallo Leute,
ich möchte ein kleines Programm in C schreiben , das eine LED bei
Tastendruck mittels extern Interrupts toggelt.
Das Problem ist , ich weiß nicht , wie ich Tastenentprellung in Diesem
Fall realisieren soll (Ich habe noch nie eine Tastenentprellung mit
extern Interrupts un Timer realisier).
Ich benutze das STK500 mit dem Atmega16 .
Kann jemand mir bitte erklären , wie man das realisiert ?
Gruß
Ismael
> Kann jemand mir bitte erklären , wie man das realisiert ?
Eigentlich: Gar nicht, man verwendet keinen (flankengetriggerten)
Interrupt zur Tastererkennung, sondern maximal per Timer-Interrupt
zeitgesteuerte schnelle Abfrage (polling).
Aber wenn man unbedingt gegen alle Ratschläge verstossen will
(klassischer fall: Der Tastendruck soll den uC aus sleep aufwecken),
kann man das Programm so schreiben, daß es auf den Interrupt durch die
Taste wartet, und wenn der Interruopt kam erst mal mindestens die
Prellzeit (5msec) nach loslassen der Taste abwartet, bevor es diese
Interrupts wieder zulässt. Es können auch 50msec sein, denn niemand
drückt so schnell die Taste nacheinander.
Tasten entprellten mit nem µC heißt nichts anderes als die Taste niemals
schneller abfragen als die Prellzeit es erlaubt!
MaWin schrieb:> Es können auch 50msec sein, denn niemand> drückt so schnell die Taste nacheinander.
Teo Derix schrieb:> Tasten entprellten mit nem µC heißt nichts anderes als die Taste niemals> schneller abfragen als die Prellzeit es erlaubt!
Nö.
Man kann es erheblich besser machen, als solche Behelfsentprellung.
Ismael Touomo schrieb:> Das Problem ist , ich weiß nicht , wie ich Tastenentprellung in Diesem> Fall realisieren soll (Ich habe noch nie eine Tastenentprellung mit> extern Interrupts un Timer realisier).
Mit AVRs kenne ich mich nicht wirklich gut aus. Aber im Grunde kann man
das schon so machen. Ich wuerde direkt nach auftreten des externen
Interrupts selbigen sperren. Wieder freigeben kannst du ihn dann nach
deiner Entprellverzoegerung z.b. mittels Timer-IRQ oder mit einem
Usertimer deines RTOS.
Am einfachsten ist, einen kleinen Kondensator (z.B. 47nF) parallel zum
Taster zu schalten. Aber das war wohl nicht die Frage.
Ich programmiere Tasten-Entprellung immer nach diesem Prinzip: Lies die
Tasten wiederholt ein, bis Du zweimal das gleiche Ergebnis erhälst.
1) Lese den Port mit den Tasten in Variable A ein (also 1..8 Tasten auf
einen Rutsch).
2) Warte ein bisschen (10-100ms).
3) Lese nochmal ein, in Variable B.
4) Maskiere mit einer UND Verknüpfung die unrelevanten Bits aus. Also
wenn an PB0 und PB1 zwei tatsen hängen, dann: A&=3; B&=3; Dieser Schritt
entfällt, wenn der ganze Port mit Tastern beschaltet ist.
5) Wenn A nicht gleich B ist, dann setze A=B und wiederhole bei 3).
6) Ansonsten, werte das Ergebnis in B aus.
Das kannst Du wahlweise in einem Timer-Interrupt machen, oder in einer
Hauptschleife. Wenn Du es im Interrupt machts, hast Du den Vorteil, dass
das Hauptprogramm während der Wartezeit nicht hängt. Andererseits fragst
Du die Tasten so viel häufiger ab, als nötig, was bei Zeitkritischen
Anwendungen stören kann. Es kommt halt sehr auf die Gesamt-Anwendung an.
Einfacher ist es, die Wartezeit einfach mit einem sleep() zu
implementieren, aber dann bleibt das laufende Programm kurz stehen,
während es die Tasten entprellt. Das kann stören, kann aber auch völlig
ok sein. Es hängt von der Gesamt-Anwendung ab.
Stefan schrieb:> Andererseits fragst> Du die Tasten so viel häufiger ab, als nötig, was bei Zeitkritischen> Anwendungen stören kann.
Eben, deshalb brauchen wir unbedingt eine Tastenabfrage, die nur dann
die Tasten abfragt, wenn Jemand in der Nähe ist, der die Tasten auch
betätigen könnte. Genauso nötig brauchen wir Bildschirme, die nur dann
arbeiten, wenn jemand auf den Bildschirm schaut...
Spaß beiseite...
Eine ordentliche Tastenentprellung läuft ständig im Hintergrund und
benötigt dabei zum Entprellen von 8 Tasten weit weniger als 1% der
Rechenleistung eines AVRs. Beispiele sind hier zu finden:
Entprellung
...
Peter Dannegger schrieb:>> Tasten entprellten mit nem µC heißt nichts anderes als die Taste niemals>> schneller abfragen als die Prellzeit es erlaubt!>> Nö.> Man kann es erheblich besser machen, als solche Behelfsentprellung.
Was willst Du da noch verbessern, zumindest was Tasten betrifft?
Teo Derix schrieb:> Was willst Du da noch verbessern, zumindest was Tasten betrifft?
Tasten können von älteren Menschen gedrückt werden (= lange).
Kontakte können verdreckt sein, Federn ermüdet (kurze Unterbrechungen).
Tasten können auch beim Loslassen prellen.
In die Tastenleitung können Störungen einkoppeln (elektrostatische
Aufladung der betätigenden Person)).
Gegen all das hilft ein einfaches Delay nicht.
> einen kleinen Kondensator (z.B. 47nF) parallel zum Taster zu schalten.> 10K +100nf - da prellt nix mehr
Wenn der Eingang einen Schmitt-Trigger hat (was beim AVR der Fall ist).
Nicht jeder Taster mag es allerdings, wenn er auf 5V geladenen 100nF
kurzschliesst. Ein 100 Ohm Widerstand in Reihe kann
lebensdauerverlängernd sein.
Peter Dannegger schrieb:> Tasten können von älteren Menschen gedrückt werden (= lange).
Äh, was hat das mit Tastenentprellung zu tun?
> Kontakte können verdreckt sein, Federn ermüdet (kurze Unterbrechungen).
Wird von der "Behelfsentprellung" weitgehend eliminiert. Wie machst Du
das?
> Tasten können auch beim Loslassen prellen.
Wie sollte das meine "Behelfsentprellung" aushebeln?
> In die Tastenleitung können Störungen einkoppeln (elektrostatische> Aufladung der betätigenden Person)).
Das will ich sehen wie Du das Softwärmäsig lösen willst!
Und zum wiederholten male, das hat nichts mit Tastenentprellung zu tun!
> Gegen all das hilft ein einfaches Delay nicht.
Oh, ich wusste gar nicht das wir uns kennen?
oder woher weist Du das ich das mit Delays mache. Ist wohl Deine erste
Wahl bei solchen Problemen?
Also ich würde es vertsehen, wenn PeDa es leid ist, auf das immer wieder
wöchentlich auftauchende Thema Entprellung nicht mehr einzugehen. Die
Diskussion wurde schon so oft geführt, dass es nicht mehr sinnvoll ist,
sie immer wieder neu aufzuwärmen.
Um auch nochmal schnell meinen Senf dazuzugeben....
Bevor man sich mit dem ENTprellen beschäftigt, sollte man sich evtl
erstmal fragen, was das Prellen eigentlich ist... dann wird man schnell
feststellen, dass es ein Hardware-seitiges Problem ist.
Ob man nun das Prellen per Hardware (RC-Glied, FlipFlop), vom µC
fernhält, und somit entprellt die Schalung entprellt, oder die Prellzeit
einfach per Software ignoriert(Interrupt,Polling (wie auch immer)), und
somit die Schaltung entprellt, ist am Ende eigentlich nur noch ne
philosophische Frage =).
Wer Bauteile sparen will, und dafür ne Zeile mehr Code tippen mag, der
wähle diesen Weg. Wer lieber 20 Sekunden mehr Lötvergnügen haben
möchte,und dafür ne Zeile spart, möge diesen Weg wählen =).
Am Ergebnis, nämlich in beiden Fällen eine vernünftig entprellte
Schaltung zu haben, ändert sich im großen eigentlich gar nichts.
in diesem Sinne, jendrik
Wie schon geschrieben wurde, es kommt auf deinen Einsatz an wie du es am
einfachsten bei dir realisierst.
Die Frage ist auch warum dein Switch mit einem Interrupt ausgelesen
werden soll? Denn so richtig Sinn macht das nur wenn du ein
Batteriebetriebenes Gerät hast das sonst ständig im Sleep-Mode ist.
Falls das nicht der Fall ist, dann ist es einfacher ständig den Taster
zu pollen, dein Programm läuft ja eh ständig.
(angespasstes Codesnippet von einem Microchip Beispiel)
Du setzt deinen Timer auf eine Periode von 1ms, im Timer pollst du dann
den Taster. Du verwendest zwei Variablen, eine die den Status der Taste
enthält (buttonPressed), eine zweite als Zähler (buttonCount).
1
volatileBOOLbuttonPressed;
2
volatileBYTEbuttonCount;
1
//Initialize all of the debouncing variables
2
buttonCount=0;
3
buttonPressed=FALSE;
kommt in die Interrupt-Routine des Timers:
1
//This is reverse logic since the pushbutton is active low
2
if(buttonPressed==sw2)
3
{
4
if(buttonCount!=0)
5
{
6
buttonCount--;
7
}
8
else
9
{
10
//This is reverse logic since the pushbutton is active low
11
buttonPressed=!sw2;
12
13
//Wait 100ms before the next press can be generated
14
buttonCount=100;
15
}
16
}
17
else
18
{
19
if(buttonCount!=0)
20
{
21
buttonCount--;
22
}
23
}
D.h. am Anfang ist buttonPressed = False und buttonCount = 0 und nichts
passiert im Timer. sw2 (der Eingang des uC vom Taster) ist 1 in
Ruheposition, 0 wenn er gedrückt wird. (falls es bei dir anders rum ist
musst du es eben anpassen).
Wird sw2 gedrückt (=0) setzt die Timer Routine den Status auf
buttonPressed = True (!sw2) und initialisiert den Counter (entspricht
100ms). D.h. sw2 = 0 (gedrückt) --> buttonPressed = 1 (!sw2).
Im Timer wird ab dann nun einfach der counter runter gezählt (unterer
else part), da buttonPressed =! sw2 ab sofort ist.
Lässt die Person den Taster los, sw2 = 1, so springt die Timer routine
in den oberen if part, da sw2 == buttonPressed ist, und zählt weiter
runter, sofern die 100ms noch nicht vergangen sind.
Sind sie es, wird der Status der Taste auf buttonPressed = False gelegt
(!sw2=1) und der Zähler zählt wieder 100ms runter bis 0 und verharrt
dort bis der nächste Drücker kommt.
Wie du siehst, brauchst du den externen Interrupt der Taste nicht.
Du kannst ihn einbauen, indem du damit den uC aus einem Sleep aufwachst
und/oder den Timer damit einschaltest und nach dem Loslassen der Taste
den Timer wieder ausschaltest.
Beides aber 'unnötig' bei netzbetriebenen Applikation bei denen der uC
ständig full power läuft.
Ich bin der Meinung diesen Code kann man schnell nachvollziehen und auch
schnell an seine Bedürfnisse anpassen. Er reicht für den normalen
Gebrauch sicherlich vollkommen aus.
Der Code vom Mikcrocontroller Artikel hingegen, der Timer verwendet, ist
ein Alptraum bezüglich Lesbarkeit. Mag zwar sein, dass es super klein,
effizient und einen großen Funktionsumfang bietet, aber naja, das ist
dem Threadstarter sicherlich vollkommen egal, vorerst.
Vielen vielen Dank an allen für die Antworte.
Ich merke schon dass, die Tastenentprellung kein einfaches Thema ist.
Eigentlich brauche ich das für ein viel größeres Projekt.
Ich wollte erstmal anhand eines kleinen Programm verstehen, wie es geht.
Ich glaube , ich werde das Design meines Projektes ändern und die
Tastenentprellung mit einem Timer Interrupt realisiren(Polling).Ich muss
nur noch ein Mechanismus einbauen, das mir Informationen zu der
gedrückten Taste liefern.
@ Frank M. : Danke für den Stückcode. Ich verstehe , was du gemacht hast
:)
Ein einfacher "Mechanismus" zur Tastenabfrage ist per Spannungsteiler
5V----[1KOhm]---------[2KOhm]---[Taster]--((Gnd
|
|
|---[4KOhm]---[Taster]--((Gnd
|
|
|---[8KOhm]---[Taster]--((Gnd
|
|
|---[16KOhm]--[Taster]--((Gnd
|
|
|-----------[ADµC
So kannst du bis zur ADC-Auflösung minus 1 Taster gleichzeitig abfragen.
Wenn du dich drauf beschränkst, einzelne Taster zu drücken, kannst du
die Spannungsteiler auch beliebig dimensionieren, und dann den
entsprechenden ADC-Wert ausmessen.
Polling im Millisekundenbereich auf gelatchte Pegel, die im
Microsekundentakt hardwareseitig aktualisiert werden, ist zur
exkludierenden Erkennung von Störsignalen genausogut geeignet, wie ein
Dreh am Glücksrad.
Pollingroutinen entprellen nur dadurch, daß sie in der Summe ihrer
Zeitabschnitte die Abklingzeit des Prellvorganges großzügig
überschreiten.
Als Trigger zur sicheren Erkennung von Störimpulsen ist Polling völlig
ungeeignet, weil nur zufallstatistisch arbeitend.
Daran ist nix genial und schon gar nix sicher, im mathematischen, bzw.
programmiertechnischen Sinne.
Längere Störsignalsequenzem können z.B. durch das pollingmässige
Stochern im Nebel nicht mit Sicherheit eliminiert werden, weil immer
wieder Zufallstreffer auf mehrere "konstante" Pegel enstehen werden, die
jedoch zu einem Wechselsignal gehören können.
Mike
Michael Sch. schrieb:> Längere Störsignalsequenzem können z.B. durch das pollingmässige> Stochern im Nebel nicht mit Sicherheit eliminiert werden, weil immer> wieder Zufallstreffer auf mehrere "konstante" Pegel enstehen werden, die> jedoch zu einem Wechselsignal gehören können.
Dieses Problem hast du aber immer, egal welche Methode.
Einer Sequenz von Pulsen sieht man nun mal nicht mehr an, wie sie
entstanden ist. Und es wird immer eine Grauzone geben, an der nicht mit
letzter Sicherheit gesagt werden kann, ob ein Puls jetzt ein gewollter
Tastendruck oder ein Störpuls war.
Was schlägst du statt dessen vor?
Und ja. Die von Frank M. weiter oben gezeigt Lösung ist in dieser
Hinsicht sicher nicht 'optimal'. Besser wäre es, nicht auf 100ms
'Zwangspause' zu gehen, sondern die Zählerei bei jedem Pegelwechsel neu
zu starten und nur dann, wenn der Zähler abläuft (müssen dann auch keine
100ms sein), dann wird das als Tastendruck gewertet. Aber seis drum. Du
hast ja nicht seinen Code speziell angesprochen sondern Polling an sich.
Michael Sch. schrieb:> Längere Störsignalsequenzem können z.B. durch das pollingmässige> Stochern im Nebel nicht mit Sicherheit eliminiert werden, weil immer> wieder Zufallstreffer auf mehrere "konstante" Pegel enstehen werden, die> jedoch zu einem Wechselsignal gehören können.
ROFL, und wie entprellt der Herr Theoretiker dann?
Bildest du jetzt eine Autokorrelationsfunktion von -unendlich bis
+unendlich über deine Tastereingänge um zumindest stochastische
Störungen rauszufiltern, oder hast du über eine adaptive
Verhaltensannahme Kenntnisse über das Tastendruckverhalten und mit
dieser Kenntnis bildest du eine Kreuzkorrelation über das Tastensignal
und eliminierst so alle Störungen die nicht dem Muster der Tastendrücke
entsprechen?
Sag mal an, wie machst du es besser?
Udo Schmitt schrieb:> Michael Sch. schrieb:>> Längere Störsignalsequenzem können z.B. durch das pollingmässige>> Stochern im Nebel nicht mit Sicherheit eliminiert werden, weil immer>> wieder Zufallstreffer auf mehrere "konstante" Pegel enstehen werden, die>> jedoch zu einem Wechselsignal gehören können.>> ROFL, und wie entprellt der Herr Theoretiker dann?> Bildest du jetzt eine Autokorrelationsfunktion von -unendlich bis> +unendlich über deine Tastereingänge um zumindest stochastische> Störungen rauszufiltern, oder hast du über eine adaptive> Verhaltensannahme Kenntnisse über das Tastendruckverhalten und mit> dieser Kenntnis bildest du eine Kreuzkorrelation über das Tastensignal> und eliminierst so alle Störungen die nicht dem Muster der Tastendrücke> entsprechen?
Web-Cam, die den Finger detektiert, der die Taste drückt.
Ich entprelle folgendermassen...
Mit wenig Code im Pchg_int ist eine "sichere" Routine leicht zu
realisieren, weil dort schon die Flanken, also die Pegel_Änderungen
signalisiert werden. Und zwar NUR die Änderungen. Und das mit der
Reproduzierbarkeit und Schnelligkeit der Hardwarelogik.
Prinzip-Beispiel in Bascom:
(Von der Syntax her leicht nachzuvollziehen)
Dim Last_pins_state As Byte
Dim Changed_pins As Byte
Dim Changed_pins_sum As Byte
Dim Deb_pinb As Byte
do
.
.
loop
'*********************
'Pinchange_Isr triggert bei JEDER Flankenänderung
Pchg_isr:
1 Changed_pins = Last_pins_state XOR PINB
2 Last_pins_state = PINB
3 Changed_pins_sum = Changed_pins_sum OR Changed_pins
Return
'********************
'Timer_isr... hier der Watchdogtimer als reiner Int_Generator
'mit ca. 19,7ms Periode...
Wd_isr:
4 Changed_pins_sum = Changed_pins_sum Xor &HFF
5 Deb_pinb = Changed_pins_sum And Last_pins_state
6 Changed_pins_sum = 0
Return
'*********************
Das ist schon alles an Code... im Deb_pinb stehen die gültigen Zustände.
...es wird JEDER Flankenwechsel in der Pchg-isr erkannt und bis zum
nächsten Timer_int gesammelt (3)... ..auch beliebige 0-1-0... oder
1-0-1... Segmente werden als "nichtstatisch" erfasst, obwohl sich der
letzte Pegel gegenüber dem ersten Wert nicht unterscheidet! Die
Polling_Routine merkt sowas nicht.
Die zu überwachenden Eingänge werden mit den Bits des PCMSK
(Pchg-Interrupt-Mask) selektiert. Nur die dort ausgewählten werden
gefiltert.
Arbeitet auf Bytebreite
Wird durch langen Tastendruck o. beliebige Tastenaktionen nicht
blockiert
Tasten werden unabhängig voneinader prozessiert
Arbeitet reproduzierbar sicher!
Grenzfrequenz hängt direkt mit Timerfrequenz, sowie Code-Laufzeit
zusammen.
Bei Polling kann es vorkommen, daß bei ganzzahligen Verhältnissen von
Timerintervall und Störfrequenz ein vermeintlich statischer Zustand
signalisiert wird, wo jedoch eine Frequenz zugrunde liegt. Oder bei
geringfügig unterschiedlichen Freq.-Ratia kommt es zu langen
Fehl-Signalen durch Schwebung.
Das passiert in der obigen Routine nicht. Die unterscheidet statische
Pegel zweifelsfrei von nichtstatischen Da gibt es keine
Polling-Artefakte.
Mike
Michael Sch. schrieb:> Ich entprelle folgendermassen...>> Mit wenig Code im Pchg_int ist eine "sichere" Routine leicht zu> realisieren, weil dort schon die Flanken, also die Pegel_Änderungen> signalisiert werden. Und zwar NUR die Änderungen.
Ach!
Und das unterscheidet sich jetzt ganz genau wie von Pegeländerungen
durch Störungen?
> Ich entprelle folgendermassen...> 'Pinchange_Isr triggert bei JEDER Flankenänderung
Ach du Scheisse, NEEEEIIIIINNNNN !
Jedesmal kommt der gröbste Schwachsinn wenn der Thread eigentlich schon
geklärt ist, weil irgendeine absoluter Hornochse auch noch unbedingt
öffentlich kund tun will was für ein Hornochse er ist.
> ...es wird JEDER Flankenwechsel in der Pchg-isr erkannt und bis> zum nächsten Timer_int gesammelt (3)... ..auch beliebige 0-1-0...> oder 1-0-1... Segmente werden als "nichtstatisch" erfasst, obwohl> sich der letzte Pegel gegenüber dem ersten Wert nicht unterscheidet!> Die Polling_Routine merkt sowas nicht.
Mit anderen Worten.
Wenn sich in deinem, durch den Timer vorgegebenen, Polling-Intervall
(denn um etwas anderes handelt es sich nicht) ein Flankenwechsel an
einem Eingangspin gezeigt hat, dann wartest du das als Tastendruck.
Und das löst jetzt das Problem von auftretenden Störimpulsen wie?
(MEiner Meinung nach löst es das Problem überhaupt nicht. Aber
vielleicht übersehe ich ja was).
Alles in allem ist das IMHO: eine selten komplizierte Kombination aus
Pin-Change INterrupt und Polling, die das angestrebte Ziel der
Störimpulsunterdrückung nicht lösen kann. In dem Punkt vollständig
durchgefallen.
Und wenn ich es mir recht überlege:
Sie entprellt auch nicht immer korrekt. Was wenn die Prellpulse genau
auf die 19.7ms Grenze deines Timers fallen?
Das einzige was deine Lösung kann ist:
Sie registriert auch dann noch einen Tastendruck, wenn dieser kürzer als
die 20ms ist, auf die die PeDa Lösung so über den Daumen eingestellt
wird. Aber den Benutzer möchte ich mal sehen, der es schafft in 20 ms
eine Taste zu drücken und wieder loszulassen.
Du nimmst es mir nicht krumm, aber ich bleibe bei der PeDa Lösung. Deine
Variante ist dazu einfach keine Alternative.
Autor: Michael Sch. (mikel_x)
Datum: 05.03.2013 12:57
Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum: 05.03.2013 12:58
Ach!
Und das unterscheidet sich jetzt ganz genau wie von Pegeländerungen
durch Störungen?
1 Minute um die Wahrheitstabelle nachzuvollziehn und die Prozedur als
Ganzes innerhalb beider Ints zu vertstehen und zu bewerten....
3 mal kurz gelacht.... Dazu muss man nix mehr sagen.... ;-)
Michael Sch. schrieb:> Autor: Michael Sch. (mikel_x)> Datum: 05.03.2013 12:57>> Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)> Datum: 05.03.2013 12:58>> Ach!> Und das unterscheidet sich jetzt ganz genau wie von Pegeländerungen> durch Störungen?>>> 1 Minute um die Wahrheitstabelle nachzuvollziehn und die Prozedur als> Ganzes innerhalb beider Ints zu vertstehen und zu bewerten....
Jau. stell dir das mal vor :-)
> 3 mal kurz gelacht.... Dazu muss man nix mehr sagen.... ;-)
So krass wollte ich das nicht ausdrücken, bin ja schliesslich höflich.
Aber ja: Routine gesehen, die ersten Probleme darin gesehen, und ....
tatsächlich gelacht.
Michael Sch. schrieb:
>Polling im Millisekundenbereich auf gelatchte Pegel, die im>Microsekundentakt hardwareseitig aktualisiert werden, ist zur>exkludierenden Erkennung von Störsignalen genausogut geeignet, wie ein>Dreh am Glücksrad.
Das hat die alte Frau, die strickend neben mir sitzt sofort verstanden
und
mit einem wohlwollenden Kopfnicken quittiert.
Mawin schrieb:
>Ach du Scheisse, NEEEEIIIIINNNNN !>Jedesmal kommt der gröbste Schwachsinn wenn der Thread eigentlich schon>geklärt ist, weil irgendeine absoluter Hornochse auch noch unbedingt>öffentlich kund tun will was für ein Hornochse er ist.
Das hingegen löste bei ihr nur mildes Kopfschütteln aus und sie sagte,
daß man bei diesem Wetter nun seine Mütze langsam abnehmen könne.
gez. Zittermann
> Jau. stell dir das mal vor :-)
Ich bin ziemlich gut darin, Code schnell zu erfassen.
Und deiner ist nicht besonders kompliziert.
Er beruht auf: Wenn es in den letzten 19.7ms irgendeinen Puls an einem
Eingang gab, dann gilt der zuletzt im Intervall angetroffene Zustand als
der 'entprellte' Tastenzustand.
Das ist weder in allen Fällen korrekt entprellt, noch behandelt es
Störpulse.
@khb
Das war bis jetzt eine Behauptung, die auf Verifizierung anhand von
logischen Abläufen wartet. Ich warte immer noch, bis ich mitlachen
darf...
Bei mir funktioniert die Routine fehlerfrei.... sowohl mit
Dauersignalen, als auch mit zwei zusammengeschnippten Drähten, als
Worst_Case-Taster....
Michael Sch. schrieb:> @khb>> Das war bis jetzt eine Behauptung, die auf Verifizierung anhand von> logischen Abläufen wartet.
Och, das ist nicht schwer zu verifizieren.
Ein 1ms langer 1-0-1 Störpuls löst den Pin-Change Interupt aus. Und wenn
der zeitliche Ablauf so ist, dass hier
1-0-1
^
|
der Watchdog Timer zuschlägt, dann registrierst du diesen Pin-Change
als Tastendruck, durch ein 0-Bit an der entprechenden Stelle in
Deb_pinb.
Das Ziel der Übung ist es aber gerade, dass dieser 1ms Puls es nicht
durch die Tasten-Entprellung/Störungsbehandlung schafft, weil das kein
Tastendruck sein kann.
QED
Quatsch! Durch die 1-0 Flanke wird dieser Zyklus schon als instabil
markiert und verworfen! Das ist ja gerade mein obiges Argument, das
dafür spricht. Diese Routine lässt sich nicht vom letzten Zustand
täuschen, wie die Polling-Dinger...
Ich sag ja, diese Routine ist seeehr genau... quasi unbestechlich... ;-)
Michael Sch. schrieb:> Quatsch! Durch die 1-0 Flanke wird dieser Zyklus schon als instabil> markiert und verworfen!
Aha.
Und das passiert ganz genau wo?
Hmmm.
OK. Muss mich bei dir entschuldigen.
Ich hab die Auswirkungen des XOR hier
4 Changed_pins_sum = Changed_pins_sum Xor &HFF
nicht gut genug bedacht. Ich hab das zuerst als Umdrehen des
Tastenzustands interpretiert. Aber, es gibt dem hier
5 Deb_pinb = Changed_pins_sum And Last_pins_state
eine neue Wendung.
In Deb_pinb kriegt man ein 1-Bit, genau dann wenn
* am Pin im letzten Intervall nicht gewackelt wurde UND
* der zuletzt angetroffene Tastenzustand eine 1 war
Karl Heinz Buchegger schrieb:> In Deb_pinb kriegt man ein 1-Bit, genau dann wenn>> * am Pin im letzten Intervall nicht gewackelt wurde UND> * der zuletzt angetroffene Tastenzustand eine 1 war
Nehm ich jetzt aber dazu, dass ein gedrückter Taster normalerweise eine
0 liefert, dann liefert das in der Umkehrung
In Deb_pinb kriegt man pro Taste ein 0-Bit genau dann wenn
* am Pin gewackelt wurde ODER
* die Taste niedergedrückt ist
Hmmmm. Damit kannst du aber erst recht nicht einen gedrückten Taster von
einem kurzen Störpuls unterscheiden.
Ich habe mal Michaels Bascom-Routine nach C übersetzt und ein kleines
main() geschrieben, um das unter Linux zu simulieren:
1
#include<stdint.h>
2
#include<stdio.h>
3
4
staticvolatileuint8_tPINB;// SIMULIERTER Pin
5
staticvolatileuint8_tchanged_pins_sum;
6
staticvolatileuint8_tlast_pins_state;
7
staticvolatileuint8_tdeb_pinb;
8
9
// Pinchange_Isr triggert bei JEDER Flankenänderung
10
voidpinchange_ISR(void)
11
{
12
uint8_tchanged_pins;
13
14
changed_pins=last_pins_state^PINB;
15
last_pins_state=PINB;
16
changed_pins_sum=changed_pins_sum|changed_pins;
17
}
18
19
// Timer_isr... 19,7ms Periode...
20
voidtimer_ISR(void)
21
{
22
changed_pins_sum=changed_pins_sum^0xff;
23
deb_pinb=changed_pins_sum&last_pins_state;
24
changed_pins_sum=0;
25
}
26
27
intmain()
28
{
29
PINB=1;
30
timer_ISR();
31
printf("1: 0x%02x\n",deb_pinb);
32
33
// jetzt kurzer Puls:
34
#if 1
35
PINB=0;
36
pinchange_ISR();
37
PINB=1;
38
pinchange_ISR();
39
#endif
40
41
timer_ISR();
42
printf("2: 0x%02x\n",deb_pinb);
43
timer_ISR();
44
printf("3: 0x%02x\n",deb_pinb);
45
46
return0;
47
}
Ausgabe:
1
# cc debounce.c -o debounce && ./debounce
2
1: 0x00
3
2: 0x00
4
3: 0x01
Entweder ist meine Bascom-C-Übersetzung falsch oder Michaels Routine.
Denn hier wird beim 3. Timer-Ablauf plötzlich eine Taste erkannt...
Wenn ich aus dem '#if 1' ein '#if 0' mache, ist die Ausgabe:
1
# cc debounce.c -o debounce && ./debounce
2
1: 0x00
3
2: 0x00
4
3: 0x00
Das heisst für mich: Ein Störimpuls wird fälschlicherweise als
Tastendruck erkannt - witzigerweise aber erst nach einem weiteren
Timer-Ablauf.
Die eine Minute war wohl doch n Bissl kurz...?!
na, in (1)... da wird identifiziert WELCHES BIT ne Flanke produziert
hat. Der Pchg_int meldet das ja nicht rüber, sondern nur, DAß
irgendeines der gemasketen Bits geändert wurde.
...und in (3) werden alle weiteren Flanken in das Changed_pins_sum
hinein_ge_ODER_t. Falls andere Eingänge innerhalb der Periode auch noch
wackeln, werden sie dadurch auch reingeholt. Ebenso, wenn ein Eingang
ein zweites Mal wackelt. Der wird auch nochmal hineingeodert, was aber
nichts bewirkt. weil er eh schon auf 1 (=changed) gesetzt war.
Wohlgemerkt, ich spreche hier vom Intervall zwischen 2 Timer_ints. Ich
beobachte nicht den letzten, vorherig gültigen Wert, wie es andere
Routinen machen... Ich sammle nur alle Erst-Flanken zwischen zwei
Timer_ints.
Der Timer_int stellt dann das Bitmuster auf den kopf und aktualisiert
per UND nur jene Bits im Ausgaberegister, bei denen kein Flankenwechsel
auftrat, mit dem gecachten Wert. Danach setzt er das Sammelregister
aller Flankenänderungen auf Null, so dass es auf neue Flanken 'lauern'
kann.
Michael Sch. schrieb:> Die eine Minute war wohl doch n Bissl kurz...?!>> na, in (1)... da wird identifiziert WELCHES BIT ne Flanke produziert> hat. Der Pchg_int meldet das ja nicht rüber, sondern nur, DAß> irgendeines der gemasketen Bits geändert wurde.>>> ...und in (3) werden alle weiteren Flanken in das Changed_pins_sum> hinein_ge_ODER_t. Falls andere Eingänge innerhalb der Periode auch noch> wackeln, werden sie dadurch auch reingeholt. Ebenso, wenn ein Eingang> ein zweites Mal wackelt. Der wird auch nochmal hineingeodert, was aber> nichts bewirkt. weil er eh schon auf 1 (=changed) gesetzt war.
Erzähl mir was neues.
Der Teil war von vorne herein klar.
Der spannende Teil ist der Auswertungsteil im Timer Interrupt.
> Der Timer_int stellt dann das Bitmuster auf den kopf und aktualisiert> per UND nur jene Bits im Ausgaberegister, bei denen kein Flankenwechsel> auftrat, mit dem gecachten Wert. Danach setzt er das Sammelregister> aller Flankenänderungen auf Null, so dass es auf neue Flanken 'lauern'> kann.
Code vorlesen kann ich auch.
Aber was bedeutet er? Welche Konsequenzen ergibt sich aus der
Abarbeitung.
Dein Code liefert ein 0-Bit im Ergebnis wenn entweder
* der Pin gewackelt hat
* oder kein Wackeln feststellbar war und der letzte Pin-Wert ein 0-Bit
war
Nimmt man jetzt dazu, dass ein gedrückter Taster ein 0-Bit liefert,
kannst du nicht zwischen Störpuls und gedrücktem Taster unterscheiden.
(das lässt sich beheben, wurde aber in dem Code nicht gemacht)
Deine Philosophie ist
* solange am Pin in einem Zeitintervall Bewegung herrscht
wird der Eingang definitiv als 0 gewertet
PeDas Philiosphie ist
* ein prellender Taster kommt irgendwann zur Ruhe
* solange Bewegung am Eingang herrscht, kann keine
definierte Aussage über irgendeinen Zustand getroffen werden.
Der zuletzt festgestellte Zustand bleibt erhalten
* Dazu genügt es (für Tasten), in regelmässigen Abständen
hinzusehen
Michael Sch. schrieb:> 1 Changed_pins = Last_pins_state XOR PINB> 2 Last_pins_state = PINB
Nur was ist mit Pegeländerungen zwischen 1 und 2? An einem anderen Pin
als dem, der den Interrupt ausgelöst hat? Allgemein gehen alle während
der ISR-Ausführung auftretenden Flanken bis auf eine Verloren.
Ernsthaft: die dadurch nicht registrierten Störungen dürften zu
vernachlässigen sein. Insofern ist Deine Methode nicht verkehrt. Aber
was bringt der Aufwand? In welchem realen Szenario ist dieser Aufwand
zuverlässiger als das Polling?
Wenn da regelmäßige Störungen auf der Leitung zu einem Taster sind,
deren Amplitude ausreicht, um ebenso regelmäßig die digitale Auslegung
des Pegels zu kippen, dann würde ich doch von einem massiveren Problem
ausgehen, das HW-seitig angegangen werden sollte? Oder ist Dein Taster
drahtlos angebunden? Dann wäre vielleicht ein bisschen Aufbereitung vor
dem digtalen Eingang angebracht?
Malte S. schrieb:> Ernsthaft: die dadurch nicht registrierten Störungen dürften zu> vernachlässigen sein. Insofern ist Deine Methode nicht verkehrt. Aber> was bringt der Aufwand? In welchem realen Szenario ist dieser Aufwand> zuverlässiger als das Polling?
Und wenn ich hinzufügen darf.
Durch den Einsatz des Timers sehe ich diese Methode ebenfalls als eine
Art Polling an.
Mit dem Zusatz, dass ein flatternder Eingang dazu führt, dass die
Eingangsabfrage auf einen bestimmten Wert (bei ihm 0) erzwungen wird.
Karl Heinz Buchegger
> PeDas Philiosphie ist
PeDa kann ausserdem:
- mit beliebigen Ports
- ohne Pin Change Interrupt arbeiten
- bietet autorepeat
- ist durch die große Verbreitung praxisgeprüft.
- ist nicht in einer proprietäten preogrammiersprache, die auch noch
Geld kostet.
Frank M. schrieb:> Entweder ist meine Bascom-C-Übersetzung falsch oder Michaels Routine.
Ich bin mir noch nicht sicher, ob Michael nicht seine Tasten umgekehrt
anschliest: Taster schaltet nach Vcc mit externem Pulldown.
So macht sein Ergebnis für mich noch am meisten Sinn.
> Denn hier wird beim 3. Timer-Ablauf plötzlich eine Taste erkannt...
Das sieht so gesehen dann für mich nämlich richtig (also im Sinne seines
Code) aus:
Im letzten Intervall gab es keine Flanken am Eingang und der letzte
Zustand der Eingangsleitung war eine 1
> Wenn ich aus dem '#if 1' ein '#if 0' mache, ist die Ausgabe:>>
1
> # cc debounce.c -o debounce && ./debounce
2
> 1: 0x00
3
> 2: 0x00
4
> 3: 0x00
5
>
Das ist allerdings interessant. IMHO hätte das Ergebnis eigentlich
1
# cc debounce.c -o debounce && ./debounce
2
1: 0x00
3
2: 0x01
4
3: 0x01
sein sollen. Die allererste 0 ist dem Umstand geschuldet, dass
last_pins_state sich erst mal korrekt einstellen muss.
Udo Schmitt schrieb:> Karl Heinz Buchegger>> PeDas Philiosphie ist>> PeDa kann ausserdem:> - mit beliebigen Ports> - ohne Pin Change Interrupt arbeiten> - bietet autorepeat> - ist durch die große Verbreitung praxisgeprüft.> - ist nicht in einer proprietäten preogrammiersprache, die auch noch> Geld kostet.
Nicht zu vergessen (und das ist für mich wichtig):
PeDas Code verwaltet einen Tasten-DRUCK in dem Sinne, dass eine
niedergedrückte Taste nur einmal gemeldet wird. Das ist immer dann
wichtig, wenn es um "1 mal drücken - 1 Funktionsausführung" geht.
Michaels Code kann man auch dorthin bringen, ist aber so gesehen von
daher noch nicht gleichwertig. Dieser Code entprellt erst mal nur den
Pin-Zustand. Aber letzten Endes liefert er auch nur den aktuellen
Pin-Zustand am Ende eines Intervalls mit dem Zusatz, dass dieser
Pin-Zustand auf 0 gezwungen wird, wenn im Intervall eine Flanke am
Eingang passierte.
@Namensvetter:
Seine Methode ist für 0=Taster losgelassen, 1=Taster gedrückt.
Für Inverse Logik funktioniert sie ohne Anpassung wohl nicht, wie KHB
anmerkte.
@Malte S.
Der Schwachpunkt meiner Routine weit oben ist, dass ein Störimpuls nicht
erkannt wird (hat man Störimpulse auf den Leitungen hat man aber ganz
andere größere Probleme), nur die Taste entprellt wird und das
Zeitfenster fest eingestellt ist.
Der Schwachpunkt der Methode aus dem Artikel ist, dass die Taste eine
sehr hohe Verzögerung hat (je nachdem wie lange man entprellen will),
dafür Störimpulse detektiert werden, das Zeitfenster aber auch fest ist,
da wenn es zu klein gewählt wird man wieder nicht entprellt.
Der Vorteil der von Michael Sch vorgestellten Methode ist, dass
Störimpulse rausgefiltert werden, sich die Zeit zum Entprellen dynamisch
anpasst und somit eine Auflösung der Taste nur durch den Timer und den
uC beschränkt ist.
Bitte korrigiert mich wenn ihr was anders seht.
Hier im Forum hat einer laut aufgeschrieen als er meinte er wertet jeden
Pin-Change aus, weshalb?
@Udo S.
- benötigt Pin Change Interrupt: klarer Nachteil der Methode, jedoch
wenn die Pins ein Port Change besitzen, was heutzutage viele haben, dann
ist es eine Überlegung Wert, zumal der Threadstarter den Taster an solch
einen Pin angeschlossen hat, passt es hier wunderbar
- Autorepeat: Wird sich sicherlich auch implementieren lassen. Er hat ja
eher nur das Grundgerüst gepostet.
- Praxisgeprüft: Falsch implementiert nutzt es einem nichts. ^^ Und
immerhin mal was neues.
- das ist ein schlechter Witz das als negativ Punkt anzumerken!
Karl Heinz Buchegger schrieb:> Ich bin mir noch nicht sicher, ob Michael nicht seine Tasten umgekehrt> anschliest: Taster schaltet nach Vcc mit externem Pulldown.
Geändertes main mit 0-1-0 statt 1-0-1:
1
intmain()
2
{
3
PINB=0;
4
timer_ISR();
5
printf("1: 0x%02x\n",deb_pinb);
6
7
// jetzt kurzer Puls:
8
#if 1
9
PINB=1;
10
pinchange_ISR();
11
PINB=0;
12
pinchange_ISR();
13
#endif
14
15
timer_ISR();
16
printf("2: 0x%02x\n",deb_pinb);
17
timer_ISR();
18
printf("3: 0x%02x\n",deb_pinb);
19
20
return0;
21
}
Ausgabe:
1
# cc -Wall debounce.c -o debounce && ./debounce
2
1: 0x00
3
2: 0x00
4
3: 0x00
Das sieht tatsächlich besser aus.
> So macht sein Ergebnis für mich noch am meisten Sinn.
Ja, aber oben schrieb er in
Beitrag "Re: Tastenentprellung"
"...es wird JEDER Flankenwechsel in der Pchg-isr erkannt und bis zum
nächsten Timer_int gesammelt (3)... ..auch beliebige 0-1-0... oder
1-0-1... Segmente werden als "nichtstatisch" erfasst, obwohl sich der
letzte Pegel gegenüber dem ersten Wert nicht unterscheidet!"
Für 1-0-1 scheint das nicht zu stimmen, es verhält sich offenbar anders
als 0-1-0.
Frank M. schrieb:> "...es wird JEDER Flankenwechsel in der Pchg-isr erkannt und bis zum> nächsten Timer_int gesammelt (3)... ..auch beliebige 0-1-0... oder> 1-0-1... Segmente werden als "nichtstatisch" erfasst, obwohl sich der> letzte Pegel gegenüber dem ersten Wert nicht unterscheidet!">> Für 1-0-1 scheint das nicht zu stimmen, es verhält sich offenbar anders> als 0-1-0.
du hattest den Status 1 nach zwei Timer-Interrupts, somit nicht
gewackelt, somit richtigerweise als 1 erkannt.
Was er meinte war, wenn innerhalr einer Timer-Periode eine Folge 1-0-1
oder 0-1-0 auftritt, wird es rausgefiltert, was stimmt. Wenn danach aber
eine 1 eine Periode lang konstant bleibt, wird die 1 gespeichert.
Frank M. schrieb:> Ja, aber oben schrieb er in>> Beitrag "Re: Tastenentprellung">> "...es wird JEDER Flankenwechsel in der Pchg-isr erkannt und bis zum> nächsten Timer_int gesammelt (3)... ..auch beliebige 0-1-0... oder> 1-0-1... Segmente werden als "nichtstatisch" erfasst, obwohl sich der> letzte Pegel gegenüber dem ersten Wert nicht unterscheidet!"
Worum es ihm geht ist, dass er in seinem Polling-Schema allen
auftretenden Flanken am Eingang den Sonderstatus einräumt, dass sie das
Ergebnis 'ungültig' machen. Wobei 'ungültig' für ihn bedeutet: ein 0-Bit
im Ergebnis.
> Für 1-0-1 scheint das nicht zu stimmen.
Worauf er hinaus wollte. In PeDas Code kann es theoretisch dazu kommen,
dass die Prellpulse in Phase zur Abfrage-Frequenz des Timers kommen, was
die Funktion dann nicht mitbekommt. Obwohl heftige 'Bewegung' am Eingang
ist, kriegt das der Code nicht mit und sieht den Eingang als statisch am
immer gleichen Pegel an (und meldet das dann auch). So gesehen kann man
PeDas Code austricksen, indem man eine Signal mit genau der richtigen
Frequenz und Phasenlage in den Eingang einspielt. Das kann bei ihm nicht
passieren.
Dafür hat sein Code das Problem, dadurch dass er sicherheitshalber im
Ergebnis auf 0 geht, wenn die Lage nicht eindeutig ist, dass in einer
Leitung mit active-Low Verhalten, jeder Störpuls zu einer 0 am Ausgang
führt. Blöderweise genau die Variante, die man für Taster am AVR
sinnvollerweise nimmt.
Frank M. schrieb:> @Namensvetter:> Seine Methode ist für 0=Taster losgelassen, 1=Taster gedrückt.
Ja, ist wohl so.
> Hier im Forum hat einer laut aufgeschrieen als er meinte er wertet jeden> Pin-Change aus, weshalb?
Pin-Change Plus Timer-Interrupt finde ich persönlich übertrieben. Dann
kann ich den Pin auch gleich im Timer-Interrupt pollen. Da sehe ich auch
keinen Nachteil. Die Gefahr eines "Verschluckens" eines Tastendrucks
durch Pollen sehe ich nicht. So kurz kann man keine Taste drücken, als
dass da was verloren gehen könnte. Daher ist für mich der
Pin-Change-Interrupt hyperfluid.
P.S.
Muss ich jetzt mein "Frank M." im Namen mit einem weiteren Buchstaben
versehen? Ich will nicht unbedingt verwechselt werden ;-)
sorry... da war tatsächlich ein Fehler meinerseits, durch die
verschiedenen Versionen, die ich hier auf verschiedenen Rechnern
rumgeistern habe.
so sollte es rennen, falls ich jetzt nicht das Chaos perfektioniert
habe... :-)
'******************
Pchg_isr:
Changed_pins = Last_pins_state Xor Pinb
Last_pins_state = Pinb
Changed_pins_sum = Changed_pins_sum Or Changed_pins
Return
'********************
Wd_isr:
Deb_pinb = Changed_pins_sum XOR Last_pins_state
Changed_pins_sum = 0
Return
Frank M. schrieb
> - Autorepeat: Wird sich sicherlich auch implementieren lassen. Er hat ja> eher nur das Grundgerüst gepostet.> - Praxisgeprüft: Falsch implementiert nutzt es einem nichts. ^^ Und> immerhin mal was neues.
Das zweifellos.
Zum Grundgerüst:
Ich seh das so. Bis man die Teile nachgerüstet hat, die ich mir von
einer normalen Tastdruckerkennung erwarte, bin ich Codeumfangsmässig
auch schon wieder bei der PeDa Lösung. Mit dem Vorteil nur eine ISR zu
haben. So wie der ukw-Frank sehe ich bei Tasten (das erscheint mir
wichtig, dass hier die Tasten ins Spiel kommen - denn Tasten können
nicht beliebig schnell gedrückt werden) nicht die Gefahr, dass eine
Benutzereingabe durch Timer-Polling verloren geht. Und so wie der andere
Frank sehe ich es so, dass ein Eingang an dem ausser Störpulse nur noch
Störpulse anliegen, von vorne herein nicht brauchbar ist. Ein unendlich
lang prellender Taster muss getauscht werden und nicht umgangen.
Michael Sch. schrieb:> so sollte es rennen, falls ich jetzt nicht das Chaos perfektioniert> habe... :-)> Wd_isr:>> Deb_pinb = Changed_pins_sum XOR Last_pins_state> Changed_pins_sum = 0>> Return
Also jetzt geänderte Timer-ISR:
1
// Timer_isr... 19,7ms Periode...
2
voidtimer_ISR(void)
3
{
4
deb_pinb=changed_pins_sum^last_pins_state;
5
changed_pins_sum=0;
6
}
Ausgabe für 1-0-1:
1
# cc -Wall debounce.c -o debounce && ./debounce
2
1: 0x00
3
2: 0x00
4
3: 0x01
Das heisst: Störimpuls wird immer noch als Tastendruck erkannt.
Frank M. schrieb:> Ausgabe für 1-0-1:
Sei fair und verdopple die erste Zahl
1-1-0-1
Ich denke so fair muss man schon sein, dem System ein 'einschwingen' in
einen stabilen Zustand zu erlauben.
D.h
> 1: 0x00
diese erste 0 ist uninteressant, die stammt aus der Einschwingphase
Michael Sch. schrieb:> Deb_pinb = Changed_pins_sum XOR Last_pins_state> Changed_pins_sum = 0
Changed State Result
0 0 0 ok
1 0 1 err
0 1 1 ok
1 1 0 err
Bei positiver Logik:
Gedrückte Taste, deren Zustand sich im letzten Timerintervall geändert
hat, gilt jetzt als losgelassen => der kleinste Störimpuls lässt eine
gedrückt gehaltene Taste nun als kurz losgelassen erscheinen. Was
verloren geht: welchen Zustand hatte die Taste denn im Intervall davor?
Nicht gedrückte Taste, deren Zustand sich im letzten Timerintervall
geändert hat, gilt als gedrückt => der kleinste Störimpuls lässt eine
unberührte Taste nun als kurz gedrückt erscheinen. Was verloren geht:
welchen Zustand hatte die Taste denn im Intervall davor?
Diese Variante sorgt vielmehr dafür, dass jede Störung zu einer
umgekehrten Auslegung des Zustands bei der letzten Flanke führt. Oder
sehe ich da was grundlegend falsch?
Karl Heinz Buchegger schrieb:> Sei fair und verdopple die erste Zahl>> 1-1-0-1>> Ich denke so fair muss man schon sein, dem System ein 'einschwingen' in> einen stabilen Zustand zu erlauben.
Okay, dann also 1-1-1-1-1-0-1:
Malte S. schrieb:> Diese Variante sorgt vielmehr dafür, dass jede Störung zu einer> umgekehrten Auslegung des Zustands bei der letzten Flanke führt. Oder> sehe ich da was grundlegend falsch?
Ich denke das siehst du richtig.
Denn in Changed... liegt ja das Ergebnis vor, ob sich am Eingang was
getan hat.
Ich denke das Grundproblem liegt darin, dass in dem Code versucht wird,
3 Informationen in einem einzigen Bit abzubilden.
gedrückt - losgelassen - gestört
die einzig sinnvolle Anwendung für 'gestört' kann aber nur sein, den
jeweils letzten Zustand weiter beizubehalten (oder "gestört" getrennt
auszuwerten) In allen anderen Fällen gibt es immer Verwechselungsgefahr
zwischen 2 der 3 Zuständen.
Karl Heinz Buchegger schrieb:> die einzig sinnvolle Anwendung für 'gestört' kann aber nur sein, den> jeweils letzten Zustand weiter ...
den jeweils letzten GÜLTIGEN Zustand weiter ....
Meine Fresse, in jedem Thread kommt ein Blöder, und dann geht es
endlos mit dem Blödsinn weiter.
> Dafür hat sein Code das Problem, dadurch dass er sherheitshalber im> Ergebnis auf 0 geht, wenn die Lage nicht eindeutig ist
Da Prellen sowohl beim runterdrücken der Taste als auch beim Loslassen
der Taste passieren kann, also symmetrisch ist, ist jeder code der sich
unsymmetrisch verhält von vorneherein falsch und er sollte dort hin
kommen wo er hingehört: In die Tonne.
MaWin schrieb:> Da Prellen sowohl beim runterdrücken der Taste als auch beim Loslassen> der Taste passieren kann, also symmetrisch ist, ist jeder code der sich> unsymmetrisch verhält von vorneherein falsch und er sollte dort hin> kommen wo er hingehört: In die Tonne.
Wo er recht hat, hat er recht.
MaWin schrieb:> Da Prellen sowohl beim runterdrücken der Taste als auch beim Loslassen> der Taste passieren kann, also symmetrisch ist, ist jeder code der sich> unsymmetrisch verhält von vorneherein falsch und er sollte dort hin> kommen wo er hingehört: In die Tonne.
Jepp,
Und zum Pin change Interrupt.
Wie oft denkt ihr denn prellt so eine taste? So eine richtig schlechte!
Einmal, zweimal? Dann seid ihr Optimisten.
1. braucht man den Pin change evt. für was anderes
2. Wird das entprellen über Pin Change mehr Rechenzeit brauchen. Zudem
hat man keinerlei Kontrolle wie oft und wie schnell die Interrupts
kommen.
Unschön!
MaWin schrie:
>Meine Fresse, in jedem Thread kommt ein Blöder, und dann geht es>endlos mit dem Blödsinn weiter.
Ja, aber es dauerte immerhin eine Weile, bis er kam....
SCNR
Habt ihr eventuell außer 8 gelassen, daß wenn der Taster auf Masse
zieht es Störimpulse sehr schwer haben, auf der dann auf GND liegenden
Leitung aufzutreten?
Buna-Pelzer
Von Basic 7 Zeilen nach C zu portieren, dürfte einfacher sein, als
umgekehrt. Und einige Leute hier, die sich analytisch beteiligen, machen
das ja auch, statt nur rum zu mosern. ;-)
Michael Sch. schrieb:> Deb_pinb = Deb_pinb AND Changed_pins_sum
Deb_pinb = alle bisher gedrückten und seit dem letzten Tick veränderten
Tasten
> Changed_pins_sum = Changed_pins_sum XOR &HFF
Changed_pins_sum = alle unveränderten Tasten...
> Changed_pins_sum = Changed_pins_sum AND Last_pins_state
...die gerade gedrückt sind
> Deb_pinb = Deb_pinb OR Changed_pins_sum
Deb_pinb = alle bisher gedrückten und seit dem letzten Tick veränderten
Tasten und alle unveränderten Tasten, die gerade gedrückt sind.
Ach komm...du verbeißt dich mit jeder neuen Variante weiter vom Ziel
weg.
Michael Sch. schrieb:> Die angepassten Namen kommen nachher.
Namen sind Schall und Rauch. Darum geht's doch gar nicht.
> Aber schön, daß du> auch was "entdeckt" hast, was du nicht verstehst... :-)
Dann versuche ich es doch glatt nochmal :-)
> '*********************> Pchg_isr:
Wie gehabt:
Last_pins_state = Aktueller Zustand der Taster
Changed_pins_sum = Alle Taster, deren Zustand sich seit dem letzten Tick
verändert hat.
>> '********************> Wd_isr:>> Deb_pinb = Deb_pinb AND Changed_pins_sum
Immer noch:
alle bisher gedrückten (alter Wert von Deb_pinb) und seit dem letzten
Tick veränderten (Changed_pins_sum) Tasten.
> Changed_pins_sum = Changed_pins_sum XOR &HFF
Bedeutung von Changed_pins_sum wird invertiert: alle seit dem letzten
Tick UNveränderten Tasten
> Changed_pins_sum = Changed_pins_sum AND Last_pins_state
Und maskiert, so dass diejenigen übrig bleiben, die gerade (= beim
letzten PCINT) gedrückt sind.
> Deb_pinb = Deb_pinb OR Changed_pins_sum
Und das jetzt plus wie oben gesagt diejenigen, die vorher gedrückt waren
und verändert wurden.
Oder anders: alle Tasten, die beim letzten Tick gedrückt waren.
Deb_pinb alt Taster jetzt geändert? Deb_pinb neu korrekt?
0 0 0 0 ja
0 0 1 0 ja
0 1 0 1 wayne*
0 1 1 0 ja
1 0 1 1 ja
1 0 0 0 wayne*
1 1 0 1 ja
1 1 1 1 ja
* = diese Kombination sollte niemals auftreten, da "geändert" gesetzt
sein müsste
Alles korrekt, nicht? Nur leider ist der Zustand etwas zu stabil...das
ist kein entprellen mehr, das ist ein Deb_pinb = Deb_pinb OR
undefined_behaviour.
Hmm, Deb_pinb bleibt also stets unverändert, außer wenn sich der Zustand
eines Tasters geändert hat, ohne dass das entsprechende Bit in
Changed_pins_sum gesetzt ist. Dieser Zustand sollte aber bei korrekter
Funktion des PCINT-Handlers nicht vorkommen. Wenn sich natürlich der
Readout von Pinb zwischen
Changed_pins = Last_pins_state XOR Pinb
und
Last_pins_state = Pinb
ändert, kann es schon dazu kommen. Wenn die Taste ausreichend prellt,
ist das evtl. sogar garantiert? Dann könnte das dem Placebo-Timer den
Hintern retten.
Davon abgesehen: Mach mal nen Zähler in den PCINT...ob da ein
acht-Bit-Typ reicht? Ich bezweifle das, bin aber zu faul, das jetzt zu
testen. Lohnt dieser Umgang mit CPU-Zyklen? ;)
Noch mehr abgesehen: versuche mal, diesen Ansatz auf eine gemuxte
Tastenmatrix zu skalieren. Polling kann das mit links.
@Malte S.
Die Tabelle ist schön und zeigt, dass das Programm so funktioniert wie
er behauptet.
Die Zustände bei denen du wayne geschrieben hast, sind korrekt und die
wichtigen.
Das Prinzip des Programs (modifiziertes Zitat von KHB)
In Deb_pinb kriegt man ein 0-Bit, genau dann wenn
* am Pin im letzten Intervall nicht gewackelt wurde UND
* der zuletzt angetroffene Tastenzustand eine 0 war
Also in anderen Worten:
Der Timer überprüft alle 20ms ob ein Pin einen anderen Status hat als
bisher. Wurde der Status des Pins dabei in den letzten 20ms jedoch nicht
verändert, dann kann davon ausgegangen werden dass der neue Status
stabil ist und der Taster nicht mehr prellt. Hat sich der Status in den
letzten 20ms jedoch noch geändert, dann schwingt da noch etwas.
Die Idee mit dem Zähler, um zu sehen wie oft die Interrupt-Routine
aufgerufen wird um zu sehen ob sie nicht den uC in der Zeit in der der
Taster prellt mehr oder weniger blockiert, ist interessant.
Vergiss es, du verstehst den Programmablauf und die Funktion seiner
Zwischenschritte nicht.
> Changed_pins_sum = Changed_pins_sum AND Last_pins_state
"Und maskiert, so dass diejenigen übrig bleiben, die gerade (= beim
letzten PCINT) gedrückt sind."
Dieser Abschnitt gehört zum maskierten Übertragen der "gültigen" bits...
hat nix mit "Tasten, die gerade gedrückt sind" zu tun, sondern mit
"Werte, die gerade gültig sind"...
Die bits, die im Ausgabebyte geändert werden, werden zuvor dediziert auf
0 gesetzt, damit sie mit den gültigen, neuen Werten auf Byteebene
definiert verodert werden können.
Du interpretierst auf Textbasis etwas am realen Ablauf vorbei... aber du
versuchst es immerhin... ;-)
@Frank M.
Bingo... genau so funktioniert das ganze... :-)
Ich hatte anfangs den Schnitzer in der Maskierungsroutine übersehen...
weil ich mich auf ein bestimmtes Bitmuster eingeschossen hatte. Mit dem
neuen Code solte es symmetrisch für High und Low genau das tun, was das
Ziel war.
@Michael Sch.
>Mit dem neuen Code solte es symmetrisch für High und Low genau das tun,>was das Ziel war.
Kannst Du bitte den ganzen Quelltext zur Verfügung stellen, mit
Initiali-
sierung u.s.w. ?
gez. Buna-Pelzer
Michael Sch. schrieb:> Du interpretierst auf Textbasis etwas am realen Ablauf vorbei... aber du> versuchst es immerhin... ;-)
Und ich gebe nicht auf.
Aber nach noch mehr Hinsehen nehme ich den Placebo und das undefinierte
Verhalten etc. zurück. Sorry!
Ja, der Groschen ist gefallen. Ich wollte dir eine Verwechslung von
Deb_pinb und Last_pins_state vorwerfern und genau dem bin ich selber
aufgesessen. Wie es zu den als undefiniert behaupteten Zuständen und
dadurch natürlich zum Funktionieren deines Codes kommt, habe ich
schließlich doch noch kapiert ;)
Dafür hab ich jetzt doch mal mit einem PCINT-Zähler experimentiert:
Kurzhubtaster, THT, genaue Bezeichnung unbekannt erzeugt i.d.R. genau
einen Interrupt beim Drücken und einen beim Loslassen. Gelegentlich aber
auch 3, vor allem beim Loslassen.
Das Einstecken einer Steckbrettbrücke prellt im zweistelligen Bereich,
aber schon durchaus mit Ausreißern über 200.
Beim Aneinanderhalten zweier Steckbrücken wird die ISR meistens zwischen
2000 und 5000 mal angesprungen, selten <200 oder >8000 mal. Beim
Loslassen ebenso.
Ein halbwegs guter Taster sollte also die Rechenzeit auch nur sehr mäßig
beanspruchen, während nach häufigem Gebrauch wohl mit mehr Aktivität zu
rechnen sein dürfte.
Tja, am Anfang ging ich davon aus, dass deine Methode funktioniert, dann
geriet ich ins Schwanken, jetzt denke ich wieder, dass sie durchaus
korrekt arbeitet.
Sehe trotzdem die erwähnten Nachteile der stark erhöhten
Unregelmäßigkeiten im Gesamttiming bei Betätigung (schlechter) Taster
und dass es unpraktikabel wird, wenn Multiplexing oder Schieber ins
Spiel kommen.
EDIT: ich zähle recht häufig eine gerade Anzahl von Interrupts, obwohl
der Zustand letztlich 2n+1 mal gewechselt haben muss. Manches wird also
verschluckt. Sollte deinen Code am Ende nicht stören, zeigt aber m.E.
dass der Mehraufwand auch nicht 100% sicher ist.
Ausgabe für 1-0-1:
# cc -Wall debounce.c -o debounce && ./debounce
1: 0x00
2: 0x00
3: 0x01
Sorry, ein kurzer Störimpuls wird immer noch als Tastendruck erkannt.
Bei 0-1-0 ist es:
# cc -Wall debounce.c -o debounce && ./debounce
1: 0x00
2: 0x00
3: 0x00
Das Programm verhält sich daher immer noch nicht "symmetrisch".
Buna-Pelzer schrieb
> Habt ihr eventuell außer 8 gelassen, daß wenn der Taster auf Masse> zieht es Störimpulse sehr schwer haben, auf der dann auf GND liegenden> Leitung aufzutreten?
Wir können glaube ich wirklich davon ausgehen das KEINER sich
Störimpulse auf einer von einem Schalter auf Ground gezogenen Leitung,
die als Hi erkannt werden könnten, leisten kann/muss.
Karl Heinz Buchegger
> * solange Bewegung am Eingang herrscht, kann keine> definierte Aussage über irgendeinen Zustand getroffen werden.> Der zuletzt festgestellte Zustand bleibt erhalten> * Dazu genügt es (für Tasten), in regelmässigen Abständen> hinzusehen
Wenn man nun in dieser Polling-Routine noch das Int- FLG abfragt und
davon ausgegangen werden kann das bei Änderung ein unsicherer Zustand
herrscht, der als „Schalter nicht betätigt“ angesehen wird.
Absolut sicher ist das:
Karl Heinz Buchegger:
> PeDas Philiosphie ist
> * ein prellender Taster kommt irgendwann zur Ruhe
Werden alle Stör/Prell-Impulse höher der der Abtastfrequenz(bei Int.
einsatz:zeit bis zur „Verifizierung“) eliminiert. Wenn benötigt, wählt
man ein nahe an der zu erwarteten niedrigsten Prellfrequenz ums so
„schnellst möglich“ zu reagieren.
Frank M. schrieb:> Pin-Change Plus Timer-Interrupt finde ich persönlich übertrieben.
Einen durch Taster o. sonst was Prellendes, ausgelösten Int. ohne
Kontrolle laufen zu lassen ist Schwachsinn, da es alleine schon selten
sinnvoll ist auf das Prellen eines Tasters zu reagieren, abgesehen aller
sonstigen Nachteile!
Also wenn schon Int. nötig, dann ist ein zusätzlicher Timer meist eine
sehr gute Idee!
Und noch was:
TASTEN PER INTERRUPT ZU BEDIENEN IST NICHTS BÖSES!!!
(zumindest wenn man weiß was man tut)
Teo Derix schrieb:> Frank M. schrieb:>> Pin-Change Plus Timer-Interrupt finde ich persönlich übertrieben.> Einen durch Taster o. sonst was Prellendes, ausgelösten Int. ohne> Kontrolle laufen zu lassen ist Schwachsinn, da es alleine schon *selten*> sinnvoll ist auf das Prellen eines Tasters zu reagieren, abgesehen aller> sonstigen Nachteile!
Du hast mich falsch verstanden. Ich halte es generell nicht für
sinnvoll, Tasten durch PCINTs zu entprellen - egal, ob dieser PCINT von
einer zusätzlichen Timer-ISR "kontrolliert" wird oder nicht.
PCINT + Timer ist daher für mich der absolute Overkill. Das war mit
obiger Aussage gemeint.
> Also wenn schon Int. nötig, dann ist ein zusätzlicher Timer meist eine> sehr gute Idee!
Nein, die bessere Idee ist, nur den Timer zu nehmen und auf den PCINT
zu verzichten.
> Und noch was:> TASTEN PER INTERRUPT ZU BEDIENEN IST NICHTS BÖSES!!!
Ein Interrupt kann keine Taste "bedienen", das kann nur Dein Finger.
Ein PCINT an einem Taster kann dazu dienen, den µC aufzuwecken. Zur
Entprellung ist PCINT ungeeignet.
P.S.
Warum fängst Du plötzlich an zu schreien? Kennst Du Terry Pratchett?
Buna-Pelzer schrieb:> Habt ihr eventuell außer 8 gelassen, daß wenn der Taster auf Masse> zieht es Störimpulse sehr schwer haben, auf der dann auf GND liegenden> Leitung aufzutreten?
Wenn beide Leitungen verdrillt und abgeschirmt vom Taster direkt zum MC
gehen, ist eine Störung unwarscheinlich.
Aber oft kriegt der Taster seinen GND auf anderem Wege und dann kann
sich induktiv oder über eine Erdschleife sehr wohl eine Störung
einkoppeln.
Und eine symmetrische Entprellung (beide Flanken) macht die Software
sogar einfacher.
Frank M. schrieb:> Du hast mich falsch verstanden. Ich halte es generell nicht für> sinnvoll, Tasten durch PCINTs zu entprellen - egal, ob dieser PCINT von> einer zusätzlichen Timer-ISR "kontrolliert" wird oder nicht.
"generell nicht sinnvoll" Starkertobak den Du da Ablässt!
Frank M. schrieb:> Nein, die bessere Idee ist, nur den Timer zu nehmen und auf den PCINT> zu verzichten.
Deswegen schrieb ich "wenn nötig"!
Aber es ist meist(ich mach nur 8Bit!) weder komplizierter noch
aufwendiger einen Int, zu nutzen. Kost halt einen Int. mehr, bringt aber
abisserl Rechenzeit :)
Frank M. schrieb:> Ein Interrupt kann keine Taste "bedienen", das kann nur Dein Finger.
Das lass ich einfach mal so stehen :)
> Ein PCINT an einem Taster kann dazu dienen, den µC aufzuwecken.
Oder nur die Prozedur die die Tastatur bedient :P
> Zur Entprellung ist PCINT ungeeignet.
Hmm, eigentlich besitzt Du die Erkenntnis ja schon, nur anwenden musst
Du sie noch.
Frank M. schrieb:> P.S.> Warum fängst Du plötzlich an zu schreien? Kennst Du Terry Pratchett?
Nein, ich liebe Ihn :)
Wie so?
MaWin schrieb:>> TASTEN PER INTERRUPT ZU BEDIENEN IST NICHTS BÖSES!!!>> Doch. Da kannst du rumschreien wie du willst.
Tja, das befürchte ich leider auch :{
Teo Derix schrieb:> Frank M. schrieb:>> Zur Entprellung ist PCINT ungeeignet.> Hmm, eigentlich besitzt Du die Erkenntnis ja schon, nur anwenden musst> Du sie noch.
Ich benutze keinen PCINT zur Entprellung. Wie kommst Du auf dieses
schmale Brett?
>> Warum fängst Du plötzlich an zu schreien? Kennst Du Terry Pratchett?> Nein, ich liebe Ihn :)> Wie so?
Multiple exclamation marks... den Rest findest Du über Google ;-)
Teo Derix schrieb:> Und noch was:> TASTEN PER INTERRUPT ZU BEDIENEN IST NICHTS BÖSES!!!
Naja, böse nicht, aber in den allermeisten Fällen deutet es schlicht auf
Murks hin. Bestenfalls, wenn es um Sleep-Modi geht, lasse ich mal für
eine Flanke einen Pinchange-Interrupt für einen Taster als sinnvoll
gelten.
> (zumindest wenn man weiß was man tut)
Das trifft auf gut 99% der hier allwöchentlich in zigfach Varianten
erscheinenden ISR-Entprell-Erfindungen nicht zu.
Um es kurz zu fassen: so ein schnarchlangsames Signal wie ein
manuell betätigter Taster oder Schalter braucht in einem "normalen"
Programm (ohne Sleep, Powersave usw.) niemals einen Interrupt. Falls
doch, dann ist die Programmstruktur falsch.
Also wenn ich mir die neueren Threads so ansehe, man kann genauso gut
gegen ne Wand reden:
"Nein, keine Interrupts."
"Nein, keine Delays."
"Nein, nicht anfassen, die Herdplatte ist heiß."
Jeder will sich erstmal unbedingt selber die Finger verbrennen.
Buna-Pelzer schrieb:> Habt ihr eventuell außer 8 gelassen, daß wenn der Taster auf Masse> zieht es Störimpulse sehr schwer haben, auf der dann auf GND liegenden> Leitung aufzutreten?
Ich bin deiner Meinung.
Aber in den letzen Tagen gab es da auch einen Thread, bei dem die
Entprellung wunderbar funktionierte ausser wenn er seinen Lötkolben
aussteckt. Irgendwas ist da passiert, was die Entprellung ausser Tritt
brachte.
Peter Dannegger schrieb:> "Nein, nicht anfassen, die Herdplatte ist heiß."> Jeder will sich erstmal unbedingt selber die Finger verbrennen.
Wenn's dem Erkenntnisgewinn dient ...
PS: So uninteressant ist dieser Thread nun auch wieder nicht
> Du hast mich falsch verstanden. Ich halte es generell nicht> für sinnvoll, Tasten durch PCINTs zu entprellen - egal, ob> dieser PCINT von einer zusätzlichen Timer-ISR "kontrolliert"> wird oder nicht.
Ich denke, man muss zu Michals Code auch etwas mal ganz klar sagen:
Die Entprellung selbst wird NICHT vom PCINT durchgeführt. Die
Entprellung macht der Timer Interrupt. Der PCINT ist nur Zulieferer für
den Timer Interrupt.
Von daher sind Aussagen wie "man braucht nur einen PCINT und ein
zusätzlicher Timer wäre eventuelle eine gute Idee" absolut irreführend.
Denn der Timer ist nicht nur eine gute Idee, der Timer ist der
Hauptakteur in diesem ganzen Spiel. Der PCINT ist die zusätzliche
Komponente!
Womit wir mehr oder weniger wieder am Ausgangspunkt der These angelangt
sind, der da lautete: Polling ist keine brauchbare Methode um Tasten
abzufragen.
Blöd nur, dass die präsentierte Alternative genau das macht: Polling.
Lothar Miller schrieb:> Naja, böse nicht, aber in den allermeisten Fällen deutet es schlicht auf> Murks hin.
Das ist wohl der grösste Blödsinn den ich hier je von Dir gesehen hab!
Ein sauber und mit Verstand geschriebener Interrupt ist was feines, egal
von was o. wem er ausgelöst wird.
Das eigentlich schlimme daran ist, das es so simpel ist das es keiner
kapieren will, weil ja ein Interrupt eine so hoch komplexe Sache ist :(
> Bestenfalls, wenn es um Sleep-Modi geht, lasse ich mal für> eine Flanke einen Pinchange-Interrupt für einen Taster als sinnvoll> gelten.
Wie gut das mir das am Ars... vorbei gehen kann was DU gelten lässt o.
nicht :D
@Karl Heinz:
Ich hab mir den Code von Michael nicht angesehen und deshalb auch nie
Bezug auf ihn genommen.
Teo Derix schrieb:> Lothar Miller schrieb:>> Naja, böse nicht, aber in den allermeisten Fällen deutet es schlicht auf>> Murks hin.> Das ist wohl der grösste Blödsinn den ich hier je von Dir gesehen hab!> Ein sauber und mit Verstand geschriebener Interrupt ist was feines, egal> von was o. wem er ausgelöst wird.> Das eigentlich schlimme daran ist, das es so simpel ist das es keiner> kapieren will, weil ja ein Interrupt eine so hoch komplexe Sache ist :(
Dann zeig mal deine Lösung, die Tastenentprellung/Entstörung ohne Timer
und nur mit einem externen Interrupt macht. Und dann vergleichen wir mal
mit der Timer Lösung, welche davon tatsächlich simpler ist.
Bis jetzt wurde immer wieder nur behauptet, dass es mit einem externen
Interrupt genau so einfach geht. Gesehen hab ich einen derartigen Code
aber noch nie (oder ich erinnere mich nicht mehr - kann auch sein).
Udo Schmitt schrieb:> Ist sinnlos, man kann genausogut mit Fischen über die gute frische Luft> reden...
Auch wieder wahr.
Dann warten wir mal auf den nächsten Entprellthread, bei dem dann wieder
ein "Nimm einen externen Interrupt" kommt. Vielleicht präsentiert ja
dann endlich mal wer eine Lösung, die auch funktioniert und ohne Timer
auskommt. Ist ja nicht so, ich lass mich ja gerne überzeugen, stell es
mir aber schwer vor, denn Prellen ist nun mal ein Vorgang der eine
starke zeitliche Komponente hat. Und für zeitliche Sachen ist ein Timer
die einfachste Lösung.
Teo Derix schrieb:> Lothar Miller schrieb:>> Naja, böse nicht, aber in den allermeisten Fällen deutet es schlicht auf>> Murks hin.> Das ist wohl der grösste Blödsinn den ich hier je von Dir gesehen hab!
Du reisst meine Aussage aus dem Kontext. Das ist billig.
Ich habe mich ausdrücklich auf diese Behauptung bezogen:
>>> TASTEN PER INTERRUPT ZU BEDIENEN IST NICHTS BÖSES!!!
Und gesagt, es sei nicht böse, sondern ungeschickt.
> Ein sauber und mit Verstand geschriebener Interrupt ist was feines, egal> von was o. wem er ausgelöst wird.
Ein simples, ideales und deterministisches System hat keinen
Interrupt. Jeder zusätzliche Interrupt verschlechtert den
Determinismus und macht das Sytem unbeherrschbarer. Das habe ich selber
so erfahren : die stabilsten Programme sind die, in denen die
Hauptschleife schnell genug abläuft, um sämtliche Peripherie bedienen zu
können. Und ab etwa 7 Interruptquellen (die evtl. noch priorisiert
werden können und Querwirkungen haben z.B. RS232-RX wird auf CAN-TX
ausgegeben) wird das System unbeherrschbar.
Sieh dir einfach mal Windows mit seinen 255 Prioritäten an. Es wundert
niemanden, wenn da ab&an mal was abkotzt...
> Ein sauber und mit Verstand geschriebener Interrupt ist was feines, egal> von was o. wem er ausgelöst wird.
Das behauptest du so pauschal?
Ich kann dir Systeme zeigen, die bei passenden EA-Stimuli einfach zäh
und unbrauchbar werden. Die sind vermutlich mit Interrupts auf der EA
geschrieben worden. Zur Erinnerung: früher beim 8051 (tm) realisierte
man gerne per Interrupt einen Einzelschrittbetrieb. Und das war dann
mal echt langsam...
Herbert schrieb:> void KEYBOARD_Interrupt( void )
Das sieht mir nicht wie ein externer, sondern eher wie ein
Timerinterrupt aus.
Ich sehe auch nicht, wo da irgendwas entprellt wird. Beim ersten
Antreffen einer anscheinend gedrückten Taste wird diese gepuffert und
steht ab diesem Zeitpunkt mittels KEYBOARD_GetKey als "gedrückt" zur
Verfügung. Ob der anscheinend gedrückte Zustand der Taste wirklich
stabil ist, wird doch gar nicht überprüft.
Von einer Entprellung beim Loslassen ganz zu schweigen.
Herbert schrieb:> Kritik daran?
Die Tokens heißen nicht [code] sondern [ c]
J.-u. G. schrieb:> Das sieht mir nicht wie ein externer, sondern eher wie ein> Timerinterrupt aus.
Ja, die Variablennamen deuten darauf hin:
1
voidKEYBOARD_Interrupt(void)
2
{
3
KEYBOARD_time[i]=0;
Und natürlich wird diese Zählroutine auch funktionieren. Nur ist sie
wesentlich ausfwändiger als die Routine von PeDa, der mit 2 Bytes 8
Stück Zähler von 0..3 aufbaut...
Michael Sch. schrieb:> 'wenn sich garnix geändert hat, ist das gesamte L_p_s stabil....
Wie oft? In welchem Zeitraum?
Michael Sch. schrieb:> Initialisierung muss natürlich sein. Der Last_pins_state wird sonst erst> NACH der ersten Änderung aktualisiert und korrekt ausgewertet. shit..> :-P :-)>> Last_pins_state = Pinb
Damit gehts.
Für 1-0-1:
# cc -Wall debounce.c -o debounce && ./debounce
1: 0x01
2: 0x01
3: 0x01
Für 0-1-0:
# cc -Wall debounce.c -o debounce && ./debounce
1: 0x00
2: 0x00
3: 0x00
Der Störimpuls scheint tatsächlich unterdrückt zu werden.
Wenn ich aber Deine nunmehr zum X-ten Male modifizierten ISRs auch noch
aus dem letzten Beitrag von Dir übernehme, kommt das raus für 1-0-1:
# cc -Wall debounce.c -o debounce && ./debounce
1: 0x01
2: 0x00
3: 0x01
D.h. der Störimpuls wird jetzt früher als Tastendruck erkannt :-)
Für 0-1-0:
# cc -Wall debounce.c -o debounce && ./debounce
1: 0x00
2: 0x00
3: 0x00
Du hast es also durch die Änderung der ISRs verschlimmbessert.
Ausserdem ist die Zeile
Deb_pinb = 0
Unsinn. Zwei Zeilen darunter übernagelst Du die Variable wieder.
Du hast die ganze Zeit getönt, dass bei Dir die Kombination von
PCINT-ISR + Timer-ISR schon gaaaanz lange stabil(!) läuft, kommst hier
aber alle paar Minuten mit einer neuen Lösung, an der Du dann wieder neu
rumbastelst.
Findest Du das nicht seltsam?
Lothar Miller schrieb:> die stabilsten Programme sind die, in denen die> Hauptschleife schnell genug abläuft, um sämtliche Peripherie bedienen zu> können.
Genau das ist der Knackpunkt, das Main muß auch im Worst-Case schnell
genug sein!
Braucht ein Maindurchlauf nur einen Tick zu lange, geht eben das Byte
der UART unwiederbringlich verloren, welches sonst der UART-Interrupt
bequem in seinen FIFO geschrieben hätte.
Ohne Interrupts gehen also nur sehr einfache Aufgaben und mit
überdimensionierter CPU.
Mit Interrupts muß das Main dagegen nur im Mittel schnell genug sein.
Der Interrupt verringert drastisch die CPU-Last bzw. die gleiche CPU
kann viel mehr Aufgaben erledigen.
Natürlich muß man die Interruptlast abschätzen und das geht bei Timern
oder Datenübertragung ganz einfach, da man ja die Bitrate bzw. das
Timerintervall selber festlegt.
Ein Sonderfall sind externe Interrupts von irgendwelchen Leitungen,
damit kann man die CPU im Störungsfall totblockieren. Daher sind diese
wirklich nur bei Bedarf und mit Bedacht einzusetzen.
Man kann dann im Interrupt einen Zähler aufsetzten, der mit einem Timer
rückgesetzt wird. Wird er das nicht rechtzeitig, ist die Zahl der
Ereignisse zu hoch und der externe Interrupt disabled sich selbst und
setzt ein Fehlerflag. Das Main kann nun wieder ran und den Fehler
behandeln.
Herbert schrieb:> J.-u. G. schrieb:>> Ich sehe auch nicht, wo da irgendwas entprellt wird.>> wird mit der keyboard.h besser erkenntlich:
Selbst dann würde ich hier
1
if(KEYBOARD_time[i]==1)
nicht gleich bei 1 akzeptieren, sondern auf 3 oder 4 gehen.
Dein Code hängt momentan stark davon ab, dass
> CLOCK_RegisterCallbackFunction( KEYBOARD_Interrupt, MSECOUND );
MSECOND länger als die längste zu erwartende Prellzeit ist.
Karl Heinz Buchegger schrieb:> Dann zeig mal deine Lösung, die Tastenentprellung/Entstörung ohne Timer> und nur mit einem externen Interrupt macht. Und dann vergleichen wir mal> mit der Timer Lösung, welche davon tatsächlich simpler ist.
Jetz geht's los man, hakt's bei Dir nu völlig?
Lies meine Beiträge wenigstens bevor Du sie zerreißt!
Ich habe hier in mehreren Beiträge deutlichst versucht klar zu
machen das die Interuptlösung ohne Timer (o. adäquates Zeitglied) keine
sinnvolle Tastenentprellung zu realisieren ist. Jegliche Lösung ohne
Timer ist letztlich auch nur ein Zeitglied, nur ziemlich umständlich
und sich nicht wirklich "Betriebssicher".
Teo Derix schrieb:> Tasten entprellten mit nem µC heißt nichts anderes als die Taste niemals> schneller abfragen als die Prellzeit es erlaubt!
Heißt Timer einbauen!
Teo Derix schrieb:> Frank M. schrieb:>> Pin-Change Plus Timer-Interrupt finde ich persönlich übertrieben.> Einen durch Taster o. sonst was Prellendes, ausgelösten Int. ohne> Kontrolle laufen zu lassen ist Schwachsinn, da es alleine schon selten> sinnvoll ist auf das Prellen eines Tasters zu reagieren, abgesehen aller> sonstigen Nachteile!> Also wenn schon Int. nötig, dann ist ein zusätzlicher Timer meist eine> sehr gute Idee!
War etwas ironisch ausgedrückt. Heißt, eigentlich zwingen notwendig.
Und noch mal wen Du hier meine Beiträge angreifst dann lese sie
gefälligst vorher!
Am Verständnis wird's hoffentlich nicht liegen.