[Home]
[SpannungsVersorgung]
[Labornetzteile]
[ESP32]
[SchrittmotorTechnik]
[TemperaturSensoren]
[Delay oder Millis() ?]
[I2C - Bus]
[Eigenbau Geräte]
[Multiprocessing  32Bit]
[Schalten & Regeln]
[Temp. od. Licht Kontr.]
[D>A Convert 0-10 V]
[Die Uhr DS3231]
[Sensor Schield]
[Töne ausgeben]
[Ultraschall -Sensoren]
[LCD Display]
[SMS über GSM]
[Fehler- & Störungssuche]
[Voltmeter]
[Lüfter-Steuerung]
[Raumluft CO2]
[Frästisch]
[Akkubox für 5 Volt]
[Controllino]
[Siemens Logo 8]
[Arduino FAN´s]
[Woran ich  Arbeite]
[Alte Technik]
[Kontakt]

 

Zum Technik Forum

Banner_2021

Weil das Thema millis() immer wieder ein Problem zu sein scheint, habe  ich hier mal ein Programm eingestellt, das seine drei verschiedenen  Zeiten rein durch millis() kontrolliert und steuert.
Ich denke die Erklärung hinter den Befehlszeilen ist so, dass man es verstehen sollte. Das  Programm Block2 sorgt im Betrieb dafür, dass die LED am Pin13 (Pin13-LED beim Uno&Mega auf der Platine vorhanden) immer eine Sekunde an ist  und eine Sekunde aus. Aber wehrend der Sekunde wo die LED aus ist, greift der  Programm-Block3, der im 100ms Abstand die selbe LED ein / aus schaltet.
Am Pin11 kann man eine Taste gegen GND anschliessen, die dafür sorgt,  dass immer sofort nach dem Druck der Taste die selbe LED durchgehend 5  Sekunden an bleibt. Also 5 Sekunden an ist die Quittung dafür, dass der  Tastendruck erkannt wurde. So sieht man, dass egal wo sich das Programm  gerade befindet IMMER der Tastendruck erkannt und die zugehörige  Funktion (5 Sekunden LED an) ausgeführt wird.

Ein kompletter Durchlauf dieses Programmes hier dauert übrigens auf  einem Arduino-Mega 16 - 20 microsekunden. Also 16-20 Millionstel  Sekunden. Das nur mal, weil so oft für jeden Käse gleich Interrupte  programmiert werden. Hier sieht man, dass eine Abfrage eines Pins in dem Programm alle 16-20 Millionstel Sekunden durchgeführt wird. Also z.B.  die Abfrage der Taste auf Pin11 in dem Programm.

Es wird also in einer Sekunde 50.000x der Pin11 abgefragt!!! Natürlich ist es übel, wenn man z.B. einen einzigen delay(1); im Programm hat, wird  aus 50.000x gleich nur noch 1000x pro Sekunde !!!
Mit einem einzigen delay(100); im Programm wird nur noch 10x in der  Sekunde die Pin11 Abfrage durchgeführt !!! Das reicht bereits, um einen kurzen Tastendruck nicht mehr erkennen zu können!! Also der ganze Loop wird nur  noch 10x pro Sek. durchfahren!!! Wenn ich jetzt hier ins Programm einen  delay(1000); einbaue, dann wird es schon extrem unwahrscheinlich dass  ich die Taste zu dem Zeitpunkt drücke, wo der Pin auch abgefragt wird. 1 Sekunde geht nichts, dann wird für 10 Millionstel Sek. der Port  abgefragt, dann wieder eine Sekunde Pause, dann wird wieder für 10  Millionstel Sek. der Port abgefragt, ...........u.s.w. Es ist also wie  ein Sechser im Lotto, wenn man da die Taste dann drückt, wenn der Port  gerade abgefragt wird.

Das sagt wohl deutlich aus, wo das Problem bei den meisten Programmen  liegt, wenn die Tastenabfrage nicht mehr funktioniert. Auch die Ausgabe  auf ein Display ist eine gewaltige Bremse. Die darf man nur so oft wie  unbedingt nötig durchführen. Nicht in jedem Loop Durchgang. Das wäre ein gewaltige Bremse. Auch sollte man nur die Werte im Display ändern, die sich wirklich erwähnenswert geändert haben. Das kann man gut kontrollieren, indem man den Wert, der an das Display gegeben wurde z.B. in “WertAlt” speichert, dann den neusten Wert in z.B. “WertNeu”, so kann man dann WertAlt <-> WertNeu vergleichen und sieht dann ob er sich so geändert hat, dass man ihn ans Display geben muss. Namen / Bezeichnungen die man am Display braucht, gibt man wenn möglich nur einmal oben im “void setup()” ans Display.

Ich habe mal diese Zeile hier unten eingefügt und dann getestet wie lange ein Programmdurchlauf dauert, wenn der Controller nur eine Serial.print() Nachricht ausgeben muss.
 

Serial.println("Das ist ein Test mit Millis und Micros");


Mit 9600Baud waren das 41620 Microsekunden oder 41,62 Millisekunden.
Mit 115200Baud waren es nur noch 3412 Microsekunden oder 3,412 Millisekunden.
Also auch das ist ein erheblicher Unterschied.

Ich habe hier noch ein Programm eingefügt, das auch ausschließlich mit Millis arbeitet und damit alle Zeiten, wie Tastenentprellen, LED Leuchtzeiten, LCD Display Anzeige Tackt, u.s.w. steuert. Man braucht delay´s eigentlich für absolut nichts. Und es ist auch extrem schlecht, wenn man es benutzt. Es stoppt die Abarbeitung von allen was sonst noch im Loop steht. Dieses Programm hier hat eine Durchlaufzeit von 200 - 204 Microsekunde (Millionstel Sekunden), oder 0,2 Millisekunden (Tausendstel Sekunden). Nur jede Sekunde werden Uhrzeit und PWM Wert aufs LCD Display ausgegeben, da ensteht dann immer einmal eine Durchlaufzeit von 34 Millisekunden. Das ist die Zeit die für die LCD Display Ausgabe gebraucht wird.

Bei der LCD Ausgabe könnte ich noch etwas sparen, indem ich den PWM Wert nur dann ausgebe, wenn er sich verändert hat. Das könnte ich auch mit der Uhrzeit machen, ich denke da werde ich in den nächsten Tagen eine Programmänderung in diese Richtung nachschieben.

Hier ist mal ein Video, der zeigt was das Programm macht das ich hier unten eingefügt habe . Es ist wie gesagt nur eine Demo zum Thema millis() statt delay(). Man kann es natürlich auch als Grunddstock für Programme nehmen. Man hat Tastenabfragen, Ausgänge die getaktet werden, einen Poti Eingang der abgefragt wird, PWM Ausgänge, einen Tonausgang, eine Uhrenplatine wird abgefragt, ein LCD Display 4x20 wird gesteuert. Also eine ganze Menge. Man kann einfach löschen was man nicht braucht, und das andere als Grundstock für ein Programm nehmen, das man dann nur noch anpassen muss.

Hier habe ich mal meine Serial.print Ausgabe aufgezeigt. Leider komme ich mit dem Stativ nicht so nahe an den Bildschirm, deshalb musste ich die Kamera in der Hand halten und es ist sehr verwackelt. :-(((  Aber die Information zählt. Man sieht hier sehr schön, dass jeder Durchgang des Programmes 176 Microsekunden dauert. Alle 17 Durchgänge sind es 180 Microsekunden. Wenn dafür jemand eine Erklärung hat, dann her damit. Würde mich schon interessieren. Andererseits sind diese 4 Millionstel Sekunden jetzt nicht so das Problem :-)))
Wichtig ist, dass man sieht, dass auch die kleinste Änderung im Display einen extrem großen Zeitaufwand im Vergleich zur normalen Durchlaufzeit bedeutet. Man muss also mit den Ausgaben am Display so sparsam wie möglich sein, wenn die Laufzeiten des Programmes eine Rolle spielen. Die Ausgabe auf ein Display ist nach den delay() Befehlen das, was am meisten Zeit raubt. Und dann sind da noch die Serial.print() Ausgaben, die man nur zur Fehlersuche bemühen sollte.

Übrigens habe ich im Programm inzwischen die Ausgabe des PWM Wertes nicht mehr jede Sekunde, sondern nur noch wenn er sich verändert hat. Das spart natürlich auch wieder viel Zeit im Programmablauf. Der PWM Wert wird übrigens nicht unten mit “0” begonnen, sondern mit “25”, weil der PWM geregelte Motor, den ich hier anschließen könnte, erst ab etwa 25 zu laufen beginnt. Deshalb habe ich das im “map” Befehl so angelegt, dass die Ausgabe von 25 bis 254 geht.

Ich habe jetzt das Programm in der Display - Ausgabe noch ein bisschen optimiert, und habe daher jetzt nicht mehr jede Sekunde einmal 27000 Microsekunden Programm Durchlaufzeit, sondern nur noch jede Minute einmal 21270 Microsekunden. Da mache ich jetzt aber nicht mehr extra einen neuen Video davon. Aber die Änderung ist in dem verlinkten Programm hier enthalten. Es wurde mit der Minuten Kontrolle etwas kompliziert. Wenn ich nicht mehr jede Sekunde die Zeit auslese, habe ich auch keine aktuellen Sekunden mehr zur Verfügung. Ich muss mir diese Übersicht  also anders besorgen.

Ich gehe zum Start des Programmes einmal zum auslesen der Uhrzeit. Da hole ich mir einen Wert, der heißt “eineminute”. Der wird bei der Zeitausgabe berechnet, indem ich (60 - sekunden) * 1000 rechne. Somit habe ich die Millisekunden bis zur nächsten Minuten Umstellung, Man könnte meinen, Schwachsinn, bis zur nächsten Minuten-Umstellung sind es immer 60000 millis. Ja, ausser beim Starten des Programmes. Da wird die Zeit aufs Display gegeben und da sind es nur bei maximalen Glück 60 Sekunden bis die nächste Minute fällig ist. Deshalb der Aufwand. Die Uhr hätte sonst immer ihren eigenen Minutentakt, je nachdem, wann das Programm startet. Auch diese Umstellung ist in dem Programm hier unten enthalten.

Ich habe jetzt auch mal im Forum das Thema Delay´s oder Millis aufgriffen. Dazu habe ich im Forum auch mal ein kleines Programm erstellt, das mit Millis arbeitet. Ich hoffe ich habe es dort auch nochmal gut erklärt. Es scheint kompliziert zu sein, solange man das Programm mit millis mit der Funktion delay() vergleicht. Man muß im Kopf weg vom Delay Befehl. Dieser Befehl stoppt an der Stelle, an der er steht das Programm für die Zeit, die dort in Klammern steht. Deshalb ist das überhaupt keine Ähnlichkeit mit dem Arbeiten mit Millis. Das ist nicht das gleich, sonder der absolute Gegensatz. Bei der Arbeit mit Millis läuft das Programm im Loop immer vollgas durch. Kleine Programme in 100-200 Microsekunden also Millionstel Sekunden!! für einen Durchlauf. Also bitte unbedingt, wenn man versucht das Programm zu verstehen, nicht nach der Bremse suchen, wie das delay() arbeitet, das ist sinnlos. Die “Bremse” gibt es ja eben nicht, wenn man mit millis() arbeitet. Bei Millis wird nur im Loop an einem bestimmten Punkt kontrolliert, ob eine bestimmte Zeit abgelaufen ist, nach der eine Aktion EINMAL ausgeführt werden muss. Dann wird die Aktion ausgeführt, die Millis für die neue Laufzeit aktualisiert, und alles läuft weiter. Das heißt, alles, vor und nach dieser Aktion läuft weiter, nur die Aktion, die eine bestimmte Wartezeit braucht wird für diese Zeit nicht ausgeführt, sondern übersprungen.

Arduino, Uno, Mega, RC3231, Schrittmotor, Treiber, RFID, DC, RC, 5 Volt, 3,3 Volt, PWM, Pin, Analog Pin, https://www.nof-schule.de/forum/