Zwei .ino zusammenführen / Problem mit while im loop

Hallo zusammen.

Ich benötige eure Schwarmintelligenz. Ich habe zwei Sketche, die größtenteils eigenständig funktionieren.
In dem einen Sketch (Dashboard_working.zip) werden auf einem TFT diverse Werte ausgewertet und angezeigt. Unter anderem Temperatursensoren und das GPS Signal von einem Ublox Neo 6m.
Im selben Sketch wird die UTFT und UTFT_Button Lib von Henning Karlson genutzt. Leider ist der verbaute Touchcontroller am TFT nicht mit der Lib von H.K. kompatibel. Soweit so gut.

Im zweiten Sketch ist das Testprogramm des Touchcontroller und ebenfalls die UTFT+UTFT_Button von H.K sowie die Erfassung der GPS-Daten vorhanden.

Dies funktioniert insoweit auch. Leider hat das Testprogramm eine (für mich große) Hürde eingebaut. Sie lässt quasi die Funktion der Koordinatenabfrage innerhalb des loop solange im while laufen, bis die Voraussetzungen für den break erfüllt sind (Exit betätigen).

Solange bleibt der loop aber stehen und es werden natürlich keine Werte der Sensoren / GPS abgefragt. Ich hatte diverse Serial.print im Sketch verteilt und konnte im seriellen Monitor sehen, dass alle Daten genau einmal abgefragt werden, er in den loop springt, diesen aber nicht wiederholt.

Wenn ich das while entferne, dann läuft der loop durch, im seriellen Monitor sehe ich auch die Daten vom GPS und das der loop stetig durchlaufen wird, allerdings zeichnet er dann auch ständig die Buttons neu, was er ja nicht im Sinne des Erfinders ist. Wenn gewünscht, kann ich gerne kurze Videos anfertigen und verlinken.

Evtl kann mal ein Wissender über die Sketche schauen und mir einen Tip geben, wie ich die Beiden zu einem Funktionstüchtigen zusammenführen kann.

Im Anhang sind beide Sketche aufgeführt.

Vielen Dank für die Mühe.

Dashboard_working.zip (12.6 KB)

touchbutton_working.zip (4.28 KB)

Lowbird:
Ich benötige eure Schwarmintelligenz. ...

Je nach Tageszeit und Wochentag bin ich manchmal nur zu Blödheit fähig.

Deine Programme habe ich jetzt gar nicht angeguckt. Evtl. ist das Folgende also nicht sonderlich hilfreich.

Was Du vorhast klingt für mich jedenfalls wie etwas, das man am besten mit Klassen löst. Verpacke die diversen Dinge, die Du machen möchtest, in Klassen, die jeweils eine Methode haben, in der sie das durchführen, was sie in einer loop()-Runde machen sollen. Diese Methode rufst Du dann in loop() für jedes Ding auf. Wichtig ist, dass es keinen blockierenden Code gibt (wie jetzt die while-Schleife).

Hast Du schon mit Klassen gearbeitet?

Gruß

Gregor

In loop() sollten keine weiteren Schleifen den Ablauf blockieren, schließlich wird loop() ja selbst in einer Schleife ständig neu durchlaufen. Im einfachsten Fall kann dann jedes while(x) durch ein if(x) ersetzt werden, um ein Blockieren zu vermeiden.

das Dashboard_working hat innerhalb der Loop ein While(1). Damit bleibt das Beispiel schon dauerhaft in dieser Dauerschleife.

Im touchbutton_working hast du zwar dieses while in ein while (flag) geändert, setzt aber das flag nicht mehr auf 0.

Ich würde versuchen:

  • den GUI Teil im while(1) in eine extra Funktion auslagen und diese im loop aufrufen
  • den GPS Teil ebenso in eine extra Funktion auslagern und diese im loop einmal pro Sekunde abfragen

die extra Funktionen sind zwar nicht zwingend notwendig, machen den Code in diesem Fall wohl besser lesbar (bzw. schieben halt das Leseproblem aus der Loop in die Funktion).

Apropos lesbar: mit einem Strg-T kannst du die Einrückungen formatieren lassen. Probier es mal aus.

Hallo und danke für die hilfreichen Antworten.

Ich habe mich daraufhin erneut mit den beiden Sketchen auseinandergesetzt. Es ist nunmehr so, dass ein while im loop vermutlich sein muss.

Hintergrund ist, dass er nur bei Betätigung des Buttons der Button eingefärbt werden soll (von rot nach blau). Auch wenn ich das while durch if ersetzte, werden die Buttons stetig neugezeichnet.

Ich habe jetzt allerdings die Abfrage der Sensoren in while Teil mit eingebaut und nun erfolgt natürlich die stetige Abfrage der Daten.
Den GPS Teil habe ich wie von noiasca vorgeschlagen in eine eigene Funktion gepresst und die Abfrage erfolgt auch im while. Allerdings muss ich mir mal anschauen wie ich die Abfrage auf einmal pro Sekunde begrenze.
BlinkWithoutDelay scheint da wohl der richtige Ansatz zu sein, oder?

Somit ist zumindest erstmal die funktion gegeben, ob das allerdings der saubere Weg ist wage ich zu bezweifeln...

Danke euch erstmal für die Mühe

ja so wie blickwithout delay im Sekundenrhythmus GPS abfragen, scheint mir plausibel.
Ob du eine LED umschaltest oder deine GPS Funktion aufrufst, ist ja fast das gleiche :wink:

Lowbird:
Allerdings muss ich mir mal anschauen wie ich die Abfrage auf einmal pro Sekunde begrenze.

Wenn ich Dich richtig verstehe, möchtest Du unterm Strich erreichen, dass loop() nur einmal pro Sekunde durchlaufen wird.

Dazu merkst Du Dir am Anfang von loop(), wie der aktuelle Wert von millis() ist. Am Ende von loop() platzierst Du eine while()-Schleife, in der einfach nur geguckt wird, ob der neue millis()-Wert eine Sekunde „größer“ ist, als der gemerkte. Ungefähr so:

...
uint32_t millismerker=0;
...
loop()
{
  millismerker=millis();
  ...
  while (millis()-millismerker<1000)
  {}
}

HTH

Gregor

ich würde es eher streng nach "BlinkWithoutDelay" machen und nur EINMAL pro Intervall in die GPS Abfrage gehen:

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval){
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    // und nun
    gpsAuslesenUndWasWeisIchSonstNoch();

  }

gregorss:
Wenn ich Dich richtig verstehe, möchtest Du unterm Strich erreichen, dass loop() nur einmal pro Sekunde durchlaufen wird.

Dazu merkst Du Dir am Anfang von loop(), wie der aktuelle Wert von millis() ist. Am Ende von loop() platzierst Du eine while()-Schleife, in der einfach nur geguckt wird, ob der neue millis()-Wert eine Sekunde „größer“ ist, als der gemerkte. Ungefähr so:

...

uint32_t millismerker=0;
...
loop()
{
  millismerker=millis();
  ...
  while (millis()-millismerker<1000)
  {}
}




HTH

Gregor

Da kannst Du auch gleich delay() nehmen. Das ist kürzer und blockiert genau so.

Gruß Tommy

Guten Morgen. :slight_smile:

Ich möchte auf jeden Fall verhindern das eine Blockade entsteht. Jede zeitliche Verzögerung im loop sorgt u.U für eine verzögerte Toucherkennung.

Und das soll nicht passieren. Fühlt sich dann so an wie man es evtl vom Smartphone oder Tablet kennt wenn es hängt.

Gregor, der loop soll ständig und mit möglichst geringer Verzögerung durchlaufen werden. Nur so ergibt sich ein "flüssiges Touchgefühl" :slight_smile: . Aber innerhalb des loop sollen die Daten des GPS nur jede Sekunde ausgelesen werden, da diese Daten nicht zeitkritisch sind.

Sobald ich wieder zuhause bin, werde ich mich an die Umsetzung machen. Den Vorschlag von noiasca werde ich versuchen umzusetzen.

Danke nochmal an dieser Stelle für die Hinweise und Unterstüzung.

Gruß Chris

Aber innerhalb des loop sollen die Daten des GPS nur jede Sekunde ausgelesen werden, da diese Daten nicht zeitkritisch sind.

Die GPS die ich kenne, werden nicht abgefragt sondern plappern vor sich hin, und liefern jede Sekunde einen Datensatz. Stichwort: Nicht blockierend einlesen. Wenn der Datensatz komplett ist, kannst du ihn auswerten und dazwischen tausendemale auf deinen Touch reagieren.

Das Beispiel Simple_Test aus der TinyGPS library ist in dieser Hinsicht suboptimal.

Statt

  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;

geht besser

    if (ss.available())
    {
      char c = ss.read();
      if (gps.encode(c)){
        // auswerten ...
      }
    }

Hallo Michael,

genau das meine ich... Das GPS liefert in der Geschwindigkeit der Baudrate dauernd seine Werte über den seriellen Port. Ich möchte daher diese Werte nur einmal die Sekunde abfragen ohne den Touch zu blockieren.

Deine Variante hatte ich bereits im Sketch so vorgesehen, allerdings wirft es mit dieser Variante keine Daten mehr im seriellen Monitor aus.

Tante Edit sagt: " Man sollte nicht nach dem SuperBowl solche Sachen angehen, wo Konzentration gefragt ist... Dein Beispiel funktioniert jetzt, ich hatte aus Versehen die Abfrage der Funktion im loop entfernt." :frowning:

Ich habe das Parsen der Daten auf 20ms gedrückt. Das ist das Minimum mit den wenigsten Errors aber es setzt newData auf true.

void satgps () {


  //****************************************GPS-TEIL*****************************************
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  // for (unsigned long start = millis(); millis() - start < 20;)
  //{
  if (ss.available())
  {
    char c = ss.read();
    Serial.write(c); // uncomment this line if you want to see the GPS data flowing
    if (gps.encode(c)) // Did a new valid sentence come in?
      newData = true;
  }
  //}

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }

  //  gps.stats(&chars, &sentences, &failed);
  //  Serial.print(" CHARS=");
  //  Serial.print(chars);
  //  Serial.print(" SENTENCES=");
  //  Serial.print(sentences);
  //  Serial.print(" CSUM ERR=");
  //  Serial.println(failed);
  //  if (chars == 0)
  //    Serial.println("** No characters received from GPS: check wiring **");
}
//****************************************GPS-TEIL*****************************************

Wenn das GPS tatsächlich unaufhörlich plappert, und nicht nur jede Sekunde eine Zeile, kannst du ja das Mitlesen vom Auswerten trennen.

Ich habe das Parsen der Daten auf 20ms gedrückt

Wenn du in jedem loop Durchlauf nur einen Buchstaben vom GPS lesen musst und am Zeilenende auswerten, blockiert dich das nie im Millisekunden-Bereich, da hast du also parallel noch viel Zeit für anderes.
Wobei Touchscreen jetzt keine sooo anspruchsvolle realtime Anforderung ist.

Darfst natürlich nicht mehr Serial - Debug-Ausgaben machen als in den Puffer und auf die Leitung passen, wenn das nicht blockieren soll. (9600 Bd = 1ms/Zeichen:Bei 90 Zeichen verzögern die letzten 24 Zeichen also 24 ms lang)

Tommy56:
Da kannst Du auch gleich delay() nehmen. Das ist kürzer und blockiert genau so.

Ja, stimmt :slight_smile: Es entspricht aber eher dem, wie ich den OP verstanden hatte (und das war offensichtlich falcsh). Immerhin kann man im (bei mir leeren) while()-Körper aber noch Sachen machen wie Taster abfragen. Mit delay() hat man halt eine pure Blockade.

Gruß

Gregor

Hi

Jain - Da könnte man yield nehmen :wink: (sofern, meinem Verständnis nach, die Funktion yield() immer wieder von delay aufgerufen wird, wenn die Zeit noch nicht um ist)

MfG

yield() ist auf AVR-Systemen eine Dummyfunktion. Dafür gedacht, wenn jemand kooperatives Multitasking bauen will.
Es wird pro Sekunde einmal in delay() aufgerufen (nicht in delayMicroseconds()).

Gruß Tommy