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
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...
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.
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.
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!
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.
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:
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.
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.
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/EntprellungBeitrag "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.