Hallo Forum, in einer Dauerschleife werte ich ein paar Sensoren aus und lasse die Ergebnisse im 10-Sekunden-Takt (delay(10000)) auf einem kleinen OLED anzeigen bzw. aktualisieren. Jetzt möchte ich erreichen, dass das Display standardmäßig aus ist und die Anzeige nur auf Tastendruck erfolgt. Mein Problem ist das delay(10000) in der Schleife. Der Anwender wird in 99,99% der Fälle die Taste zum falschen Zeitpunkt drücken. Ich müsste also erreichen, dass der Tastendruck einen D-Pin dauerhaft setzt, sodass ich diesen dann im nächsten Durchgang der Schleife auswerten und wieder loslassen kann. Geht das? Danke für Tipps. 3nibble
Verwende anstatt delay_ms() millis() um deinen 10 Sekunden Takt zu erzeugen. Dies ist genau der Grund warum man kein einfaches delay() nimmt. https://www.arduino.cc/reference/de/language/functions/time/millis/
Delay, dass GOTO des Arduinos... 😝 Was Thomas sagt.
3nibble schrieb: > Der Anwender wird in > 99,99% der Fälle die Taste zum falschen Zeitpunkt drücken. "If the button is pressed while Arduino is paused waiting for the delay() to pass, your program will miss the button press." https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay
macst du halt statt einem delay(10000) 100 delay(100) da hast du Tastenentprellung gleich mit dabei
3nibble schrieb: > Mein Problem ist das delay(10000) in der Schleife. Wenn ich in einem Programm ein delay() sehe, dann ist das ein Warnsignal. Wenn hinter dem delay() eine Zahl größer als 1 ms steht, dann ist es ein Fehler. Kleiner Merksatz: die Hauptschleife muss immer mit kürzestmöglicher Zeit durchlaufen werden. Sagen wir mal: jede Funktion, die länger dauert als 10ms, muss aufgetrennt werden. Wenn es also Aktionen gibt, die noch eine "Wartezeit" brauchen, dann kommen die eben im nächsten (oder übernächsten oder überübernächsten oder einem noch späteren) Hauptschleifendurchlauf dran. 3nibble schrieb: > sodass ich diesen dann im nächsten Durchgang der Schleife auswerten und > wieder loslassen kann. > Geht das? Weil bei mir kein Hauptschleifendurchlauf länger als 20ms dauert, ist das Abfragen von Tastern absolut kein Problem. dummschwaetzer schrieb: > 100 delay(100) > da hast du Tastenentprellung gleich mit dabei So billig bekommt man ehrlich gesagt die Entprellung doch nicht...
:
Bearbeitet durch Moderator
3nibble schrieb: > in einer Dauerschleife werte ich ein paar Sensoren aus und lasse die > Ergebnisse im 10-Sekunden-Takt (delay(10000)) auf einem kleinen OLED > anzeigen bzw. aktualisieren. Dir ist schon klar, dass die Sensoren dann auch nur im 10s-Takt abgefragt werden? Verwende entweder die Funktion millis() zur Abfrage des Arduino Timers oder wenigstens ein kürzeres delay() zusammen mit einem Zähler. Für eine Tastenabfrage alle 20ms könnte man die Abfrage/Ausgabe bei nur jedem 500-sten Schleifendurchlauf aufrufen.
3nibble schrieb: > Mein Problem ist das delay(10000) in der Schleife. Der Anwender wird in > 99,99% der Fälle die Taste zum falschen Zeitpunkt drücken. Ich müsste > also erreichen, dass der Tastendruck einen D-Pin dauerhaft setzt, sodass > ich diesen dann im nächsten Durchgang der Schleife auswerten und wieder > loslassen kann. > Geht das? Beitrag "Re: Tasten entprellen - Bulletproof"
Hallo, ich weiß nicht, wieso ihr euch am "delay()" festhält. Sein fundamentales Problem ist, dass er laut Beschreibung wohl keinen Interrupt verwendet, sondern einfach mal zufällig in der Hauptschleife den Zustand des Pins ausliest. Es stimmt ja, dass man hier kein "delay()" so verwendet, bzw. allgemein eh den Kontroller schlafen legt und wahlweise diesen Ablauf in der Hauptschleife durch einen DEA aufteilt, aber das ist auch nur ein Teils seines Problems bzw. seinen mangelnden Grundverständnisses.
Es braucht weder Interrupt, noch muss man auf das delay() verzichten. Die Taste kann man auch in yield() lesen und nach Abschluss des delay() das gemerkte dann auswerten.
du brauche 2 Variablen für das Problem. alte_millis (bei mir genannt). LED_status Do machst eine do while Schleife in der du die Millis abfragst permanent. etwa so alte_millis = 0 do if millis >= alte_millis + Zeit_wert then alt_millis = millis frage_sensoren_ab end if if taster_gedruckt = true then if led_status = true then led_status = false mach_led_aus else led_status = true mach_led_an end if end if If Millis < alte_millis then alte_millis = 0 ' fängt den Millis überlauf an loop Das ist alles !! Mache ich übrigens genau SO bei einer meiner Projekte um die Hintergrundbeleuchtung der 2004 abzuschalten. Für die Freaks hier. Die Routine habe ich unter Arduino-C auch gemacht, das ist aber B4X-Code. Den der Arduino auch frisst mit den richtigen Compiler.
Lothar M. schrieb: > Wenn ich in einem Programm ein delay() sehe, dann ist das ein > Warnsignal. Wenn hinter dem delay() eine Zahl größer als 1 ms steht, > dann ist es ein Fehler. +1 Timer IRQ mit einer sinnvollen Zeiteinstellung IRQs erzeugen zu lassen. Sinnvoll = kleinste benötigte Zeiteinheit, aber nicht kleiner. Bei Tastendrücken reichen sicherlich auch längere Zeiträume, wenn man nicht gerade das Reaktionsvermögen einer Stubenfliege hat. Stumpfes hochzählen der verschiedenen Zeitvariablen in der IRQ und ich weiß global ob meine Zeit X abgelaufen ist, arbeite dann ab und setze zurück. So kann ich beliebig viele verschiedene Zeiten checken, brauche nicht ein delay() dazu und blockiere die MCU nie. Wenn möglich lege ich die MCU am Ende der Main schlafen und lasse die durch den IRQ wecken. Was soll die sich wild im Kreis drehen wenn die Aufgaben erledigt sind und alles weitere bis zum nächsten IRQ Zeit hat? Ben K. schrieb: > Delay, dass GOTO des Arduinos... 😝 Schlimmer. Goto macht es nur unleserlich. Delay blockiert jede weitere Aktion mit Vollgas + Bremse.
Hi, erstmal. Die Vorredner haben Recht. Man sollte kein so hohes Delay verwenden, da man seinen µC damit sehr lange dazu zwingt untätig zu sein. Da ich jetzt aber mal davon ausgehe dass das ein kleines Testprogramm ist, ist das sicherlich völlig in Ordnung. Man sollte aber bei größeren Projekten echt die Nutzung von Delays beschränken. Zu deinem Problem. Wie ich das Problem verstehe könntest du D-Flip-Flops oder T-Flip-Flops mit geeigneter Schaltung verwenden (siehe Bild anbei). Das Suchwort ist Bistabile-Kippstufe. Beim T-Flip-Flop ändert sich bei jedem mal, wenn der Taster gedrückt wird der Zustand am Ausgang (es reicht hier einen der beiden Ausgänge auszuwärten). Dabei ist Achtung geboten, da du hier definitiv deinen Taster entprellen solltest, da du sonst bei jedem Prellen den Ausgangspegel wechselst. Außerdem lässt sich das System hier schnell in die Irre führen, wenn man den Taster einfach zweimal drückt, hat man wieder den Pegel als wenn der Taster nie gedrückt wäre. Ist also nur mit starker Einschränkung verwendbar. Wenn du nun ein D-Flip-Flop verwendets, und die dargestellte Schaltung, so musst du nicht mehr unbedingt entprellen. Am linken Eingang ist der Schalter. Sobald dieser gedrückt wird, wird das Ausgangsignal des D-Flip-Flops zu eins. Wird der Taster nicht gedrückt und der rechte Eingang (z.B. vom I/O-Port des µC) auf logisch eins gesetzt, so wird das Flip-Flop zurückgesetzt, so zu sagen "Scharf gestellt". Gruß Aaron P.S.: Anbei ein Falstadt Link, der dir ein die Beispielschaltungen zeigt und du selbst etwas rumprobieren kannst. https://www.falstad.com/circuit/circuitjs.html?ctz=CQAgjCAMB0l3BWcMBMcUHYMGZIA4UA2ATmIxAUgpABZsKBTAWjDACgwEkEU8RCaIDJEECoUDsXqYU-QdkJ8xVSGwAyFMLLE08VZeIBmAQwA2AZwbVVAd03bBPJYNv2QxQhV7vPqgCZuYghaPiCyfgwmAK6mAC7q-CiCYIT6NFQpKkZmltZsAYRJ4KlumWEgEdFxbHbBsmV1of5hCJ5iKK2h4ZHGMfF2HZ4eYRiyw66DciMOEhqT7UUGVCYWVkiqQA P.P.S.: Ich selbst bin jetzt kein Profi mit Flip-Flops (habe kaum was damit direkt zu tun) aber ich denke die Schaltunge sollten auch real so funktionieren.
Aabeku K. schrieb: > P.S.: Anbei ein Falstadt Link, der dir ein die Beispielschaltungen zeigt > und du selbst etwas rumprobieren kannst. Theoretisch sind die Dioden nicht unbedingt notwendig, wenn man einen geeigneten Widerstand zum Strom begrenzen verwendet. Wie z.B. im Bild.
Max M. schrieb: > Delay blockiert jede weitere Aktion mit > Vollgas + Bremse. Herzerfrischend kenntnisfrei.
1 | bool merker; |
2 | constexpr byte tasterPin {2}; |
3 | |
4 | void yield() |
5 | {
|
6 | if(not digitalRead(tasterPin)) merker = true; |
7 | }
|
8 | |
9 | void setup() |
10 | {
|
11 | Serial.begin(9600); |
12 | pinMode(tasterPin,INPUT_PULLUP); |
13 | }
|
14 | |
15 | void loop() |
16 | {
|
17 | delay(10000); |
18 | if(merker) |
19 | {
|
20 | Serial.println("Aktion!"); |
21 | merker = false; |
22 | }
|
23 | }
|
Aabeku K. schrieb: > sicherlich völlig in Ordnung. Ganz offensichtlich ja nicht, wenn man während der 10sek gerne einen Tastendruck erkannt hätte statt sich nur hektisch im kreis zu drehen und rein garnichts mehr mitzubekommmen. Auch die lausige Programmierung mit zusätzlicher Hardware erschlagen zu wollen ist leider völlig nutzlos, da die MCU auch dann erst nach 10sek mitbekommt das eine Taste gedrückt wurde. Der TO muss das Wesen der Delay Routine verstehen, warum die Schrott ist und man das anders löst.
Ja hast du absolut recht, bei großen Anwendungen. Aber wie der TO schrieb: > Mein Problem ist das delay(10000) in der Schleife. Der Anwender wird in > 99,99% der Fälle die Taste zum falschen Zeitpunkt drücken. Ich müsste > also erreichen, dass der Tastendruck einen D-Pin dauerhaft setzt, sodass > ich diesen dann im nächsten Durchgang der Schleife auswerten und wieder > loslassen kann. Und das ist, sofern er das Delay nicht verkleinern will mit yield, weniger delay oder mit Flip-Flops möglich. Wobei yield für meinen Geschmack gefählrich nahe an goto kommt. Aas Delay in einer Testanwendung, wie diese hier zu sein scheint, ist imho völlig ok. !!! ABER !!! Delays sollte man wo es geht vermeiden, indem man z.B. einen Timer im Hintergrund laufen lässt. Bei jedem Aufruf der Funktion (in dem Fall für das Display) checkt man nun ab ob der Timer bereits einen Grenzwert erreicht hat oder nicht. Ist der Grenzwert erreicht oder überschritten, führst du deine Funktion für das Display aus. In der Zwischenzeit kannst du mit dem Controller unter anderem den Knopf abtaste, und noch vieeeeels mehr machen lassen.
Schlaumaier schrieb: > if millis >= alte_millis + Zeit_wert then Böse Falle :-( Was meinst du wohl, was passiert, wenn alte_millis + Zeit_wert einen Überlauf produziert.
... und ganz übel wird's, wenn millis() überläuft.
Delay ist nur wichtig wenn man auf Externe Hardware warten muss. Einige Teile brauchen halt ihre Zeit bis sie Befehle abgearbeitet haben. Also wartet der MC halt, an genau DER Stelle. Ansonsten benutze ich immer die oben genannte Schleife. Besonders wenn in der Zeit noch was anders passieren kann/soll.
Wolfgang schrieb: > ... und ganz übel wird's, wenn millis() überläuft. Lesen und verstehen ist eine schwere Sache. Schlaumaier schrieb: > If Millis < alte_millis then alte_millis = 0 ' fängt den Millis überlauf > an Und schon ist das übel aus der Welt. Millis fängt nach den Überlauf wieder bei 0 an. Alte_millis sind aber bei X-Mio. Ergo werden in der Zeile alte_millis auf 0 gesetzt. Beim nächsten Lauf ist millis wieder größer alte_Millis und schon läuft es wieder rund. Unter speziellen Anwendungen kann das vielleicht Problematisch werden. Aber nicht bei einer Sensorabfrage die dann vielleicht mal ein paar Takte später erfolgt.
Schlaumaier schrieb: > Schlaumaier schrieb: >> If Millis < alte_millis then alte_millis = 0 ' fängt den Millis überlauf >> an > > Und schon ist das übel aus der Welt. Warum sollte man sowas tun? Denn das ist nicht exakt und damit fehlerhaft. Zudem kann man das auch fehlerfrei, mit weniger Aufwand, hinbekommen. Damit gib es keinen Grund die Krücke zu verwenden!
1 | using Millis = decltype(millis()); |
2 | |
3 | Millis zeitMerker; |
4 | constexpr Millis interval {1000}; //ms |
5 | |
6 | void setup() |
7 | {
|
8 | }
|
9 | |
10 | void loop() |
11 | {
|
12 | if(millis()-zeitMerker>=interval) |
13 | {
|
14 | zeitMerker += interval; |
15 | // hier tuwas()
|
16 | }
|
17 | }
|
EAF schrieb: > Warum sollte man sowas tun? Weil viele Wege nach Rom führen. Und ich nie behauptet habe das meine Routinen die besten sind. Ich behaupte nur sie funktionieren. ;) Zugegeben : Deine ist besser + kürzer. Werde sie mir also merken für das nächste Projekt. ;) DANKE
Obwohl deine auch ein Fehler hat. Nach den Überlauf ist millis 0 Was dann übersetet bedeutet : if(millis()-zeitMerker>=interval) if (0 - 1000) >= 1000 then Also hast du auch min. 1 eher 2-3 Zeitsprung-Fehler beim Überlauf.
3nibble schrieb: > Ich müsste also erreichen, dass der Tastendruck > einen D-Pin dauerhaft setzt Nein, der richtige Ansatz ist, dein Programm nicht anzuhalten. Schau dir die Erklärungen zum "Blink without delay" Beispiel an, da wird das thematisiert.
Schlaumaier schrieb: > Also hast du auch min. 1 eher 2-3 Zeitsprung-Fehler beim Überlauf. Nein! Der Unterlauf bei der Subtraktion kompensiert den Überlauf.
Wolfgang schrieb: > Schlaumaier schrieb: >> if millis >= alte_millis + Zeit_wert then > Böse Falle :-( > > Was meinst du wohl, was passiert, wenn alte_millis + Zeit_wert einen > Überlauf produziert. Kommt auf die Anwendung an, millis() ist ein vorzeichenloser 32-bit-Wert, läuft knapp 50 Tage (49,71) - Windows_95 lässt grüßen. Wenn die Anwendung dauerhaft laufen soll, muß man anders programmieren oder den Überlauf per Vergleich abfangen, kein Hexenwerk. Die größere Falle ist, die Variable korrekt als 'unsigned long int' zu deklarieren, ein normales 'int' kracht schon nach 32 Sekunden über. Das sind aber Nebenbaustellen, erstmal muß Arduino-Kind 3nibble (Gast) begreifen, ohne delay zu programmieren!
Schlaumaier schrieb: > if (0 - 1000) >= 1000 then > Also hast du auch min. 1 eher 2-3 Zeitsprung-Fehler beim Überlauf. Nein, das trifft nicht zu. Bei einem Überlauf kommt trotzdem genau die gewünschte Zeitspanne heraus.
EAF schrieb: > Zudem kann man das auch fehlerfrei, mit weniger Aufwand, hinbekommen. > Damit gib es keinen Grund die Krücke zu verwenden!
1 | if(millis()-zeitMerker>=interval) |
2 | {
|
3 | zeitMerker += interval; |
4 | // hier tuwas()
|
5 | }
|
Jou, ich gucke gerade in mein letztes Project, genau so habe ich es da gemacht :-)
Manfred schrieb: > if(millis()-zeitMerker>=interval) > { Nachteil, wenn irgendwo eine Sub oder Berechnung länger dauert bevor wieder millis() abgefragt wird ist der Tastendruck uralt. ausserdem wird nicht entprellt. Ich finde PeDas Timer IRQ und Entprellung definitiv besser, JEDER Tastendruck wird erkannt, entprellt und gespeichert bis zur Verarbeitung in der MAIN loop.
3nibble schrieb: > Ergebnisse im 10-Sekunden-Takt (delay(10000)) auf einem kleinen OLED > anzeigen bzw. aktualisieren. Hier ein Taktgeber der dir nichts blockiert:
1 | // Multivibrator Taktgeber |
2 | mvist = millis(); // Multivibrator |
3 | if(mvist - mvstart >= mvinterval){ |
4 | mvstart = mvist; |
5 | if(mv == LOW){ |
6 | mv = HIGH; |
7 | } |
8 | else { |
9 | mv = LOW; |
10 | } |
11 | } // Multivibrator Ende |
12 | if(mv != mvvorher){ // Multivibratorflanken |
13 | mvpuls = HIGH; |
14 | } |
15 | else{ |
16 | mvpuls = LOW; |
17 | } |
18 | mvvorher = mv; |
19 | |
20 | if(mvpuls == HIGH){ |
21 | strommessen(); |
22 | leistung(); |
23 | displaybeschreiben(); |
24 | } |
Alles klar! Keine Fragen! 1. Da wird keine Taste abgefragt. Das passiert ein paar Postings vorher. 2. Ja, das ist bei Kooperativen Multitasking so, egal wie kompliziert oder primitiv das konstruiert wurde. Das gerade laufende Codefragment muss aktiv Rechenzeit abgeben, damit andere Teile auch mal dran kommen. 3. Das muss dir ja gar nicht gefallen. Da gibt es keine Notwendigkeit.
EAF schrieb: > Alles klar! > Keine Fragen! Das bezieht sich natürlich auf: Joachim B. schrieb: > Tastendruck
3nibble schrieb: > Ich müsste > also erreichen, dass der Tastendruck einen D-Pin dauerhaft setzt, sodass > ich diesen dann im nächsten Durchgang der Schleife auswerten und wieder > loslassen kann. das kann ein if wenn tasterpin genau gleich high, dann bool taste gleich high. Dann bleibt der high.
Joachim B. schrieb: >> if(millis()-zeitMerker>=interval) >> { > > Nachteil, wenn irgendwo eine Sub oder Berechnung länger dauert bevor > wieder millis() abgefragt wird ist der Tastendruck uralt. > ausserdem wird nicht entprellt. Du möchtest gerne ein Problem herbeireden, was in 99% aller Anwendungen nicht existiert. Der einfache Mikroprofessor ist nun mal ein seriell arbeitendes Gebilde, wenn ein Job aktiv ist, müssen andere eben warten. Das Beispiel von EAF ist erstmal ein nicht blockierender Timer, nicht mehr und nicht weniger. Der ruft eine Unteroutine "// hier tuwas()" auf, deren Funktion hier nicht definiert ist. Dein Tastenproblem ist das denkbar unpassendste, kein Benutzer stört sich ernsthaft, wenn eine Taste mit ein paar Millisekunden Zeitverzug abgefragt wird. Ich werde einen Teufel tun, eine dusselige Taste in den Interrupt zu packen, der Professor hat wichtigere Dinge zu tun als den Knopf binnen Mikrosekunden zu bedienen.
Beitrag #7261177 wurde vom Autor gelöscht.
Danke für die vielen hilfreichen Antworten. Hätte ich mir die dicken Arduino-Schwarten eine Woche früher besorgt, hätte ich nicht fragen müssen. Danke. Gruß, 3nibbles
Manfred schrieb: > Du möchtest gerne ein Problem herbeireden, was in 99% aller Anwendungen > nicht existiert. vielleicht, ich weiss nur das ich darüber nicht mehr nachdenken muss seit ich PeDas Routinen verwende aber jeder wie er mag!
Käferlein schrieb: > Was ist das? OK ich suchte für dich https://www.mikrocontroller.net/articles/Entprellung Beitrag "Taster Entprellen von Peter Dannegger" Beitrag "Tasten entprellen - Bulletproof" Beitrag "Re: Tasten entprellen - Bulletproof" es ist also total egal was gerade an anderen Routinen läuft und wie lange, sobald die Main Schleife while(1) wieder an den Anfang kommt werte ich die Tastendrücke aus! In der IRQ alle 10ms zähle ich auch einen Counter hoch der bis 25 zählt um alle 250ms ein LCD oder OLED Ausgabe zu machen, mehr 4/s kann man eh nicht lesen, alle Ausgaben schreibe ich in ein Schattenram z.B. 90 Byte für 6 Zeilen a 14 Zeichen + /0 für Zeilenende. Ich schreibe wann und wo immer ich will in das Schattenram und wo immer sich Werte ändern und muss mich nicht mehr darum kümmern wann und wo, die Ausgabe erfolgt in der Main Schleife wenn 250 ms um sind und dann wird der Screen Counter auf 0 gesetzt.
:
Bearbeitet durch User
Viel zu aufwändig. Monoflop programmieren, fertig.
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.