Anfängerfrage zu Berechnung mit unterschiedlichen Datentypen

Hallo zusammen,

mein Sketch läuft nicht so wie er soll. Bei der Fehlersuche habe ich es auf die Berechnung einer If-Bedingung eingrenzen können.
Was passiert, ist mir ansatzweise auch mittlerweile klar; aber wie geht es richtig?

if ((millis() - lTempMessung - TempConvertZeit) > TempIntervall)

[unsigned long] - [unsigned long] - [unsigned int] könnte auch negative Ergebnisse haben und läuft dann über. Der resultierende Wert ist ungewollt > [unsigned long] TempIntervall

      Serial.println(millis() - lTempMessungA - TempConvertZeit);
      Serial.println((int)millis() - lTempMessungA - TempConvertZeit);

liefert für einen positven Fall
60014 -> richtig für Vergleich
4294961774 -> schon übergelaufen

Ich interpretiere, das "(int)" gibt nicht den Datentyp des Ergebnisses vor, sondern wandelt den Wert von millis in einen int-Wert?

Vielen Dank für eure Erklärungen. Das bestimmt schon mal jemand gut erklärt, aber ohne passende Suchbegriffe findet man nur wesentlich kompliziertere Fälle, die helfen mir gerade nicht weiter.

Freundliche Grüße

Frank

Ja, (int)millis() wandelt den Rückgabewert von millis() in ein int. Das Ergebnis ist sehr selten richtig.

Die richtige Bedingung (damit auch der Überlauf nach ca. 49 Tagen funktioniert):

// alle xxx_millis-Variablen unsigned long
if (aktuelle_millis - letzte_millis >= intervall) {
  letzte_nillis = aktuelle_millis;
  // tu was
}

Gruß Tommy

Hallo Tommy,

vielen Dank für deine Antwort.

aktuelle_millis - letzte_millis >= intervall reicht mir leider nicht, da ich zwei Werte abziehen muss:

(millis() - lTempMessung - TempConvertZeit) > TempIntervall

Gehen würde
(millis() - lTempMessung) > (TempIntervall + TempConvertZeit)

Verständlicher finde ich die Subtraktion von zwei Werten, wenn ich den Code in x-Jahren wieder sehe, deshalb würde ich gerne wissen, wie ich das mit den Datentypen machen muss.

Den Überlauf fange ich so ab:
// Prüfung ob Millis übergelaufen sind
if (millis() < lTempMessungA)
{
lTempMessungA = 0;
}

Für was soll denn die TempConvertZeit gut sein? Das klingt nach Umrechnungszeit. Wenn die nicht größer als das Intervall ist, spielt die doch keine Rolle. Ansonsten hast Du ein ganz anderes Problem.

Beschreibe doch mal etwas genauer, was es werden soll.

Wenn, dann würde ich sie ins Intervall verschieben und immer >= sonst verschenkst Du unter Umständen 1 ms.

Gruß Tommy

TempConvertZeit ist die Umrechnungszeit für DS18B20 Temperatursensoren.

Bei (millis() - lTempMessung) > TempIntervall stoße ich die Messung an und bei (millis() - lTempMessung - TempConvertZeit) > TempIntervall kann ich die Ergebnisse abholen.

Da ich nur ca. minütlich messe, ist mir die ms egal.

Ich hoffe erklärt zu haben, was du wissen möchtest; mir ist nicht ganz klar was du mit

Wenn die nicht größer als das Intervall ist, spielt die doch keine Rolle. Ansonsten hast Du ein ganz anderes Problem.

meinst.

Meinst du dass ich dann schon die nächste Messung anfordern würde, bevor ich die Ergebnisse der ersten Messung abgeholt habe? Dies ist nicht der Fall

Vielen Dank und viele Grüße

Frank

Das kommt davon, wenn nur ein Teil der Infos bekannt ist.
Da kannst Du doch eine eigene Zeitsteuerung draus machen.
Messung anfordern millis als anforderungsMillis merken. Nach

if millis() - anforderungsMillis >= 750) { // oder 1000
   anforderungsMillis  =) millis();
  // lesen und neue Messanforderung starten
}

So hast Du iommer einen aktuellen Wert, unabhängig davon, wie oft Du ihn verarbeiten willst.

Gruß Tommy

Ja, aber wenn ich das Intervall auf 10 Min ausdehne, dann liefert mir der Sensor den Wert von vor 10 Min.

Mein Problem ist aber nicht der Ablauf, sondern wie ich mit den Datentypen umgehen muss.

Vielen Dank für deine Unterstützung und viele Grüße

Frank

Hi

Das riecht danach, daß Du in Deinem Sketch auf das Ende der Messung warten willst - würde ich nicht tun.

Du hast zwei Punkte

  • Anfordern der Messung
  • Abholen der Messung
  1. alle Minute (10 Minuten)
  2. 750ms danach (bzw. je nach Auflösung früher)

Die Wartezeit muß ja nicht immer identisch sein.

MfG

Mein Problem ist aber nicht der Ablauf, sondern wie ich mit den Datentypen umgehen muss.

Du hast dich vergaloppiert, bist dabei auf ein Problem gestoßen.
Und jetzt bastelst du lieber in einer abwegigen Ecke, als deinen Plan in Frage zu stellen.

Dabei kann ich dir nicht helfen!

Leitsatz:

Wer in die falsche Richtung läuft, muss sich nicht beeilen.
Und dem muss man/ich auch nicht dabei helfen, noch mehr in die Irre zu gehen.

Aber ein paar Dinge kann ich dir sagen:

  • Wenn du es richtig machst, dann gelingt es auch
  • Verwende ausschließlich unsigned Long
  • Solange dein Intervall kleiner als 49,X Tage ist, musst du dich nicht um Überläufe kümmern

F200:
Ja, aber wenn ich das Intervall auf 10 Min ausdehne, dann liefert mir der Sensor den Wert von vor 10 Min.

Mein Problem ist aber nicht der Ablauf, sondern wie ich mit den Datentypen umgehen muss.

Vielen Dank für deine Unterstützung und viele Grüße

Frank

Du hast meinen Ansatz nicht verstanden. Ich habe ausgedrückt, immer wenn der Messwert da ist, einen neuen anzufordern. Damit ist der Wert nicht älter, als 1 Sekunde, was bei Temperaturen unkritisch ist.

Gruß Tommy

@postmaster-ino

Warten möchte ich vermeiden, deshalb der Ansatz über 2 Punkte die du schreibst

  • Anfordern der Messung; habe ich umgesetzt mit
    if ((millis() - lTempMessung) > TempIntervall)

  • Abholen der Messung; habe ich umgesetzt mit
    if ((millis() - lTempMessung - TempConvertZeit) > TempIntervall)

Bei durchgeführter Messung wird lTempMessung mit lTempMessung = millis() hochgesetzt.

@Tommy56
Wenn immer wenn der Messwert da ist, einen neuen anzufordere, beginnt der Sensor doch sofort und merkt sich das Ergebnis. Wenn ich bei einem Intervall von 10 Min auslese, ist der Wert doch 10 Min alt. Der Sensor ermittelt ja nich dauern duch bis ein Abruf erfolgt.
Deshalb folge ich dem Weg, den auch postmaster-ino beschreibt.

@combie
ich bin auch bereit meinen Plan zu ändern, aber ich möchte nicht nur eine Lösung für diesen Einzelfall sondern auch Hintergründe verstehen. Und Wissen möchte ich in mehrere Richtungen erweitern, auch wenn nur ein Weg programmiert wird. :wink:
Ich verstehe deine Tipps dann so dass ich auch TempConvertZeit als [unsigned long] zu deklarieren.
Trotzdem ziehe ich von einem [unsigned long] einen größeren [unsigned long] ab soll doch etwas negatives herauskommen.

Vielen Dank für eure Unterstützung

ich bin auch bereit meinen Plan zu ändern, aber ich möchte nicht nur eine Lösung für diesen Einzelfall sondern auch Hintergründe verstehen.

Fein!

Trotzdem ziehe ich von einem [unsigned long] einen größeren [unsigned long] ab soll doch etwas negatives herauskommen.

Fakt:

if ((millis() - lTempMessung - TempConvertZeit) > TempIntervall)
Hier kannst du dir 2 Unterläufe einfangen.

Einer wird durch das Verfahren kompensiert.
Der zweite bricht dir das Genick.

Darum muss die Lösungssuche an einem Punkt beginnen, der vor der Fehlentscheidung mit der doppelten Subtraktion liegt!

Soweit einverstanden?

const unsigned long gesamtesMessInterval = 10000UL;
const unsigned long convertierInterval   = 3000UL;
const unsigned long warteInterval        = gesamtesMessInterval - convertierInterval;

unsigned long timestamp;

byte messStatus = 0;



void messwertAufnahme()
{
  switch(messStatus)
  {
    case 0 : Serial.print("Messung eingeleitet Zeit: "); Serial.println(millis());
             messStatus++;
             return;
             
    case 1 : if(millis() - timestamp < convertierInterval) return;
             Serial.print("Messung abgeschlossen Zeit: "); Serial.println(millis());
             timestamp += convertierInterval;
             messStatus++;
             return;
             
    case 2 : if(millis() - timestamp < warteInterval) return;
             Serial.print("Wartezeit abgeschlossen Zeit: "); Serial.println(millis());
             timestamp += warteInterval;
             messStatus = 0;
             return;
  }
}



void setup() 
{
  Serial.begin(9600);
  Serial.println("Start");
  timestamp = millis();
}

void loop() 
{
  messwertAufnahme();
}

Ok, zwichenzeitlich habe ich in #5 von http://forum.arduino.cc/index.php?topic=308505.0 erfahren, dass der Datentyp der Zielvariablen wohl nicht entscheidend für die Rechnung ist, sondern es hier auf die Werte ankommt. Die kann wohl durch die Kennungen z.B. “UL” beeinflusst werden, wie du sie in deinem Beispielcode auch verwendest.

Der Beispielcode ist überigens sehr übersichtlich und ich kann mir vorstellen in diese Richtung um zu bauen. (Muss noch ein paar andere Bedingungen mitnehmen.)

Grübeln musste ich bei:

if ((millis() - lTempMessung - TempConvertZeit) > TempIntervall)
Hier kannst du dir 2 Unterläufe einfangen.

Wenn ich dich richtig verstanden habe wäre der erste Unterlauf bei millis() < lTempMessung. Der wird durch den Programmablauf verhindert.

Der zweite Unterlauf (den habe ich lange nicht gesehen) millis() < TempConvertZeit.

Gedanklich hatte ich den ignoriert, da millis so groß im vergleich zur TempConvertZeit ist, aber durch millis() - lTempMessung - TempConvertZeit wiederholt sich das “Problem” nach jeder Aktualisierung von lTempMessung.
Das ist dann fast eine Dritte Möglichkeit für einen Unterlauf.

Wenn man länger darüber nachdenkt, wird es logisch.

Gilt es allgemein, dass sichergestellt werden muss, dass bei der Subtraktion von unsigned Datentypen der Minuend größer als der Subtrahend sein muss?

Vielen Dank für die Anregungen. Ich sehe mir das morgen noch mal an, jetzt geht es erstmal ins Bett.

Viele Grüße

Frank

Gilt es allgemein, dass sichergestellt werden muss, dass bei der Subtraktion von unsigned Datentypen der Minuend größer als der Subtrahend sein muss?

Nein!

Ist ja bei meinem Beispiel auch nicht der Fall!
So ca 10sec, um dem Überlauf von millis() herum, hagelt es Unterläufe.
Aber die werden durch das Verfahren kompensiert, und richten so auch keinen Schaden an.

Das Programm überwindet die Schwelle ohne Murren, oder Irrungen.

Der Beispielcode ist überigens sehr übersichtlich....

Danke für die Blumen!

Das nennt sich übrigens Schrittkette, endlicher Automat, oder Ablaufsteuerung.
Gibt ca 1/2 Dutzend sinnvolle Möglichkeiten sowas aufzubauen.
Und unendlich viele Einsatzzwecke.

Ok er scheint zu funktionieren. Wen es interessiert, wie es geworden ist hier der Link: Änfängerfrage Versuch erste eigene Library zu erstellen - Deutsch - Arduino Forum

Vielen Dank für eure Hilfe