Zu dem Thema hab ich so viel im Netz gefunden, das ich fast nicht mehr
weiss was ich nun einsetzen soll...
Klar ist wohl, das man nicht mit delay() arbeiten sollte um die
Prellzeit abzuwarten, denn die Main-Loop sollte in kurzer Zeit
durchlaufen werden können. Zudem sollte diese Durchlaufzeit möglichst
konstant sein.
Um EMV und sonstige Geister fern zu halten arbeiten die allermeisten mit
dem internen Pullup und ziehen den Taster gegen GND.
Dennoch sind viele Lösungen unglaublich kompliziert. Ich hätte mir das
viel einfacher vorgestellt:
Sobald man einen Tastendruck erkennt (Pin auf LOW) gilt diese als
gedrückt. Danach setzt man das lesen weiterer Tastendrücke für 50-100ms
aus sodass praktische jede Prellzeit vorüber ist.
Wechselt der Zustand anschließend wieder auf HIGH gilt die Taste als
losgelassen. Auch hier setzt man weitere Lesezugriffe für eine gewisse
Zeit aus.
Die Wartezeit könnte man mittels LogicAnalyzer, Oszi oder evtl. auch
einer einfachen Testsoftware auf dem Arduino bei Bedarf für den
jeweiligen Taster ermitteln (kann ja auch ein Tilt-Sensor oder sowas
sein). Ich habe mal 50 ms angenommen, aber auch 100 ms wären noch ok. So
schnell drückt kein Mensch, sodass man sicher keinen Tastendruck
"verliert".
Test-Aufbau: Taster am D2 vom Arduino (Atmega328) und gegen GND.
Mein erster Code um einfach nur den entprellten Zustand an eine LED
weiterzugeben:
1
#define BUTTON_BOUNCE_TIME 50
2
#define BUTTON_PIN 2
3
#define LED_PIN 4
4
5
int button_pushed = 0;
6
long ignore_until = 0;
7
8
void setup()
9
{
10
pinMode(BUTTON_PIN, INPUT_PULLUP);
11
pinMode(LED_PIN, OUTPUT);
12
digitalWrite(LED_PIN, LOW);
13
}
14
15
void loop()
16
{
17
if (millis() > ignore_until) {
18
int button_read = digitalRead(BUTTON_PIN);
19
if (button_read == LOW) { /* button was first pushed, or still hold down */
20
button_pushed = 1;
21
}
22
else if (button_pushed == 1 && button_read == HIGH) { /* button was released */
23
button_pushed = 0;
24
}
25
ignore_until = millis() + BUTTON_BOUNCE_TIME;
26
}
27
28
/* do some other funny stuff...
29
* delay() is allowed, but beware not to wait too long or you will miss button events
30
*/
31
if (button_pushed) {
32
digitalWrite(LED_PIN, HIGH);
33
} else {
34
digitalWrite(LED_PIN, LOW);
35
}
36
}
Und hier der Code für einen einfachen Tipp-Schalter (Toggle):
1
#define BUTTON_BOUNCE_TIME 50
2
#define BUTTON_PIN 2
3
#define LED_PIN 4
4
5
int button_toggle = 0;
6
int button_pushed = 0;
7
long ignore_until = 0;
8
int led_toggle = 0;
9
10
void setup()
11
{
12
pinMode(BUTTON_PIN, INPUT_PULLUP);
13
pinMode(LED_PIN, OUTPUT);
14
digitalWrite(LED_PIN, LOW);
15
}
16
17
void loop()
18
{
19
if (millis() > ignore_until) {
20
int button_read = digitalRead(BUTTON_PIN);
21
if (button_pushed == 0 && button_read == LOW) { /* button was first pushed, or still hold down */
22
button_pushed = 1;
23
button_toggle = !button_toggle;
24
}
25
else if (button_pushed == 1 && button_read == HIGH) { /* button was released */
26
button_pushed = 0;
27
}
28
ignore_until = millis() + BUTTON_BOUNCE_TIME;
29
}
30
31
/* do some other funny stuff...
32
* delay() is allowed, but beware not to wait too long or you will miss button events
33
*/
34
if (button_pushed) {
35
if (button_toggle != led_toggle) {
36
led_toggle = button_toggle;
37
digitalWrite(LED_PIN, led_toggle);
38
}
39
}
40
}
So, und nun könnt ihr meinen Code in der Luft zereissen und mir klar
machen das es sooo einfach nun wirklich nicht geht! Bin schon sehr
gespannt... ;-)
Olli Z. schrieb:> Um EMV und sonstige Geister fern zu halten arbeiten die allermeisten mit> dem internen Pullup und ziehen den Taster gegen GND.
Nö.
Der Pullup ist halt schon da. Warum also extra ein weiteres Bauteil
einlöten.
Peter D. schrieb:> Nö.> Der Pullup ist halt schon da. Warum also extra ein weiteres Bauteil> einlöten.
ich ziehe externe pullup aber immer vor,
1. sind sie immer vorhanden und können nicht je nach Modell abgeschaltet
werden und
2. kann ich den Strom bestimmen, bzw. wie fest die Ports angebunden sind
um sich nicht von jedem Leitungshuster in die Irre zu führen lassen.
1mA hat sich bei mir als sicher und gut herausgestellt, 3,3k bei 3,3V
und 4,7k bei um 5V
LG jar
PS bei einem Portextender I2C mit PCF/PCH 8574 und deine bulletproof
Entprellroutine habe ich auf externe R verzichtet, aber die Taster und
der I2C sind sehr kurz angebunden.
Olli Z. schrieb:> Dennoch sind viele Lösungen unglaublich kompliziert.
Und was bitte ist dein code ? Noch komplizierter ?
Der setup-Code ist halt wie er ist.
Der funny stuff auch.
Die millis-Funktion ist in Ordnung, eine Art delay ohne zu warten.
Bleibt
1
int button_read = digitalRead(BUTTON_PIN);
2
if (button_pushed == 0 && button_read == LOW) { /* button was first pushed, or still hold down */
3
button_pushed = 1;
4
button_toggle = !button_toggle;
5
}
6
else if (button_pushed == 1 && button_read == HIGH) { /* button was released */
7
button_pushed = 0;
8
}
der auch anders geht
1
button_pushed = button_read;
2
button_read = digitalRead(BUTTON_PIN);
3
button_pushed = button_read & ~button_pushed;
und man sollte aus dem button_read und button_pushed bloss ein char
machen, man nutzt eh nur 1 bit. Der Code kann allerdings auch 8 Taster
gemeinsam entprellen.
> Sobald man einen Tastendruck erkennt (Pin auf LOW) gilt diese als> gedrückt. Danach setzt man das lesen weiterer Tastendrücke für 50-100ms> aus sodass praktische jede Prellzeit vorüber ist.
Richtig, allerdings mit 10ms.
http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29.1
Joachim B. schrieb:> 1mA hat sich bei mir als sicher und gut herausgestellt, 3,3k bei 3,3V> und 4,7k bei um 5V
Das sind absolute Mindestwerte. Besser ist es, 10 - 50 mA zu nehmen,
damit die Kontakte immer gut freigebrannt sind und der Staub verdampfen
kann!
Olli Z. schrieb:> Sobald man einen Tastendruck erkennt (Pin auf LOW) gilt diese als> gedrückt. Danach setzt man das lesen weiterer Tastendrücke für 50-100ms> aus sodass praktische jede Prellzeit vorüber ist.
Interessante Idee, aber so richtig entprellen ist das erstmal nicht.
Ich lese einen Pin zyklisch ein mit meinem Scheduler, also etwa einmal
pro ms.
Oder auch jedesmal in der loop() beim Arduino.
Jedesmal wenn der Zustand gedrückt entspricht lasse ich einen Zähler
hoch zählen, ist der Taster nicht betätigt, wird der Zähler runter
gezählt.
Erreicht der Zähler einen Schwellwert gilt der Taster als betätigt.
Je nach gewünschter Funktion wird das ganze dann mit einer
Zusatz-Variable verriegelt damit keine weitere Betätigung erkannt wird,
oder auch nicht.
Das kann man dann auch so gestalten, dass anschliessend der Taster für
eine gewisse Zeit losgelassen werden muss, bevor eine neue Auslösung
möglich wird.
Solange das beim Betätigen flattert passiert also nichts, der Zähler
wird rauf und runter gezählt.
Wird der Schwellwert erreicht war für die eingestellte Zeitdauer der
Taster betätigt, die bis dahin verstrichene Zeit vielleicht durch das
Prellen ein wenig länger.
Kein Delay.
MaWin schrieb:> button_pushed = button_read;> button_read = digitalRead(BUTTON_PIN);> button_pushed = button_read & ~button_pushed;
Nach lesen der Lektüre im Link (die ich uneingeschränkt empfehlen kann)
bin ich wieder etwas schlauer. Leider hab ich Bitwise-Operatoren nicht
so drauf und daher wollte ich auch meinen Code für Anfänger lesbar
halten. Das ganze kann man vermutlich á la Perl so schreiben das es
hocheffizient ist, aber keine Sau mehr kapiert wie das arbeitet ;-)
Das mit dem 'char' anstelle 'int' verstehe ich, aber auch hier ging es
nicht um Effizienz.
Würdest Du bitte die Funktionsweise der Zeilen mal erklären?
Ja, wie ich schon in der Einleitung schrieb gibt es hier zahllose und
immer sehr einfallsreiche Methoden einen Tastendruck ordentlich zu
erkennen.
Die Zählermethode ist ja eigentlich ein Schmitt-Trigger mit Hysterese
per Software.
Meine Methode entspricht eher einem RS Flipflop.
Dabei ist das Betätigungsmuster doch immer gleich. Sobald der Taster
unten ist soll etwas passieren. Solange man gedrückt hält soll es
entweder so sein als hätte man die Taste wiederholt schnell gedrückt,
oder es soll nach einer gewissen Haltezeit etwas (anderes) passieren.
Der Moment des loslassens wird meist nicht ausgewertet.
Dann gäbe es noch den Doppelklick, also zwei Tastendrücke innerhalb
einer gewissen Zeit, zu nennen. Alles weitere sind Kombinationen und
Sequenzen mehrerer Tasten.
Hallo,
Matthias mein mit Ich schau zweimal und dann ist es wahr', dass 4 malig
das selbe Ergebnis vorliegen muss, als dann wird es als ein Ereignis
erkannt.
Karl M. schrieb:> Matthias mein mit Ich schau zweimal und dann ist es wahr', dass 4 malig> das selbe Ergebnis vorliegen muss, als dann wird es als ein Ereignis> erkannt.
Nö - nicht 4 mal, sondern eben 2 mal. Das meinte ich schon so.
Copy&Paste das ASM in Studio 4 und lass den Simulator laufen, wenn du es
nicht glaubst.
Matthias S. schrieb:> Nö - nicht 4 mal, sondern eben 2 mal.
Nicht "nö"!
> Dude schrieb:>> Mit nem timerinterrupt die Taster Pollen....das reicht völlig aus.Olli Z. schrieb:> Gibt doch bitte mal ein Beispiel.
Damit fordert er den "Dude" auf, ein Beispiel zu geben -nicht
irgendwelche anderen Leute, zum 200x die Routine von Peter Danegger zu
zitieren.
SCNR
Paul