Hallo Leute, Ich weiß es gibt viele Tutorials zum Taster entprellen jedoch will ich nicht blind was kopieren oder auswendig lernen sondern es selber schreiben und wirklich durchdenken. Meiner Meinung nach ist mein Programm genau das was es sein soll, jedoch leuchtet die LED einfach nicht auf. Schon langsam gebe ich auf. Könnt ihr mal drüberschauen und mir eventuelle einen Denkstoss verpassen? Schaltung ist nur eine LED mit Vorwiderstand auf Pin 7,mehr nicht. Bin Anfänger und beginne eben nur mit ner LED jedoch schreibe ich immer verschiedene Programme dafür (Ext.Interrupt, PWM,..) Das hier wäre mein Code: _____________________________________________ volatile int y=0,x=0,z=0; boolean ledstatus=LOW; void setup() { pinMode(2,INPUT); pinMode(7,OUTPUT); } void loop() { y=digitalRead(2); if(y>0) { x=millis(); if((millis()-x)>50) { if(y>0) { ledstatus=HIGH; } } } else if (y==0) { ledstatus=LOW; } digitalWrite(7,ledstatus); } ____________________________________________________ Pin 2 hat einen Pull Down Widerstand. Bin für jede Kritik dankbar. Lg Stefan
Stefan Mayerhofer schrieb: > x=millis(); > if((millis()-x)>50) So wie ich das sehe ist diese Bedingung nie erfüllt.
:
Bearbeitet durch User
Stefan Mayerhofer schrieb: > x=millis(); > if((millis()-x)>50) > { > if(y>0) > { > ledstatus=HIGH; > } > } > } Sieh Die mal die ersten beiden Zeilen an. x wird der aktuelle Wert von "millis()" zugewiesen. Unmittelbar danach wird geprüft, ob der Wert x um mehr als 50 vom aktuellen Wert von "millis()" abweicht. Wie soll das funktionieren? Dein µC ist nicht so langsam, daß er für zwei unmittelbar aufeinanderfolgende Operationen mehr als 50 Millisekunden benötigt.
Den gleichen Fehler hatte jemand anderes hier schon vor wenigen Tagen. Beitrag "Arduino Millis" Dort findest du auch Korrekturvorschläge.
Komischer Weise wenn ich das Programm am Arduino so stehen lasse für einige Zeit dann leuchte die LED iergendwann mal auf also kommt es doch iergendwie in die if-Abfrage rein. Ich überreisse es einfach nicht :/
> Ich überreisse es einfach nicht
Welches Arduino Modul verwendest du denn?
Wenn es eins mit im µC integriertem USB oder WLAN ist, kann das schon
sein, denn diese unterbrechen den normalen Programmablauf zyklisch um
die Schnittstellen zu bedienen.
Stefan Mayerhofer schrieb: > Komischer Weise wenn ich das Programm am Arduino so stehen lasse für > einige Zeit dann leuchte die LED iergendwann mal auf also kommt es doch > iergendwie in die if-Abfrage rein. Vermutung: wenn millis() zwischen den 2 Abfragen überläuft.
> Vermutung: wenn millis() zwischen den 2 Abfragen überläuft.
Kann auch sein. Wenn die Variable x vom gleichen Typ wäre, wie das
Ergebnis von millis() würde der Überlauf allerdings keine Fehlfunktion
auslösen. Um das zu erklären, muss man sich ganz genau anschauen, was
die Subtraktion in diesem Fall mit den Bits anstellt.
Dietrich L. schrieb: > Vermutung: wenn millis() zwischen den 2 Abfragen überläuft. Bzw. x. Denn es ist ja nur 16 Bit breit und vorzeichenbehaftet, also wird es nach ca. 32 Sekunden negativ.
I know I know, für euch ist mein Problem lustig jedoch ist es für mich zurzeit eine richtige Herausforderung :/
Dann lies den Thread, auf den ich verwiesen habe. Dort steht die Lösung. Falls du den nicht verstehst, melde Doch hier nochmal. Dann müssen wir nämlich ganz unten bei den allerersten Grundlagen anfangen. Die wären: - wann und wie oft wird setup() ausgeführt? - wann und wie oft wird loop() ausgeführt? - was macht millis()? - was ist der Unterschied zwischen einer Schleife und einer Bedingung? - Welche Datentypen stehen zur Verfügung? Das steht aber auch alles in den Arduino Tutorials, man muss sie nur lesen. Die sind schon sehr kurz gehalten, extra für Leute, die nicht gerne lesen.
Stefan Mayerhofer schrieb: > I know I know, für euch ist mein Problem lustig jedoch ist es für mich > zurzeit eine richtige Herausforderung :/ Du willst ja lernen, daher: Ich empfehle, erst einmal ein Flußdiagramm zu zeichnen, wie du dir den Ablauf denkst. Als zweiter Schritt käme dann die Umsetzung in den Code.
Den Thread habe ich gelesen und den verstehe ich, dieser soll eine LED zum BLinken bringen und da speichert man den millis Wert in eine Variable und diese Variable fragt man danach ab und toogelt. Hier kann ich ja den millis Wert nach der if-Abfrage nicht abspeichern weil ja dieser danach viel kleiner ist als der jetzige wenn ich die taste drücke, da komm ich ja immer wieder in die if Abfrage rein du das Entprellen ist weg.
> Hier kann ich ja den millis Wert nach der if-Abfrage nicht > abspeichern weil ja dieser danach viel kleiner ist als der jetzige >> was macht millis()?
Genau, und deswegen kann millis() nicht kleiner werden (angesehen von dem sehr seltenen Überlauf, der aber bei der Subtraktion zum Glück keinen Fehler auslöst). Du willst die LED einschalten, wenn der Taster mindestens 50ms lang gedrückt wurde. Also:
1 | unsigned long sperrzeit=0; |
2 | |
3 | void loop() |
4 | {
|
5 | if (!digitalRead(2)) |
6 | {
|
7 | // Taste wurde losgelassen oder prellt
|
8 | sperrzeit=millis(); |
9 | // LED aus
|
10 | digitalWrite(7,LOW); |
11 | }
|
12 | else if (millis()-sperrzeit > 50) |
13 | {
|
14 | // Taste wurde lange genug gedrückt
|
15 | // LED an
|
16 | digitalWrite(7,HIGH); |
17 | }
|
18 | }
|
Stefan Mayerhofer schrieb: > Den Thread habe ich gelesen.. Ein Entpreller mit dem Code aus: Beitrag "Re: Arduino Millis"
1 | #include <CombieTimer.h> |
2 | |
3 | Combie::Timer::EntprellTimer entprellen(100); // Entpreller Instanz erzeugen |
4 | |
5 | |
6 | const byte taster = 2; |
7 | const byte led = 13; |
8 | |
9 | |
10 | void setup() |
11 | {
|
12 | pinMode(taster,INPUT); |
13 | pinMode(led ,OUTPUT); |
14 | }
|
15 | |
16 | void loop() |
17 | {
|
18 | digitalWrite(led,entprellen(digitalRead(taster))); |
19 | }
|
Ich erwarte nicht, dass du ihn vollständig verstehst. Aber hoffe, dass du etwas daraus mitnehmen kannst. z.B: Das man sich mit komplizierten if, und ihren Bedingungen, selber eine Frikadelle ans Knie nagelt.
> Das man sich mit komplizierten if, und ihren Bedingungen, > selber eine Frikadelle ans Knie nagelt. Ah ja, und was finden wir in der Datei CombieTimer.h? Komplizierte if Bedingungen! Und dann auch noch den kompletten Quelltext in der *.h, das ist definitiv nichts, was man Anfängern empfehlen sollte. Dann wird dort der () Operator überladen, da muss man erstmal drauf kommen! Der TO wollte keine fertige Klasse verwenden, sondern lernen, wie es funktioniert.
Danke dir, Kann ich meinen Code umschreiben, deinen verstehe ich nur teilweise. Bei der else if Abfrage kommt ja kein (digitalRead(2)==HIGH)) , wie soll der dann hier reinkommen. Ich mein es funkt, habs auspobiert, jedoch hab ichs nicht zur Gänze kapiert.
Stefan U. schrieb: > Ah ja, und was finden wir in der Datei CombieTimer.h? Komplizierte if > Bedingungen! 3 IF Bedingungen > if(!abgelaufen) und > if(merker == trigger) > if(timer(entprellzeit)) Das sind drei einfache Bedingungen. Und nicht verschachtelt. Das ist dir also schon zu kompliziert.... Aha, ja... Des weiteren, im Gegensatz zum Code des TE, deutlich benannte Variablen. Stefan U. schrieb: > Und dann auch noch den kompletten Quelltext in der *.h, Was gibts dagegen einzuwenden? Als Arduino User hat man dauernd damit zu tun. Viele Libs sind so aufgebaut. Stefan U. schrieb: > Der TO wollte keine fertige Klasse verwenden, um zu lernen, wie es > funktioniert. Sicher! Darum sagt er ja auch: Stefan Mayerhofer schrieb: > Hat wer eine Lösung ? Das ist die Lösung welche ich bieten kann. Entweder lernt er was draus, oder er verwirft sie. Ist mir beides recht. Übrigens, ich halte es für eine echt doofe Idee, Arduino Anfänger vor der OOP beschützen zu wollen. Denn: Als Arduino User hat man dauernd damit zu tun. Viele Libs sind so aufgebaut.
> Kann ich meinen Code umschreiben, deinen verstehe ich nur teilweise. Offensichtlich kannst du deinen Code nicht umschreiben, weil du weder deinen noch meinen verstanden hast. Wir helfen Sir gerne, aber dazu musst du konkrete Fragen stellen und wenigstens die Grundlagen der Programmiersprache gelernt haben. > Bei der else if Abfrage kommt ja kein (digitalRead(2)==HIGH)), > wie soll der dann hier reinkommen. Ich verstehe diesen Satz nicht. Wer soll wo rein kommen? Was glaubst du denn, was digitalRead(2) liefert? Und was erwartet if() zwischen den Klammern? Welche Ausdrücke/Werte gelten als wahr?
Stefan Mayerhofer schrieb: > Bei der else if Abfrage kommt ja kein (digitalRead(2)==HIGH)) , wie soll > der dann hier reinkommen. (digitalRead(2)==HIGH) Ist das gleiche wie: digitalRead(2) Das ==HIGH ist an der Stelle flüssiger wie Wasser. Überflüssig.
Ok also, DU fragst ab Wenn der Taster nicht gedrückt ist (if(!digitalRead(2)) soll die Lampe aus sein. Millis wird hier dauernd in die Sperrzeit geschrieben. So, ich drücke nun den Taster und da häng ich wieder. Es steht niergends eine Abfrage was ist wenn der Taster gedrückt wird. Was ich aber verstehe ist das wenn der Taster prellt die if Abfragen nacheinander aufgerufen werden. Bitte erkläre mir deinen Code.
Ist doch recht einfach... Wenn die Taste NICHT gedrückt ist, wird sich die Sperrzeit gemerkt und die led aus gemacht. Wenn die Taste gedrückt ist, wird geprüft, ob die 50ms abgelaufen sind, und dann die LED angemacht. Der Code wird auf einem UNO ca 100000 mal pro Sekunde durchlaufen.
> Es steht niergends eine Abfrage was ist wenn der Taster gedrückt wird.
Doch, das ist der "else" Teil. Und an den habe ich direkt die nächste
Bedingung angehängt.
1 | unsigned long sperrzeit=0; |
2 | |
3 | void loop() |
4 | {
|
5 | if (!digitalRead(2)) // Wenn die Taste nicht gedrückt ist ... |
6 | {
|
7 | // Taste wurde losgelassen oder prellt
|
8 | |
9 | // Messung der Sperrzeit erneut beginnen
|
10 | sperrzeit=millis(); |
11 | |
12 | // LED aus
|
13 | digitalWrite(7,LOW); |
14 | }
|
15 | else // ansonsten (also wenn die Taste gedrückt ist)... |
16 | if (millis()-sperrzeit > 50) // Wenn die Sperrzeit überschritten wurde |
17 | {
|
18 | // Taste wurde lange genug gedrückt
|
19 | // LED an
|
20 | digitalWrite(7,HIGH); |
21 | }
|
22 | }
|
Mit if und else if kann man beliebig lange Ketten bauen.
1 | if (geld<10) |
2 | puts("ich bin bettelarm, denn ich habe weniger als 10 Euro"); |
3 | else if (geld<100) |
4 | puts("ich kann was zum essen kaufen, denn ich habe 10 bis 99,99 Euro"); |
5 | else if (geld<500) |
6 | puts("ich kann ins Restaurant gehen, denn ich habe 100 bis 499,99 Euro"); |
7 | else
|
8 | puts("Es reicht sogar für ein neue Fahrrad, denn ich habe mindestens 500 Euro"); |
Wie gesagt: Grundlagen der Programmiersprache lernen. https://www.arduino.cc/reference/en/ https://www.arduino.cc/reference/en/language/structure/control-structure/if/ Hier müsste eigentlich if..else erkläert sein, aber irgendwie haben sie bei if aufgehört zu schreiben. Das ist ja mies. Vielleicht ist eine Grundlagen-Doku abseits von Arduino doch besser: http://www.c-howto.de/tutorial/
Stefan U. schrieb: > Hier müsste eigentlich if..else erkläert sein, aber irgendwie haben sie > bei if aufgehört zu schreiben. Die C++ Grundlagen muss man aus anderen Quellen beziehen. Würde auch keinen Sinn machen die C++ Bücher abzuschreiben und auf der Arduino Seite zu publizieren. Denn das Netz und die Büchereien sind voll mit C++ Tutorials. Außerdem ist das ein Wiki System, kein Selbstbedienungsladen ohne Kasse, da beschwert man sich nicht über Unvollständigkeit, sondern erweitert die Doku. Merksatz: Kritik an anderen, schützt nicht davor, eigene Leistung bringen zu müssen..
Stefan schrieb:
> Mit if und else if kann man beliebig lange Ketten bauen.
Gibt es denn in dieser Supersprache kein "Select-Case" Konstrukt?
Wenn hier mehr als 3 Sachen zu unterscheiden sind, beißt der
Programmierer doch zwischenzeitlich die Tastatur in Stücke.
> Gibt es denn in dieser Supersprache kein "Select-Case" Konstrukt? Doch schon (switch-case) aber das kann nur auf Gleichheit mit Konstanten vergleichen, nicht größer oder kleiner als. > Wenn hier mehr als 3 Sachen zu unterscheiden sind Nur eine Sprache, nämlich C++. Da C++ jedoch eine Erweiterung von C ist, genügt es für den TO momentan, die Grundlagen also C zu lernen.
Nur eine Idee von mir, wie wäre dieser Code um das Prellen zu entgehen? Tastergedrückt=DigitalRead(Pin1); If(tastergedrückt) { DigitalWrite(Pin2,High); Variable=1; } If (variable==1&&tastergedrückt==0) //fals prellen auftritt und wieder auf Masse gezogen wird { DigitalWrite (pin2,High) Variable=0; } Else DigitalWrite(Pin2,Low);
1 | volatile int taster_value = 0; // 0 = nix gedrückt |
2 | |
3 | #define DP_BUTTON ???
|
4 | |
5 | void taster_isr() { |
6 | long int c = 0; |
7 | noInterrupts(); |
8 | while ( digitalRead(DP_BUTTON) == LOW ) { |
9 | c++; |
10 | delay(30); |
11 | }
|
12 | taster_value = c; |
13 | digitalWrite(DP_BUTTON, HIGH); |
14 | interrupts(); |
15 | }
|
16 | |
17 | void workOnKeyPress() { |
18 | if ( taster_value != 0 ) { |
19 | if ( taster_value < 15 ) { // short press |
20 | ...
|
21 | } else if ( taster_value > 15 && taster_value < 50 ) { // long press |
22 | ...
|
23 | } else if ( taster_value > 50 ) { // long long press |
24 | ...
|
25 | } else { // very long press |
26 | ...
|
27 | }
|
28 | taster_value = 0; // reset taster state |
29 | }
|
30 | }
|
31 | |
32 | void initPushSwitch() { |
33 | // for push switch handling
|
34 | pinMode(DP_BUTTON, INPUT); |
35 | digitalWrite(DP_BUTTON, HIGH); |
36 | attachInterrupt(DP_BUTTON, taster_isr, FALLING); |
37 | }
|
38 | |
39 | void setup() { |
40 | ...
|
41 | initPushSwitch(); // init push switch handling (isr) |
42 | ...
|
43 | }
|
44 | |
45 | void loop() { |
46 | ...
|
47 | workOnKeyPress(); // processing push switch |
48 | ...
|
49 | }
|
nachteil: reagiert erst wenn du den taster los lässt
:
Bearbeitet durch User
> Warum ist das falsch ?
Weil dein Code nicht entprellt. Das fehlt ganz offensichtlich das
Abwarten einer gewissen Zeit.
> Wieso, wenns prellt dann wirds trotzdem auf high gezogen ?
Genau ein mal. Prellt dein Taster immer nur einmal? Oder prellt er eine
gewisse Zeit?
Die variable wird ja immer wieder von 0 auf 1 und umgekehrt gesetzt dadurch kommts mal in die eine if und mal in die andere if. Ich bin über jede kritik dankbar, das es perfekt ist kann ich selber nicht sagen, aber ein vorschlag wärs halt gewesen.
Ray M. schrieb: > delay(30); Ein Irrweg. Das Delay in der ISR wird das ganze System zum erliegen zwingen.
und ??? die while-schleife auch ... und zwar genau solange wie du auf den knopf drückst ... wenn dir das delay() da nicht gefällt lass es weg und mach die zahlen in workOnKeyPress() größer
Stefan Mayerhofer schrieb: > Das hier wäre mein Code: Da könntest du die c-Tags drumrum machen, so wie es ein paar Zeilen über jeder Eingabebox beschrieben ist... Stefan U. schrieb: >> Vermutung: wenn millis() zwischen den 2 Abfragen überläuft. > Wenn die Variable x vom gleichen Typ wäre, wie das Ergebnis von millis() > würde der Überlauf allerdings keine Fehlfunktion auslösen. millis() selber hat einen unsigned long, der läuft erst nach 49 Tagen über. Aber x ist leider nur ein 16 Bit int, da passiert der Überlauf schon nach 65 Sekunden... Ray M. schrieb:
1 | void taster_isr() { |
2 | long int c = 0; |
3 | noInterrupts(); |
4 | while ( digitalRead(DP_BUTTON) == LOW ) { |
5 | c++; |
6 | delay(30); |
In einer ISR darf niemals (ich wiederhole in Worten: nie, auf keinen Fall, garantiert nicht) ein delay() vorkommen. Nie! Denn das sorgt dafür, dass andere Interrups nicht abgearbeitet werden können und z.B. eine serielle Schnittstelle einfach überfahren wird. Auch bei Timern kann es Probleme geben, wenn ihre Interrupts für solch lange Zeit blockiert werden. Und im speziellen Code hier wird sogar das komplette System während des gesamten Tasterdrucks blockiert. Schlimmer gehts nimmer! Stefan Mayerhofer schrieb: > jedoch will ich nicht blind was kopieren oder auswendig lernen sondern > es selber schreiben und wirklich durchdenken. Eine brauchbare Entprellung ist in einem MAX6816 realisiert: https://datasheets.maximintegrated.com/en/ds/1896.pdf Und jetzt muss der Programmierer, der durch eigenes Nachdenken auf eine gleich gute Lösung kommen will, einfach mal einen halben Tag über "Figure 1. Block Diagram" grübeln und das in ein Programm umsetzen. Wenn er es dann letztlich doch nicht hinbekommen hat und auch die vielen andren Threads zum Thema nicht zur Erleuchtung beigetragen haben, dann kann er ja immer noch einfach genau diesen MAX6816 kaufen und hat damit eine zuverlässig funktionierende Entprellung in seinem System. https://www.reichelt.de/ICs-MAX-1000-9201/MAX-6816-EUST/3/index.html?ACTION=3&GROUPID=5470&ARTICLE=148598 > jedoch will ich nicht blind was kopieren oder auswendig lernen sondern > es selber schreiben und wirklich durchdenken. Wie wäre es, wenn du die Reihenfolge von Schreiben und Durchdenken umdrehst? Du darfst auch gern anderen Code ansehen und analysieren. Du wirst dann z.B. sehen, dass der geniale Code von Peter Dannegger prinzipiell genauso funktioniert wie der obige MAX6816. Wenn du das erkannt hast, dann bist du mit dem Denken fertig und kannst loslegen mit dem Schreiben. Als Denkhilfe ist recht brauchbar auch der Artikel Entprellung
:
Bearbeitet durch Moderator
Lothar M. schrieb: > > Ray M. schrieb: >
1 | > void taster_isr() { |
2 | > long int c = 0; |
3 | > noInterrupts(); |
4 | > while ( digitalRead(DP_BUTTON) == LOW ) { |
5 | > c++; |
6 | > delay(30); |
7 | >
|
> In einer ISR darf niemals (ich wiederhole in Worten: nie, auf keinen > Fall, garantiert nicht) ein delay() vorkommen. Nie! > Denn das sorgt dafür, dass andere Interrups nicht abgearbeitet werden > können und z.B. eine serielle Schnittstelle einfach überfahren wird. > Auch bei Timern kann es Probleme geben, wenn ihre Interrupts für solch > lange Zeit blockiert werden. > Und im speziellen Code hier wird sogar das komplette System während des > gesamten Tasterdrucks blockiert. Schlimmer gehts nimmer! und ich hab gesagt dann lass den delay() einfach weg wenn er euch stört für mich funktioniert das in 99% aller projekte, auch wenn die isr natürlich alle anderen aktionen während das taster-drückens blockiert, das delay() ist da gar kein problem weil eh noch noInterrupts() steht !!! damit passiert während des taster-drückens nix anderes mehr und ja, die lösung mit dem max ist natürlich schöner ;)
Ray M. schrieb: > für mich funktioniert das in 99% aller projekte, auch wenn die > isr natürlich alle anderen aktionen während das taster-drückens blockiert Alle Timer-Überläufe und sämtliche Schnittstellen und alle Interrupts. Na toll, solche Geräte kenne ich. Für mich "funktionert" so ein offensichtlich dahingehacktes Programm bestenfalls, wenn es für diesen Controller nur einzig und allein um diese Taste geht und der sonst nichts zu tun hat. > und ja, die lösung mit dem max ist natürlich schöner Und noch schöner ist Peter Danneggers Code, weil er zwar nicht bis 63 zählt, sondern nur bis 3, das aber parallel für 8 Tasten in 2 Bytes.
:
Bearbeitet durch Moderator
Stefan Mayerhofer schrieb: > Ich weiß es gibt viele Tutorials zum Taster entprellen jedoch will ich > nicht blind was kopieren oder auswendig lernen sondern es selber > schreiben und wirklich durchdenken. Eine Entprellung besteht aus einem Integrator gefolgt von einem Schmitt-Trigger. In Software macht man dazu einen gleitenden Mittelwert über z.B. 4 Abtastungen. Das Abtastintervall wählt man größer als die Prellperiode, aber nicht so groß, daß der Nutzer eine Verzögerung merkt (typisch 2..50ms). 4 aufeinanderfolgende Einsen werden dann als 1 interpretiert, 4 aufeinanderfolgenden Nullen als 0. Alle anderen Muster bewirken keine Zustandsänderung. Fertig ist die Entprellung.
Ich habe es versucht Hardwaremäßig zu entprellen und es hat nicht geklappt. Hab auch einen Pull-Down Widerstand am Pin. Hab parallel zum Pull Down einen 10uF Elko geschaltet und es hat sich kaum was verändert. Hab nähmlich per Serial Print mir eine Variable angeschaut die beim Tastendruck hinaufgezählt wird, bei einem Tasterdruck war die Variable größer als 30 also null entprellung. Kann ich da noch was machen, noch einen zusätzlichen Widerstand damit sich der Elko langsamer entlädt bzw. aufladet ? Mein Widerstand beträgt 10kOhm.
Mike1996 schrieb: > Ist mein Code also nicht vernünftig ? Was heißt in Bezug auf Code "vernünftig"? Er funktioniert halt einfach nicht, weil die Variable einfach um 1 Schleifenzyklus und der Ausgang asymmetrisch um 2 Schleifendurchläufe versetzt dem Prellen folgt. Probiers aus... Mike1996 schrieb: > Nur eine Idee von mir, wie wäre dieser Code um das Prellen zu entgehen? Wie gesagt: am Besten vor dem Schreiben drüber nachdenken, ob das überhaupt funktioniert?
1 | +5V |
2 | | |
3 | | |
4 | / |
5 | |------ |
6 | | | |
7 | | --- |
8 | | | --- |
9 | | | | |
10 | | | |
11 | --- --- |
Widerstnad 10kOhm, 10uF der Elko.
:
Bearbeitet durch Moderator
Mike1996 schrieb: > Widerstnad 10kOhm, 10uF der Elko. Warum ein Pulldown, wenn der uC schon einen Pullup hat? Mit dieser Beschaltung funktionert Entprellen nur mäßig und nur, wenn der µC Schmitttrigger-Eingänge hat. Mike1996 schrieb: > Hab nähmlich per Serial Print mir eine Variable angeschaut die beim > Tastendruck hinaufgezählt wird Lass mal das Programm sehen... BTW: für (d)eine neue Frage solltst du (d)einen neuen Thread beginnen. Und nicht den eines anderen kapern!
:
Bearbeitet durch Moderator
Mike1996 schrieb: > Widerstnad 10kOhm, 10uF der Elko. Bei dem Konstrukt ist die Wahrscheinlichkeit sehr groß, das erstens der Taster nicht lange hält, zweitens der Kontroller undefiniert reagiert.
Hubert G. schrieb: > Bei dem Konstrukt ist die Wahrscheinlichkeit sehr groß, das erstens der > Taster nicht lange hält, zweitens der Kontroller undefiniert reagiert. Auch ein Brown Out Reset ist eine definierte Reaktion. Und mit der Schaltung vermutlich sogar reproduzierbar. Bis der Taster weg/fest brennt. Wenn, dann: Internen Pullup verwenden (spart einen Widerstand ein) Kondensator kleiner, z.B. 100nF Strombegrenzungswiderstand zwischen Taster und Kondensator. Dann ist das eine recht stabile Hardwareentprellung.
Ok, probiere ich aus. Lothar M. schrieb: > Warum ein Pulldown, wenn der uC schon einen Pullup hat? > Mit dieser Beschaltung funktionert Entprellen nur mäßig und nur, wenn > der µC Schmitttrigger-Eingänge hat. Gilt das dann trotzdem ?
Mike1996 schrieb: > Sry, falsch gezeichnet, der Kondensator parallel zum Schalter? Zeichne nochmal richtig, dann kann man Ja oder Nein sagen.
Peter D. schrieb: > In Software macht man dazu einen gleitenden Mittelwert über z.B. 4 > Abtastungen. Das Abtastintervall wählt man größer als die Prellperiode, > aber nicht so groß, daß der Nutzer eine Verzögerung merkt (typisch > 2..50ms). 4 aufeinanderfolgende Einsen werden dann als 1 interpretiert, > 4 aufeinanderfolgenden Nullen als 0. Alle anderen Muster bewirken keine > Zustandsänderung. Fertig ist die Entprellung. Das ist auch meine bevorzugte Variante wenn man - keinen Timer/Interrupt verwenden will - nur eine oder wenige Tasten hat Ich hab es kürzlich mal so gelöst (mit den SBIT-Funktionen von PeDa) und dem Vergleich von 8 gleichen Zuständen. Taste ist Low-Aktiv und die Funktion liefert 1 bei gedrückter Taste. Es ist die Nachbildung eines Schieberegisters mit der Ausgangsverknüpfung UND und NOR, die ein RS-FF bedient.
1 | uint8_t get_key() // Entprellung |
2 | {
|
3 | static uint8_t shift; // vorbesetzt vom letzten Tastendruck |
4 | while(1) |
5 | {
|
6 | if(KEY_in == 1) shift |= 1; // Bit 0 setzen |
7 | else shift &= ~1; // Bit 0 löschen (&0xFE) |
8 | _delay_ms (3); |
9 | if ( (shift == 0xFF) || (shift == 0) ) return (!shift & 0x01); // 8 mal hintereinander das selbe gelesen, Taste gedrückt bei LOW, get_key liefert dann '1' |
10 | shift <<= 1; |
11 | }
|
12 | }
|
Mike1996 schrieb: > So ? Ja.
Mike1996 schrieb: > So ? Jawoll! Genau so kann eine funktionierende Hardware Entprellung aussehen. Aber eigentlich sind wir hier ja bei einer Software Entprellung. Eine solche ist in den allermeisten Fällen vollkommen ausreichend, meist erheblich billiger und flexibler was die Zeiten angeht.. Die Hardwareentprellung beginnt erst Sinn zu machen, wenn man den Eingang per Interrupt auswerten muss. Und ohne das MUSS machen Interrupts an der Stelle keinen Sinn.
Mike1996 schrieb: > Gilt das dann trotzdem ? Ja, klar. Mit der ganzen RC-Bastelei wird es zwar ständig besser, aber den eigentlichen Trick mit dem Schwellwert bringt erst ein Schmitttrigger. HildeK schrieb:
1 | uint8_t get_key() // Entprellung |
2 | {
|
3 | static uint8_t shift; // vorbesetzt vom letzten Tastendruck |
4 | while(1) |
5 | {
|
Ich weiß nicht, mir gefällt dieses blockierende Programmierung nicht. Ich mache selbst einfachste Sachen in der Hauptschleife mit z.B. einem 10ms-Flag in einem Zustandsautomaten und einem "Betätigungsdauerzähler": - wenn die Taste nicht gedrückt ist, dann setze den Zähler zurück - wenn die Taste gedrückt ist, dann zähle den Zähler hoch - wenn der Zähler 5 (oder auch 10) erreicht, dann ist die Taste gedrückt - nebenher Zähler sättigen (nicht dass ein Überlauf seltsame Dinge bewirkt) Das sind je nach Programmierstil 2..3 drei unabhängige Abfragen, die sogar noch in beliebiger Reihenfolge kommen können:
1 | uint8_t z = 0; |
2 | |
3 | for (;;) { |
4 | :
|
5 | if (flag_10ms) { |
6 | :
|
7 | if(taste_gedrueckt) z++; |
8 | else z=0; |
9 | |
10 | if (z>=5) { |
11 | z=5; // Zähler begrenzen |
12 | // Taste entprellt und mindestens 50ms gedrückt
|
13 | // machwas...
|
14 | }
|
15 | :
|
16 | }
|
17 | :
|
18 | }
|
HildeK schrieb: > Ich hab es kürzlich mal so gelöst Weil bei einem Linksshift eine 0 von rechts hereingeschoben wird, ließen sich diese beiden Zeilen noch abkürzen:
1 | // original
|
2 | if(KEY_in == 1) shift |= 1; // Bit 0 setzen |
3 | else shift &= ~1; // Bit 0 löschen (&0xFE) |
4 | |
5 | // kürzer
|
6 | if(KEY_in == 1) shift |= 1; // Bit 0 setzen falls nötig. Default=0 |
7 | |
8 | // noch kürzer
|
9 | shift |= KEY_in; |
:
Bearbeitet durch Moderator
Lothar M. schrieb: > Ich mache selbst einfachste Sachen in der Hauptschleife mit z.B. einem > 10ms-Flag in einem Zustandsautomaten und einem "Betätigungsdauerzähler": In der Arduinowelt gibt es millis(). Einen weiteren Timer Interrupt für den Zweck etablieren ist nicht sehr sinnvoll. Also muss man mit millis() zurande kommen. Und ja, das Entprellen erfordert einen Zustandsautomaten. Und sei er noch so primitiv. Lothar M. schrieb: > Ich weiß nicht, mir gefällt dieses blockierende Programmierung nicht. Mir auch nicht. "blockierende Programmierung" ist wie ein Stock in den Speichen. Lothar M. schrieb: > Ja, klar. Mit der ganzen RC-Bastelei wird es zwar ständig besser, aber > den eigentlichen Trick mit dem Schwellwert bringt erst ein > Schmitttrigger. Der hier behandelte AVR(hoffe ich doch mal) hat Schmitttriger Eingänge.
Lothar M. schrieb: > Ich weiß nicht, mir gefällt dieses blockierende Programmierung nicht. Ich sagte ja auch: wenn ich keinen Timer verwenden will. In diesem Fall habe ich aus Stromspargründen Timer, ADC usw. im PRR abgeschaltet. Ich hatte keinen Arduino verwendet, wo der ggf. sowieso läuft. In meiner Verwendung war ein 'Blockiern' überhaupt kein Thema, die meiste Zeit ist der Prozessor eh im Tiefschlaf ... Lothar M. schrieb: > Weil bei einem Linksshift eine 0 von rechts hereingeschoben wird > . > . > // noch kürzer > shift |= KEY_in; Danke, du hast ja recht - schau ich mir noch an! Ich bin nicht der Software-Profi, aber für solche Hinweise immer sehr dankbar ...
Lothar M. schrieb: > Weil bei einem Linksshift eine 0 von rechts hereingeschoben wird, ließen > sich diese beiden Zeilen noch abkürzen: // original > if(KEY_in == 1) shift |= 1; // Bit 0 setzen > else shift &= ~1; // Bit 0 löschen (&0xFE) > > // kürzer > if(KEY_in == 1) shift |= 1; // Bit 0 setzen falls nötig.Default=0 > > // noch kürzer > shift |= KEY_in; Habs mir angeschaut. Geht so nicht. Sie entprellt zwar den Übergang von KEY_in=0 auf 1, nicht aber die andere Richtung. Die geht nicht mal mehr, es kommt keine Null ... Man könnte aber bei
1 | static uint8 shift; |
das 'static' weglassen und dafür shift mit z.B. 0xAA vorbesetzten.
HildeK schrieb: > Die geht nicht mal mehr, es kommt keine Null ... Dann nimmt KEY_in völlig unerwarteterweise auch andere Werte als 0 und 1 an ;-) HildeK schrieb: > das 'static' weglassen und dafür shift mit z.B. 0xAA vorbesetzten. Das wäre sowieso sinnvoll, denn mit dem static wird evtl. gar nichts entprellt, weil das static gespeicherte Abbild des Tasters mit der Umwelt (und dem realen Tasterzustand) gar nichts zu tun hat. Oder andersrum: wenn shift vom letzten Aufruf von keypress() noch 0xff ist und wieder keypress aufgerufen wird, dann reicht theoretisch ein einziger high Impuls (oder eine weiterhin gedrückte Taste) zum Afragezeitpunkt um sofort wieder ein 0xff in shift zu erzeugen und die Routine ohne jegliche Entprellzeit sofort zu terminieren.
:
Bearbeitet durch Moderator
Lothar M. schrieb: >> Die geht nicht mal mehr, es kommt keine Null ... > Dann nimmt KEY_in völlig unerwarteterweise auch andere Werte als 0 und 1 > an ;-) Nein, sicher nicht :-) Das Problem war das links Schieben, das in meinem obigen Beispiel am Ende gemacht wurde. Es müsste so aussehen, dann passt die gewünschte Funktion und deine Vereinfachung:
1 | uint8_t get_key() // Entprellung |
2 | {
|
3 | static uint8_t shift; // vorbesetzt vom letzten Tastendruck |
4 | while(1) |
5 | {
|
6 | shift <<= 1; |
7 | shift |= KEY_in; // Bit 0 setzen |
8 | _delay_ms (3); |
9 | if ( (shift == 0xFF) || (shift == 0) ) return (!shift & 0x01); |
10 | }
|
11 | }
|
Lothar M. schrieb: >> das 'static' weglassen und dafür shift mit z.B. 0xAA vorbesetzten. > Das wäre sowieso sinnvoll, denn mit dem static wird evtl. gar nichts > entprellt, weil das static gespeicherte Abbild des Tasters mit der > Umwelt (und dem realen Tasterzustand) gar nichts zu tun hat. > Oder andersrum: wenn shift vom letzten Aufruf von keypress() noch 0xff > ist und wieder keypress aufgerufen wird, dann reicht theoretisch ein > einziger high Impuls (oder eine weiterhin gedrückte Taste) zum > Afragezeitpunkt um sofort wieder ein 0xff in shift zu erzeugen und die > Routine ohne jegliche Entprellzeit sofort zu terminieren. Doch, das 'static' passt schon. Es ist der Zustand, den die Taste beim letzten Aufruf hatte. Einzig: man könnte 'shift' mit 0xFF vorbesetzen, weil das der Zustand der ungedrückten Taste ist, was am wahrscheinlichsten beim Start des Programms ist. Ist der Taster losgelassen, dann ist der letzte Zustand (Taster Low aktiv) von shift = 0xFF. Sollte die Routine wieder aufgerufen werden, ohne gedrückten Taster, dann beendet sie sofort (nach einem Delay), weil zu dem 0xFF - geschoben zu 0xFE - wieder eine 1 am LSB hinzugefügt wurde. Kein Problem. Wurde die Taste gedrückt, dann werden, wie du sagtest, automatisch auf LSB-Seite Nullen eingeschoben, das müssen dann auch 8 Nullen nacheinander sein. Die Routine läuft so lange, bis shift 0x00 ist und gibt dann 'gedrückt' zurück - im besten Fall in 8 mal der Delayzeit. Wird die Taste länger gedrückt oder länger losgelassen, dann kommt eben bei weiteren Aufrufen der Funktion fast sofort, mit nur einer Delayzeit, der aktuelle Zustand zurück. Jede Störung oder Änderung, ob bei der losgelassenen oder gedrückten Taste, müsste dann schon 8 Delayzeiten anstehen. Ich finde, die Lösung durchaus brauchbar, wenn die 'Blockierung' woanders keine Hemmnisse hervorruft.
Hallo Leute, Stefan US hat mir diesen Code hier geschickt der softwaremäßig Taster entprellt. unsigned long sperrzeit=0; void loop() { if (!digitalRead(2)) // Wenn die Taste nicht gedrückt ist ... { // Taste wurde losgelassen oder prellt // Messung der Sperrzeit erneut beginnen sperrzeit=millis(); // LED aus digitalWrite(7,LOW); } else // ansonsten (also wenn die Taste gedrückt ist)... if (millis()-sperrzeit > 50) // Wenn die Sperrzeit überschritten wurde { // Taste wurde lange genug gedrückt // LED an digitalWrite(7,HIGH); } } Nun meine Frage, wieso funkt mein Programm nicht ? unsigned long Variable1; boolean Variable2=0,tastergedrückt=0; int AbfrageobPrellt=0,entprellzeit=50; void loop() { tastergerückt=digitalRead(Pin2); if(tastergedrückt) { Variable1=millis(); } if ((millis()-Variable1)>entprellzeit) //entprellzeit=50ms { //Nach 50ms nochmal die Abfrage if(tastergedrückt) { AnfrageobPrellt++; digitalWrite(Pin1,HIGH); } } if(!tasterdegrückt) { digitalWrite(Pin1,LOW); } Serial.println(AbfrageobPrellt); Im Serial monitor wird per Tastendruck die Variable "AbfrageobPrellt" immer um ~30mal erhöht also prellts immer noch, oder ist der uC so schnell das er das loop 30mal durchläuft während ich kurz gedrückt habe ? Wo könnt ich die Variable sonst hinsetzten um zu prüfen obs prellt oder nicht ?
Stefan Mayerhofer schrieb: > Nun meine Frage, wieso funkt mein Programm nicht ? Weil du kein Funkgerät angeschlossen hast.
Der Timer soll zurückgesetzt werden, wenn der Taster NICHT gedrückt
wurde (beachte das "!").
Danach hast du das "else" ausgelassen.
Danach hast du einen weiteren unnötigen Check "if (tastergedrückt)"
eingebaut, das habe ich Dir nicht vorgeschlagen.
> AnfrageobPrellt++;
Was soll das werden?
Diese Variable soll mir im Serial monitor nur anzeigen ob der Taster prellt, es zeigt mir beim tastendruck 30 stk davon an. Meine Überlegung nun: 1)Ich Frage den Taster ab 2)Taster gedrückt ? Wenn Ja dann soll die Zeit mal abgefragt werden mit millis(). 3)Sind nun seit der Zeit wo das erste mal gedrückt wurde 50ms vergangen frage ich zur Sicherheit nochmal ab ob der Taster nun wirklich NOCH gedrückt ist. Das habe ich als eigenes if gemacht damit es auch nach 50ms erfüllt werden kann. Dh das Programm läuft weiter bis 50ms vergangen sind und springt dann in die if rein. 4)Wenn ja dann leuchtet die LED und die Variable "abfrageobprellt" soll hochgezählt werden um sie mir im Serial monitor anzuschauen. 5)Falls nicht gedrückt wird dann soll einfach die LED nicht leuchten. Bitte erkläre mir wieso das so nicht passt und wieso die Zeit gemessen werden soll wenn der Taster NICHT gedrückt ist, die Zeit wird abgefragt wenn gedrückt wird danach läuft das Programm 50ms weiter und springt erst dann in die zweite if Abfrage hineine und die LED leuchtet. Ich raff nicht was daran falsch ist :(((
Ichn habe Dir schon erklärt, warum dein Code nicht funktioniert. Deine if Abfragen folgen einer völlig anderen Logik, als mein Beispiel. Wenn Du trotz Hinweis nicht verstehst, dass dein fehlendes Ausrufezeichen und ein fehlendes "else" die ganze Logik kaputt machen, dann kann ich Dir auch nicht weiter helfen. Außer vielleicht mit dem Ratschlag, die Grundlagen der Programmiersprache zuerst mit einem PC Programm (ganz ohne Mikrocontroller) zu lernen. Und lerne auch, den Debugger zu benutzen, denn damit kannst du Schritt für Schritt zugucken, wie das Programm abläuft. Lade Dir einfach mal Visual Studio runter, oder QT Creator und lerne damit.
Ich schaff das nicht, hab vorhin sogar eine Schaltung wie im ANhang nachgebaut mit 10k bzw.1k und 100nF (Vcc 5V). Auch dies genau 0 Besserung. Bin schon am Verzweifeln. Erfahrung habe ich im Dev-C++ gesammelt. Habe einen Pull Up Widerstand. Auch versucht mit Pull DOwn und auch mit Internen Pull Up und und und, bin nur mehr am probieren aber es funktioniert einfach nicht den Taster zu entprellen. Habe ein ganz kleines Programm wo ich nur einen Taster abfrage, wenn der Taster gedrückt ist gebe ich am Serial Monitor "GEDRÜCKT" aus. So, ich drücke einmal die Taste und es steht "GEDRÜCKT" ca. 40-50mal am Bildschirm. Keine Software und keine Hardware funktioniert bei mir. Ich hätte schon so viele Ideen die ich weitermachen könnte, aber ich will Ohne dieses Problem zu lösen einfach nicht weitermachen weil ich dann ja nur herumpfusche. Bitte gebt mir einen Lösungsvorschlag.
Arduino IDE->Beispiele->Digital->Debounce ledState = !ledState; ersetzen mit Serial.println("taster gedrückt"); ;)
Stefan Mayerhofer schrieb: > Habe ein ganz kleines Programm wo ich nur einen Taster abfrage, wenn der > Taster gedrückt ist gebe ich am Serial Monitor "GEDRÜCKT" aus. > So, ich drücke einmal die Taste und es steht "GEDRÜCKT" ca. 40-50mal am > Bildschirm. Entprellen hat mit Flankenerkennung erst mal nichts zu tun. Wenn du da natürlich was ausgibst solange der Taster gedrückt ist, dann kommt da natürlich solange du den Taster drückst auch was heraus. Wenn bei 1 Tastendruck beliebiger Länge nur 1x etwas ausgegeben werden soll, dann brauchst du zuerst eine Entprellung und danach eine Flankenerkennung. Stefan Mayerhofer schrieb: > oder ist der uC so schnell das er das loop 30mal durchläuft während ich > kurz gedrückt habe ? Ja, denk mal einfach, dass er auch wenn er langsam ist, in 1 Sekunde locker tausend Zeilen "schafft"... Stefan Mayerhofer schrieb: > jedoch will ich nicht blind was kopieren oder auswendig lernen sondern > es selber schreiben und wirklich durchdenken. Tu das. Es ist ein guter Ansatz.
:
Bearbeitet durch Moderator
Stefan Mayerhofer schrieb: > oder ist der uC so > schnell das er das loop 30mal durchläuft während ich kurz gedrückt habe > ? Je nach dem, was zu tun ist, sind durchaus 100000 Loopdurchläufe/s, und auch mehr, zu erwarten. Um nur 30 zu erwischen, musst du schon SEHR schnell wieder loslassen. Dir wurde die Hardware Entprellung erklärt. Dir wurde der Umgang mit millis() gezeigt. Dir wurde Code vorgekaut. Und dennoch: Stefan Mayerhofer schrieb: > Bitte gebt mir einen Lösungsvorschlag. Eigentlich geht da nichts mehr. Ich habe keine Antwort mehr für dich. Außer vielleicht: > Du musst dein Ändern leben! Oder, wie kann ich dir helfen? // ---- OK OK, eins fällt mir noch ein! Die Nachtwächter Erklärung aus dem Arduino Forum. Die beschreibt wie man zeitgesteuerte endliche Automaten baut. Ein Entpreller ist genau ein solcher Automat. https://forum.arduino.cc/index.php?topic=423688.0 -- Aber das schöne daran ist, wenn du diesen Bereich gefressen hast, verstanden hast, dann hast du ein ganz wichtiges Kapitel gelernt. Denn das Verfahren ist Grundlegend für nahezu alle deine weitere µC Programmierung! Immer! Zeitsteuerung, und Automaten.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.