Forum: Mikrocontroller und Digitale Elektronik Tastenentprellung


von Ismael T. (paul2_0)


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

> 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.

von Teo D. (teoderix)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Ismael Touomo schrieb:
> Ich habe noch nie eine Tastenentprellung mit
> extern Interrupts un Timer realisier

Ich auch nicht.

von Peter D. (peda)


Lesenswert?

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.

von Matthias (Gast)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

Schon mal hier nachgeschaut? Entprellung

...

von Stefan (Gast)


Lesenswert?

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.

von Stefan (Gast)


Lesenswert?

Kleine Korrektur:

5) Wenn A nicht gleich B ist, dann setze A=B und wiederhole bei 2). 
(nicht bei 3!

von Hannes L. (hannes)


Lesenswert?

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

...

von Basti (Gast)


Lesenswert?

10K +100nf - da prellt nix mehr

von Peter D. (peda)


Lesenswert?

Basti schrieb:
> 10K +100nf - da prellt nix mehr

Kannst Du das mal in C schreiben?

von Teo D. (teoderix)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

> 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.

von Teo D. (teoderix)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von J. T. (chaoskind)


Lesenswert?

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

von Frank M. (frank_m35)


Lesenswert?

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
volatile BOOL buttonPressed;
2
volatile BYTE buttonCount;
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.

von Touomo Tchouamo (Gast)


Lesenswert?

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 
:)

von J. T. (chaoskind)


Lesenswert?

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.

von Michael S. (mikel_x)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Uwe (de0508)


Lesenswert?

Hallo Michael,

jetzt bin ich auf deine funktionierende Lösung gespannt.

Entweder als Ablauf-, Zustands- oder pseudo Code gespannt.

von Udo S. (urschmitt)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Michael S. (mikel_x)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von MaWin (Gast)


Lesenswert?

> 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.

von Karl H. (kbuchegg)


Lesenswert?

> ...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.

von Michael S. (mikel_x)


Lesenswert?

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.... ;-)

von Karl H. (kbuchegg)


Lesenswert?

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.

von Michael S. (mikel_x)


Lesenswert?

@Mawin

Hey, hier geht es um sachliche Fakten... nicht um Religion... ;-)

von Michael S. (mikel_x)


Lesenswert?

Probleme... ? Sprich dich aus, ich möchte mitlachen bei dem schönen 
Wetter... :-)

von Zittermann (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Michael S. (mikel_x)


Lesenswert?

@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....

von Karl H. (kbuchegg)


Lesenswert?

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

von Michael S. (mikel_x)


Lesenswert?

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... ;-)

von Karl H. (kbuchegg)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
static volatile uint8_t     PINB;   // SIMULIERTER Pin
5
static volatile uint8_t     changed_pins_sum;
6
static volatile uint8_t     last_pins_state;
7
static volatile uint8_t     deb_pinb;
8
9
// Pinchange_Isr  triggert bei JEDER Flankenänderung
10
void pinchange_ISR(void)
11
{
12
    uint8_t         changed_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
void timer_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
int main ()
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
    return 0;
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.

von Michael S. (mikel_x)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

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

von Malte S. (maltest)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Udo S. (urschmitt)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank M. (frank_m35)


Lesenswert?

@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!

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
int main ()
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
    return 0;
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.

von Frank M. (frank_m35)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von Michael S. (mikel_x)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
void timer_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.

von Karl H. (kbuchegg)


Lesenswert?

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

von Malte S. (maltest)


Lesenswert?

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?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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:
1
int main ()
2
{
3
    PINB = 1;
4
    timer_ISR();
5
    timer_ISR();
6
    timer_ISR();
7
    timer_ISR();
8
    timer_ISR();
9
    printf ("1: 0x%02x\n", deb_pinb);
10
11
    // jetzt kurzer Puls:
12
#if 1
13
    PINB = 0;
14
    pinchange_ISR();
15
    PINB = 1;
16
    pinchange_ISR();
17
#endif
18
19
    timer_ISR();
20
    printf ("2: 0x%02x\n", deb_pinb);
21
    timer_ISR();
22
    printf ("3: 0x%02x\n", deb_pinb);
23
24
    return 0;
25
}

Ausgabe bleibt dieselbe:
1
# cc -Wall debounce.c -o debounce && ./debounce
2
1: 0x00
3
2: 0x00
4
3: 0x01

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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 ....

von MaWin (Gast)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Udo S. (urschmitt)


Lesenswert?

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!

von Buna-Pelzer (Gast)


Lesenswert?

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 Michael S. (mikel_x)


Lesenswert?

Auf ein Neues...

'*********************
 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 = Deb_pinb AND Changed_pins_sum
  Changed_pins_sum = Changed_pins_sum XOR &HFF
  Changed_pins_sum = Changed_pins_sum AND Last_pins_state
  Deb_pinb = Deb_pinb OR Changed_pins_sum

  Changed_pins_sum = 0

 Return

von Udo S. (urschmitt)


Lesenswert?

Michael Sch. schrieb:
> Auf ein Neues...

Was hilft das eigentlich dem TO, der ein kleines Programm in C möchte?

von Michael S. (mikel_x)


Lesenswert?

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. ;-)

von Malte S. (maltest)


Lesenswert?

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.

von Michael S. (mikel_x)


Lesenswert?

Ach Malte... Die angepassten Namen kommen nachher. Aber schön, daß du 
auch was "entdeckt" hast, was du nicht verstehst... :-)

von Malte S. (maltest)


Lesenswert?

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.

von Frank M. (frank_m35)


Lesenswert?

@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.

von Michael S. (mikel_x)


Lesenswert?

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... ;-)

von Michael S. (mikel_x)


Lesenswert?

@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.

von Buna-Pelzer (Gast)


Lesenswert?

@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

von Malte S. (maltest)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael Sch. schrieb:
> Auf ein Neues...

Übersetzt in C:
1
#include <stdint.h>
2
#include <stdio.h>
3
4
static volatile uint8_t     PINB;   // SIMULIERTER Pin
5
static volatile uint8_t     changed_pins_sum;
6
static volatile uint8_t     last_pins_state;
7
static volatile uint8_t     deb_pinb;
8
9
// Pinchange_Isr  triggert bei JEDER Flankenänderung
10
void pinchange_ISR(void)
11
{
12
    uint8_t         changed_pins;
13
14
    changed_pins = last_pins_state ^ PINB;
15
    last_pins_state = PINB;
16
    changed_pins_sum |= changed_pins;
17
}
18
19
// Timer_isr... 19,7ms Periode...
20
void timer_ISR(void)
21
{
22
    deb_pinb = deb_pinb & changed_pins_sum;
23
    changed_pins_sum = changed_pins_sum ^ 0xff;
24
    changed_pins_sum = changed_pins_sum & last_pins_state;
25
    deb_pinb = deb_pinb | changed_pins_sum;
26
27
    changed_pins_sum = 0;
28
}
29
30
int main ()
31
{
32
    PINB = 1;
33
    timer_ISR();
34
    timer_ISR();
35
    timer_ISR();
36
    timer_ISR();
37
    timer_ISR();
38
    printf ("1: 0x%02x\n", deb_pinb);
39
40
    // jetzt kurzer Puls:
41
#if 1
42
    PINB = 0;
43
    pinchange_ISR();
44
    PINB = 1;
45
    pinchange_ISR();
46
#endif
47
48
    timer_ISR();
49
    printf ("2: 0x%02x\n", deb_pinb);
50
    timer_ISR();
51
    printf ("3: 0x%02x\n", deb_pinb);
52
53
    return 0;
54
}

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".

von Teo D. (teoderix)


Lesenswert?

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)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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?

von MaWin (Gast)


Lesenswert?

> TASTEN PER INTERRUPT ZU BEDIENEN IST NICHTS BÖSES!!!

Doch. Da kannst du rumschreien wie du willst.

von Peter D. (peda)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?

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 :{

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Darwin Award (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Teo D. (teoderix)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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).

von Udo S. (urschmitt)


Lesenswert?

Ist sinnlos, man kann genausogut mit Fischen über die gute frische Luft 
reden...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

von Herbert (Gast)


Lesenswert?

Würde mich interessieren, was ihr von dieser Lösung mit Interrupt 
haltet:
1
/***************************************************************************
2
 *            key.c
3
 *
4
 *  Sun Sep 11 17:18:16 2011
5
 *  Copyright  2011  Dirk Broßwick
6
 *  <sharandac@snafu.de>
7
 ****************************************************************************/
8
9
/*
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 * 
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Library General Public License for more details.
19
 * 
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
23
 */
24
25
#include <stdio.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <stdlib.h>
29
#include <avr/io.h>
30
#include <avr/pgmspace.h>
31
#include "config.h"
32
33
/**
34
 * \ingroup hardware
35
 * \addtogroup KEYBOARD Interface um ein Tasten am Controller einzubinden (keyboard.c).
36
 *
37
 * @{
38
 */
39
40
/**
41
 * \file
42
 *
43
 * \author Dirk Broßwick
44
 */
45
46
#if defined( KEYBOARD )
47
48
#include "keyboard.h"
49
#include "hardware/gpio/gpio_core.h"
50
#include "system/buffer/fifo.h"
51
#include "system/clock/clock.h"
52
53
#define    KEYBOARD_INVERSE      // Was macht INVERSE ???
54
//#define   KEYBOARD_PULLUP        // sonst Taster als Active Low mit externem Pull-Up
55
const char   KEYBOARD_DATA[] PROGMEM = { PORTF_0, PORTF_1, PORTF_2, PORTF_3 };
56
const char   KEYBOARD_CHAR[] PROGMEM = { 's', 'c', 'f', 'e' };
57
char     KEYBOARD_time[ sizeof ( KEYBOARD_DATA ) ];
58
59
char KEYBOARD_Buffer[ KEYBOARD_Bufferlen ];
60
int KEYBOARD_fifo;
61
62
/**
63
 * \brief Initialisiert die Tasten.
64
 * \param  NONE
65
 * \return  NONE
66
 */
67
void KEYBOARD_init( void )
68
{
69
  int i;
70
  for ( i = 0 ; i < sizeof( KEYBOARD_DATA ) ; i++ )
71
  {
72
    GPIO_setdirection( GPIO_IN , pgm_read_byte( &KEYBOARD_DATA[ i ] ) );
73
#if defined( GPIO_IN_PULLUP )
74
    GPIO_setPullUp( pgm_read_byte( &KEYBOARD_DATA[ i ] ) );
75
#endif
76
    KEYBOARD_time[ i ] = 0;
77
  }
78
  
79
  KEYBOARD_fifo = Get_FIFO( KEYBOARD_Buffer, KEYBOARD_Bufferlen );
80
  CLOCK_RegisterCallbackFunction( KEYBOARD_Interrupt, MSECOUND );
81
}
82
83
/**
84
 * \brief Die Interruptroutine zur Auswerten der Tasten.
85
 * \param  NONE
86
 * \return  NONE
87
 */
88
void KEYBOARD_Interrupt( void )
89
{
90
  int i;
91
92
  for( i = 0 ; i < sizeof( KEYBOARD_DATA ) ; i++ )
93
  {
94
    // checken ob Taster gedrueckt, wenn ja, Timer hoch zaehlen sonst auf 0 setzen
95
    if ( GPIO_getPin( pgm_read_byte( &KEYBOARD_DATA[ i ] ) ) )
96
    {
97
#if defined( KEYBOARD_INVERSE )
98
      KEYBOARD_time[ i ] = 0;
99
#else
100
      KEYBOARD_time[ i ]++;      
101
#endif
102
    }
103
    else
104
    {
105
#if defined( KEYBOARD_INVERSE )
106
      KEYBOARD_time[ i ]++;
107
#else
108
      KEYBOARD_time[ i ] = 0;      
109
#endif
110
    }
111
112
    // wenn gedrueckte Taste entdeckt, dann Zeichen ab in den Puffer
113
    if ( KEYBOARD_time[ i ] != 0 )
114
    {
115
      if ( KEYBOARD_time[ i ] == 1 )
116
      {
117
        Put_Byte_in_FIFO ( KEYBOARD_fifo, pgm_read_byte( &KEYBOARD_CHAR[ i ] ) );
118
      }
119
      // Wenn Taste laenger gedrueckt, warten auf DELAY-Wert
120
      else if ( KEYBOARD_time [ i ] == KEYBOARD_DELAY )
121
      {
122
        // Taste speichern
123
        Put_Byte_in_FIFO ( KEYBOARD_fifo, pgm_read_byte( &KEYBOARD_CHAR[ i ] ) );
124
        // Vom aktuellen Wert den Repeatwert abziehen
125
        KEYBOARD_time [ i ] = KEYBOARD_time[ i ] - KEYBOARD_REPEAT;
126
      }
127
    }
128
  }
129
}
130
131
/**
132
 * \brief Holt eine Tasten aus den Tastenpuffer
133
 * \param  NONE
134
 * \return  Keyvalue or EOF
135
 */
136
int KEYBOARD_GetKey( void )
137
{
138
  int retval = EOF;
139
  
140
  if ( Get_Bytes_in_FIFO ( KEYBOARD_fifo ) != 0 )
141
    retval = Get_Byte_from_FIFO( KEYBOARD_fifo );
142
143
  return( retval );
144
}
145
146
/**
147
 * \brief Löscht den Tastenpuffer
148
 * \param  NONE
149
 * \return  NONE
150
 */
151
void KEYBOARD_Flush( void )
152
{
153
  Flush_FIFO( KEYBOARD_fifo );
154
}
155
156
#endif // KEYBOARD
157
158
/**
159
 * @}
160
 */

Kritik daran?

von Michael S. (mikel_x)


Lesenswert?

Initialisierung muss natürlich sein. Der Last_pins_state wird sonst erst 
NACH der ersten Änderung aktualisiert und korrekt ausgewertet. shit.. 
:-P :-)
1
.
2
.
3
4
Last_pins_state = Pinb
5
6
do
7
.
8
loop
9
.
10
.
11
12
'*********************
13
 Pchg_isr:
14
15
  Changed_pins = Last_pins_state Xor Pinb
16
  Last_pins_state = Pinb
17
  Changed_pins_sum = Changed_pins_sum Or Changed_pins
18
19
 Return
20
21
 '********************
22
  Wd_isr:
23
  'wenn sich garnix geändert hat, ist das gesamte L_p_s stabil....
24
  
25
  If Changed_pins_sum = 0 Then
26
   
27
    Deb_pinb = Last_pins_state
28
29
  Else
30
31
     'Ausgabe nochmal vereinfacht
32
    Deb_pinb = 0                                              
33
    Changed_pins_sum = Changed_pins_sum Xor &HFF
34
    Deb_pinb = Changed_pins_sum And Last_pins_state
35
    Changed_pins_sum = 0
36
37
  End If
38
39
 Return

von J.-u. G. (juwe)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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
 void KEYBOARD_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?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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?

von Herbert (Gast)


Lesenswert?

J.-u. G. schrieb:
> Ich sehe auch nicht, wo da irgendwas entprellt wird.

wird mit der keyboard.h besser erkenntlich:
1
/***************************************************************************
2
 *            key.h
3
 *
4
 *  Sun Sep 11 17:18:16 2011
5
 *  Copyright  2011  Dirk Broßwick
6
 *  <sharandac@snafu.de>
7
 ****************************************************************************/
8
9
/*
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 * 
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Library General Public License for more details.
19
 * 
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
23
 */
24
25
#ifndef KEY_BOARD_H
26
  #define KEY_BOARD_H
27
28
  #define  KEYBOARD_Bufferlen  8
29
  #define KEYBOARD_DELAY    50
30
  #define KEYBOARD_REPEAT    5
31
32
  void KEYBOARD_init( void );
33
  void KEYBOARD_Interrupt( void );
34
  int KEYBOARD_GetKey( void );
35
  void KEYBOARD_Flush( void );
36
37
#endif // KEY_BOARD_H

von Peter D. (peda)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?

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.

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.