Temperaturabfragen ohne if Kaskaden

Guten Morgen allerseits :slight_smile:

Angeregt durch diesen Thread

frage ich mich, ob man auch bei Temperaturabfragen auf if Kaskaden verzichten kann, um es übersichtlicher zu programmieren?

Die Temps liegen ja meist als float vor:

Z.B.
Wenn modusAuto = Ein && tempAussen > 15 Grad && tempAussen < 25 Grad && tempInnen < 20 Grad || tempInnen = 30 Grad dann tue etwas

Ich hatte erst switch case im Auge, aber nach meiner Suche kann man nur ganze Zahlen vergleichen.

Wäre es da sinnvoll, die floats in int zu wandeln?
Aber die hätten dann ja keine Kommastellen und würden erst beim nächsten ganzen Grad den Switch case erfüllen.

Oder macht man das ganz anders?
Hat da jemand eine Richtung für mich, in der ich gucken kann?

Danke euch :wave:t2:

Ich denke das geht schon in die richtige Richtung, habe es aber noch nicht ganz verstanden, was da passiert…

Ich würde,vor dem switch case, je nach Anzahl der Nachkommastellen, mit 10..100... multiplizieren, dann haste auch ganze Zahlen die Du auswerten kannst.
Notfalls ne Variable dafür mißbrauchen :wink:

1 Like

Ja,
in dem anderen Thread das letzte Post von mir - das zweite example.

1 Like

Auf jeden Fall.
Normale Sensoren für Raumtemperatur haben ein halbes Grad Auflösung und noch weniger Genauigkeit. [OT] Die amerikanischen Fahrenheit haben immerhin den Vorteil, dass man da nie auf die Idee kommt, mit Bruchteilen zu rechnen [/OT]. Um leichter erkennbare Werte zu haben, nimm als Einheit Zehntelgrad, wie @combie woanders vorgeschlagen hat.

1 Like

Eine Variante:

#include <Streaming.h> // die Lib findest du selber ;-)
Print &cout = Serial; // cout Emulation für "Arme"


constexpr long Zehntel(const float value)
{
  return value * 10;
}

long zehntel(const float value)
{
  return value * 10;
}


void setup() 
{
  Serial.begin(9600);
  cout << F("Start: ") << F(__FILE__) << endl;
}

void loop() 
{
 float messwert = 42.11; 
 switch(zehntel(messwert))
 {
  case Zehntel(11.3) ... Zehntel(19.8):   cout << F("Tuwas1") << endl; break;
  case Zehntel(19.9) ... Zehntel(48.6):   cout << F("Tuwas2") << endl; break;
  default: cout << F("Unerwarteter Messwert: ") << messwert << endl;
 }
}

Varianten, verschiedenste.....
Hier mit etwas weniger Schreibarbeit, vielleicht auch ganz interessant:

#include <Streaming.h> // die Lib findest du selber ;-)
Print &cout = Serial; // cout Emulation für "Arme"


constexpr long operator""_z(double long value) // macht aus float Zehntel
{
  return value * 10;
}


long zehntel(const float value)
{
  return value * 10;
}


void setup() 
{
  Serial.begin(9600);
  cout << F("Start: ") << F(__FILE__) << endl;
}

void loop() 
{
 float messwert = 42.11; 
 switch(zehntel(messwert))
 {
  case 11.3_z ... 19.8_z:   cout << F("Tuwas1") << endl; break;
  case 19.9_z ... 48.6_z:   cout << F("Tuwas2") << endl; break;
  default: cout << F("Unerwarteter Messwert: ") << messwert << endl;
 }
}
1 Like

Wie immer: Vielen Dank :slight_smile:

Echt krass mit was für einem Tempo ihr hier immer wieder helft :ok_hand:t2: :ok_hand:t2: :ok_hand:t2:

Zwischenruf:
Was für Sensoren benutzt Du und welche Lib dazu?
Für die Dallas-Temperature kannst Du das umrechnen ggfls. auch lassen und den Rohwert (ein int32_t ) weiterverwenden.

Denn der float TempC wird daraus errechnet.
Es macht ja keinen Sinn, den erst bauen zu lassen und dann wieder zurück zu rechnen.

1 Like

Hast natürlich Recht :wink: Doch wieder was vergessen, verdammt :slight_smile:

Ja das würde die DallasLib mit ziemlich sicher DS18B20 Sensoren werden

Dafür sind ja hier ein paar mehr...
Grundlegend wäre int32_t DallasTemperature::getTemp(const uint8_t* deviceAddress) { Dein Einsprung.
Wenn Dir das zu unübersichtlich ist, kannst Du den Wert auch nehmen und aus der Funktion float DallasTemperature::rawToCelsius(int32_t raw) { erhellendes übernehmen und die Temperatur wie dort, nur ohne Nachkomma (also mit 10 multipliziert) errechnen.

Kann man auch Switch Case verwenden, wenn sich die Wertebereiche überschneiden?

Fiktives Beispiel, vom Handy handgetippt:

if(temp>22 && temp<24){
  // Tue etwas
}
if(temp>23 && temp<25){
  // Tue etwas anderes
}
if(temp>24 && temp<26){
  // Tue noch etwas anderes
}
if(temp<23 || temp>25){
  // Tue etwas ganz anderes
}

Kann mir jemand ein Beispiel zeigen, wie man das mit Switch Case aufbaut? Da tun sich gerade Knoten im Kopf auf.

Natürlich kann man, es ist aber zu sehen ob das logisch sinnvoll ist bzw daß beide Fälle überhaupt ausgeführt werden.
Das EVA ( Eingabe Verarbeitung Ausgabe) Prinzip hilft sicher dabei.

Wie man bei switch case die Variable auf Bereiche kontrollieren kann hat DIr combie in #6 gezeigt:

Grüße Uwe

Und wie werte ich einen Wert von 15.8 bis 22.2 aus?
Solange ich unter 19.8 bleibe springt er ins erste Case.

case braucht keinen Abschluß mit break;
In diesem Fall wird die erste Fall abgearbeitet und dann der nächste.

Beispiel:
a=0; b=0;
switch(variable)
{
case 1 ... 5: a=1;
case 3 ... 4: b=1; break;
}

zwischen 3 und 4 wird b =1 und a = 1
zusätzlich wird zwischen 1 und 2 und bei 5 a=1 und b=0

Grüße Uwe

1 Like

switch case geht nicht mit Überlappungen.
Da meckert der Compiler:

error: duplicate (or overlapping) case value

Was aber geht ist das aufteilen:
Variante 1:

  switch (temp * 10)
  {
    case 220 ... 229:
      // Tue etwas
      break;
    case 230 ... 239:
      // Tue etwas
      // Tue etwas anderes
      break;
    case 240 ... 249:
      // Tue etwas anderes
      // Tue noch etwas anderes
      break;
    case 250 ... 259:
      // Tue noch etwas anderes
      break;
    default:
      // Tue etwas ganz anderes
      break;
  }

Variante 2:

  switch (temp * 10)
  {
    case 230 ... 239:
    // Tue etwas anderes
    case 220 ... 229:
      // Tue etwas
      break;
    case 250 ... 259:
      // Tue noch etwas anderes
    case 240 ... 249:
      // Tue etwas anderes
      break;
    default:
      // Tue etwas ganz anderes
      break;
  }

Die zweite Variante macht sich zunutze, das ein fehlendes break überlaufen wird udn das nächste Case mitgenommen wird.

1 Like

Mit welchen Stichwörtern erhält man erhellende Texte?

Bei "Benutzerdefinierte Literale" lese ich

Nach den Anführungszeichen "" muss ein Leerzeichen stehen.

Das ist hier nicht der Fall, also bin ich wohl falsch. Mehr Treffer finde ich aber im großen Buch nicht :thinking:

Jou, da hat mich die "C++-Wundertüte" combie auch mit überrascht! :rofl:

Nachtrag: das ist der "suffix operator" seit C++11 (Link)

Zweiter Nachtrag: welche Stelle in der Präzedenzreihenfolge hat der?

Und ich hab mich nicht getraut zu fragen weil ich mich nicht als C++ unwissender outen wollte. :innocent: :innocent:

Nee, du bist schon an der richtigen Adresse!
Das könnte/wird ein Fehler in deinem geheimen Buch sein.

Denn meine Doku sagt ganz eindeutig:

#include <string>
 
void        operator "" _km(long double); // OK, will be called for 1.0_km
std::string operator "" _i18n(const char*, std::size_t); // OK
 
template<char...>
double operator "" _π(); // OK
float  operator ""_e(const char*); // OK
 
// error: suffix must begin with underscore
float operator ""Z(const char*);
 
// error: all names that begin with underscore followed by uppercase
// letter are reserved (NOTE: a space between "" and _).
double operator"" _Z(long double);
 
// OK. NOTE: no space between "" and _.
double operator""_Z(long double);
 
// OK: literal operators can be overloaded
double operator ""_Z(const char* args);
 
int main() {}

Da sind explizit beide Varianten mit OK bezeichnet!

Dabei benutze ich das hier schon seit Jahren in aller Öffentlichkeit.......
delay(2_Tage + 3.5_Sekunden);