Unterschiedliche Ausführgeschwindigkeiten

Hurra

kulturbereicherer:
... Leider funktioniert der Taster mit dem delay nicht mehr richtig ...
... Den Code kann ich hier schlecht posten ...
Ist es überhaupt möglich "unterprogramme" funktionen langsamer auszuführen während der Hauptloop weiter schnell arbeitet?

Du schreibst von delay()s, zeigst aber den Code nicht. Das ist ... äh ... ungünstig. Zumindest mir bleibt da nur die Stocherei im Nebel, worauf ich überhaupt nicht stehe.

Man kann Unterprogramme langsamer als den Hauptloop machen, wobei mir da spontan auch nur delay()s einfallen (und die Frage, warum man sowas machen wollen sollte). Im Allgemeinen wird Code gleich schnell ausgeführt, unabhängig davon, ob er sich im loop() oder sonstwo befindet.

Gruß

Gregor

Entferne die delays und arbeite mit millis. Sieh dir dazu BlinkWithoutDelay an.
Das findest du in den Beispielen der IDE.
Oder hier.

Pausen dürfen nicht mit delay() gemacht werden da während delay() keine anderen Funktionen ausgeführt werden.

Du mußt wie HotSystems vorschlägt die Wartezeiten mit millis() realisieren. Einfach gesagt Du kontrollierst ob eine gewisse zeit um ist und machst dann die Aktion. Während des millis() -Kontrollierens kannst Du andere Sachen auch noch mitmachen.

Grüße Uwe

kulturbereicherer:
Ist es überhaupt möglich "unterprogramme" funktionen langsamer auszuführen während der Hauptloop weiter schnell arbeitet?

Ich sage immer: Was Du in deutscher (oder englischer) Sprache als gewünschten Ablauf grammatikalisch und logisch einwand- und widerspruchsfrei formulieren kannst, das kann man auch programmieren.

Und natürlich ist es ein leichtes in der loop diverse Tasks aufzurufen, zum Beispiel zehntausendmal pro Sekunde, aber die Tasks selbst arbeiten asynchron und führen ihre Aktion nur wesentlich seltener aus.

Wenn ich zum Beispiel ein Programm für ein halbes Dutzend Tastschalter mit RTC und LCD schreibe, dann achte ich drauf, dass

  • die loop() Funktion möglichst zehntausendmal pro Sekunde läuft
  • die Tastschalter aber nur alle zwei Millisekunden abgefragt werden (software-Entprellung)
  • die RTC circa hundertmal pro Sekunde abgefragt wird
  • und das LCD ggf. aber nur einmal pro Sekunde aktualisiert wird, z.B. beim Sekundenwechsel oder wenn eine Interaktion durch Tastendruck es erfordert, andere Inhalte auf dem Display zu zeigen.

Und wenn der Platz auf einem 1602 Display nicht ausreicht, um alles gleichzeitig anzuzeigen, was eigentlich gleichzeitig angezeigt werden soll, dann mache ich mir eine "automatische Wechselanzeige", die vollkommen ohne Eingriff des Benutzers automatisch zeitgesteuert durchwechselt

  • zwei Sekunden lang Uhrzeit/Datum
    zwei Sekunden lang Temperatur/Luftfeuchte
    zwei Sekunden lang andere Informationen
  • danach wieder von vorne.

So dass es ggf. drei oder vier "virtuelle" Displayanzeigen gibt, die sich zeitgesteuert automatisch abwechseln. So bekommst Du dann mit vier virtuellen Anzeigen auf einem1602 LCD das unter, was zur gleichzeitigen Darstellung eigentlich vier 1602 LCDs erfordern würde. Der Benutzer muß dann aber ggf.bis zu sechs Sekunden warten, bis er "alles einmal gesehen" hat. Und eine laufende Uhrenanzeige ist dann zumindest in den Sekunden etwas weitergelaufen, eventuell sogar die Minute umgesprungen, bis das nächste mal für eine kurze Weile wieder Datum/Uhrzeit angezeigt werden.

Ein mit 16 MHz getakteter UNO kann 16 Millionen Controller-Instruktionen pro Sekunde ausführen. Und ob ein Programm den Controller mit delay(1000) für eine Sekunde lang blockiert zbd 16 Millionen Instruktionen vollkommen ungenutzt läßt, oder ob das Programm in derselben Zeit 100 nützliche Aufgaben erfüllt, das ist nur Sache des Programmierers bzw. des Programms.

Also sollen wir weiter raten ?
So wird dein Problem sicher nicht lösbar.
Zeige uns deinen Sketch und wir können helfen.
Und wenn es mit millis nicht funktioniert, hast du etwas falsch gemacht.
Aber es liegt ganz bei dir, ob wir helfen können.

kulturbereicherer:
Ich habe diverse Codes zusammengewürfelt. Manche stehen unter irgendwelchen Lizenzen. Ich hab keine Lust auf eine Abmahnung weil irgendwer seinen Code in dem Listing wiedererkennt ohne 100% genaue Lizenz- und Quellennennung. Siehe jüngstes Urteil aus Hamburg wo wegen einer Lapalie (es wurde nicht dazu geschrieben dass das Bild verändert wurde) zu teuren Abmahnungen führte und das auch noch bei dritten die nur darauf verlinkt haben.

Nunja ... wenn Du wegen Lizenz-Scheiß Deinen Code nicht zeigen möchtest, dann kann man Dir schlecht helfen. Dann solltest Du beim Programmieren nichts verwenden, das nicht von Dir ist. Oder eben mal einen kurzen Blick auf die rechtlichen Bedingungen für die Verwendung derlei Sachen werfen.

Und wenn sich Leute, die auf etwas lizenzrechtlich Bedenkliches verlinkt haben, deshalb abmahnen lassen, dann sind die IMO ziemlich dämlich. Hatten die keine entsprechenden rechtl. Hinweise auf Ihren Seiten?! Oder hat sich diesbezüglich die Rechtslage derart geändert, dass man trotz solcher Hinweise wegen so einem Scheiß abgemahnt werden kann?!

Gruß

Gregor

kulturbereicherer:
Ich hab die Tastendauererkennung von 80 auf 3 runter gedreht. So funktioniert es vorerst ohne das man einen halben Monat den Taster drücken muss :slight_smile: Ich werde mir die nächsten Tage die Mils Beispiele anschauen und durchprobieren, vielleicht klappt es ja dann das zusammengewürfelte zu verbessern

Na ok, dann konnten wir dir ja ein wenig helfen.
Also raten geht doch noch, wenn es auch schwieriger ist. Aber wir geben unser Bestes.

kulturbereicherer:
Den Code zusammen würfeln ist ja nicht das Problem ...

Doch, das Zusammenwürfeln von Code ist der Kern des Problems.

Gruß

Gregor

ich habe mir jetzt mal, mehrfach, den Thread von oben bis unten durchgelesen..

Und ja, du hast mein volles Mitgefühl!

Tipp:
Und wenne dann fertig bist, mit jammern, dann kannst ja mal schauen ob du eine Lösung für deine ganzen Probleme findest.

kulturbereicherer:
:slight_smile: Klingt schön, nur wie umsetzen?

Da gibt es verschiedene Möglichkeiten.

Ich habe Dir mal ein kleines Beispielprogramm mit 3 asynchronen Tasks gemacht

void setup() {
  Serial.begin(9600);

}

void readTimeFromRTC(unsigned long now)
/*Simulation einer Funktion, die alle50ms eine Funktion ausführt, 
 * z.B. ein RTC-Modul auslesen
 */
{
  static unsigned long lastReadTime;
  if(now-lastReadTime>=50)
  {
    // do it!
    Serial.print('Z');
    lastReadTime=now;
}
}

void readTemperature(unsigned long now)
/*Simulation einer Funktion, die alle 10s eine Funktion ausführt, 
 * 
 *z.B. eine Temperatur messen
 */
{
static unsigned long lastReadTime;
if(now-lastReadTime>=10000)
{
  // do it!
  Serial.println("Temperatur messen");
  lastReadTime=now;
}
}

void updateDisplay(unsigned long now)
/*Simulation einer Funktion, die einmal pro Sekunde eine Funktion ausführt, 
 * 
 *z.B. einen angezeigten Text aktualisieren;
 */
{
static unsigned long lastUpdateTime;
if(now-lastUpdateTime>=1000)
{
  // do it!
  Serial.print("\nTime counting: ");
  Serial.println(now/1000);
  lastUpdateTime=now;
}
}


void loop() 
{
  unsigned long now=millis();
  readTimeFromRTC(now);
  readTemperature(now);
  updateDisplay(now);

}
  1. Alle 50 Millisekunden eine RTC auslesen, simuliert durch Ausgabe des Buchstabens 'Z' auf Serial
  2. Einmal pro Sekunde ein Display aktualisieren, simuliert durch Ausgabe eines Sekundenzählers
  3. Einmal alle 10 Sekunden eine Temperaturmessung, simuliert durch Ausgabe " Temperatur messen"

Lade Dir das Beispiel hoch und öffne den seriellen Monitor!

Bekommst Du nach Durchsicht des Codes eine Idee davon, wie man es in einem Programm machen könnte, dass manche Sachen häufiger und andere Sachen seltener ablaufen?

Für ein Programm mit laufender "Uhrzeitangabe mit Sekundenanzeige" würde man die Programmlogik allerdings noch ein wenig synchronisieren müssen, so dass die Ausgabe nicht dann erfolgt, wenn der interne millis() Zeitzähler um 1000 weiter gezählt hat, sondern man würde die Ausgabe immer dann machen, wenn die RTC auf eine neue Sekunde umgesprungen ist.

Grund: Die "interne Zeitzählung von Arduino-Boards ist oft grottenschlecht ungenau, mit Abweichungen von bis zu 0,8%, also 8 Sekunden auf 1000 Sekunden. Die Zeitzählung einer RTC ist um ein vielfaches genauer. Wenn Du hier beim Anzeigen der sekundengenauen Zeit nicht der RTC-Zeit den Vorzug geben würdest, kann es alle paar Minutenpassieren, dass entweder eine Sekunde doppelt angezeigt wird, also dieZeitin der Anzeige für zwei Sekunden identisch stehen bleibt, oder dass die Sekunde in der Zeitanzeige plötzlich auf einmal zwei Sekunden vorwärts springt, obwohl sie um 1 weiter zählen sollte.

Also für genaue Zeitzählungen über längere Zeiträume immer RTC-Zeit verwenden und nicht die boardeigene interne Zeitzählung!

jurs:

  1. ...
  2. ...
  3. ...

Klasse, das rettet mir den Tag! So gut bekommt das sonst nur der quersche Söder hin!

Wenn es wirklich vier Punkte gäbe, hieße der vierte 8 – das ist ja wohl logisch.

Leute, die sich mit Computern befassen, haben halt zwei an der Waffel. Mindestens!

Gruß

Gregor

Leute, die sich mit Computern befassen, haben halt zwei an der Waffel. Mindestens!

Morbus Balsen.

gregorss:
Klasse, das rettet mir den Tag!

Ich lege nochmal nach und habe noch einen zusätzlichen Task draufgelegt, der folgendes zusätzlich macht:

In der loop() Funktion zählt eine Zählvariable (loopCount) bis 5000 hoch und gibt dann einen Wert dafür aus, wieviele loop() Durchläufe "pro Sekunde" das Programm schafft.
In der loop() Funktion is ein kleines delay von einer Millisekunde (delayMicroseconds(1000) enthalten

Da könnte man meinen: 1000 Mikrosekunden (eine Millisekunde) ist doch nicht viel, aber das bei jedem Schleifendurchlauf, das läppert sich ganz schön zusammen!

Aber vergleiche mal dieses Programm:

void setup() {
  Serial.begin(9600);

}

void readTimeFromRTC(unsigned long now)
/*Simulation einer Funktion, die alle50ms eine Funktion ausführt, 
 * z.B. ein RTC-Modul auslesen
 */
{
  static unsigned long lastReadTime;
  if(now-lastReadTime>=50)
  {
    // do it!
    Serial.print('Z');
    lastReadTime=now;
}
}

void readTemperature(unsigned long now)
/*Simulation einer Funktion, die alle 10s eine Funktion ausführt, 
 * 
 *z.B. eine Temperatur messen
 */
{
static unsigned long lastReadTime;
if(now-lastReadTime>=10000)
{
  // do it!
  Serial.println("Temperatur messen");
  lastReadTime=now;
}
}

void updateDisplay(unsigned long now)
/*Simulation einer Funktion, die einmal pro Sekunde eine Funktion ausführt, 
 * 
 *z.B. einen angezeigten Text aktualisieren;
 */
{
static unsigned long lastUpdateTime;
if(now-lastUpdateTime>=1000)
{
  // do it!
  Serial.print("\nTime counting: ");
  Serial.println(now/1000);
  lastUpdateTime=now;
}
}


unsigned long time;
unsigned int loopCount;

void loop() 
{
  unsigned long now=millis();
  readTimeFromRTC(now);
  readTemperature(now);
  updateDisplay(now);
  
  loopCount++;delayMicroseconds(1000);
  if (loopCount==50000) //loop has run 50000 times
  {
    float loopsPerSecond=loopCount/((now-time)*0.001);
    Serial.print("loops per second: ");
    Serial.println(loopsPerSecond);
    loopCount=0; // reset counter
    time=now; // reset time
  }
}

-...und dann lösche mal das delayMicroseconds(1000); heraus und lasse nochmal laufen!

Die Version, die das kleine delay() von einer Millisekunde in jedem loop() Durchlauf drin hat, schafft natürlich weniger als 1000 loop() Durchläufe pro Sekunde und braucht knapp über 50 Sekunden Laufzeit, bis es einmal auf 50000 hochgezählt hat.

Und sobald Du das delay() aus dem Programm herauslöscht, rennt es plötzlich über 50 mal schneller.

Soviel zum Thema "eine Millisekunde ist doch nicht viel".
Alleine für sich genommen zwar nicht.

Aber in einem effektiv programmierten Programm, dessen loop() Funktion viele Tausend male pro Sekunde durchläuft, sinkt die Performance auf einen Bruchteil des ursprünglichen Wertes.

Ich messe beim Programm mit delayMicroseconds(1000) in der loop Funktion

loops per second: 978.26

Und im ansonsten funktionsgleichen Programm ohne delayMicroseconds(1000) messe ich (
loops per second: 65274.15 (etwas schwankende Werte)

Bei fast identischer Funktionalität: Kleines -delay() - großer Unterschied!

kulturbereicherer:
Danke an alle, insbesondere jurs für das Codebeispiel. :smiley:

Bitteschön!

kulturbereicherer:
... Ich habe mir damals schon mal die Finger verbrannt als ich paar Zeilen Text einer anderen Internetseite in meine Einbaute. 380 Euro hat das gekostet...

Sag' bloß, Du hast einen Anwalt bezahlt, den Du nicht beauftragt hast?!

kulturbereicherer:
„Mitgefühl und Liebe sind wertvolle Dinge im Leben. Sie sind nicht kompliziert. Sie sind einfach, aber sie sind schwierig zu praktizieren.“ Tendzin Gyatsho - 14. Dalai Lama

Wer programmieren kann und klug genug ist, einen Anwalt nicht zu bezahlen, den er nicht bestellt hat, ist klar im Vorteil
(ich)

Gruß

Gregor :wink: