Comparing float before display update

Im printing a float to a LCD. It's printed with one decimal.
To avoid flicker I only want to update the LCD if the displayed value changes.

Is there an elegant way to compare the current value with the displayed value only up to the first decimal? I already found that round() doesn't work as in C++ and casting the values to int seems overly complex for such a simple thing.

Use fabs() ?

I guess you must convert the value to a string somehow before printing it to the LCD? Using dtostrf() or similar? Copy that string to a static or global variable. Next time you print the value, convert it to a string as normal, then compare that string to the previous version with strcmp() and update the LCD only if the string has changed.

static char lastValue[10] = "";
char newValue[10];
dtostrf(f, 7, 1, newValue);
if (strcmp(newValue, lastValue) != 0) {
  // Update LCD to newValue
  strcpy(lastValue, newValue);
  }


1 Like

Multiply by 10.0, add 0.5, and truncate to an integer.

int rounded(float value)
{
  return (value * 10.0) + 0.5;
}

  if (rounded(newValue) != rounded(previousValue))
  {
    previousValue = newValue;
    lcd.print(newValue, 1);
  }
1 Like

What's the source of the number and what board are you using?

Seriously? My eyes are probably not what they used to be, but I submit, if the value is the same, there shouldn't be any flicker. I don't think it matters what LCD you have, but it might be time for you to post your code.

1 Like

Board is a UNO R3, Sensor a Adafruit_MAX31865 with <Adafruit_MAX31865.h>.

It's barely noticable, maybe it's because there is some code between "clear display" and "print value".

void printTemp0() {
  static unsigned long previousMillis = 0;
  static float previousOvenTemp = 0.0;

  // print interval
  if (currentMillis - previousMillis > 1000) {
    previousMillis = currentMillis;

    // prevent flicker
    if (ovenTemp0 != previousOvenTemp) {
      previousOvenTemp = ovenTemp0;

      // clear display
      lcd.setCursor(13, 0);
      lcd.print("     ");

      // if error
      if (ovenTemp0 <= -100 || ovenTemp0 >= 1000) {
        lcd.setCursor(15, 0);
        lcd.print("ERR");
      }
      else {
        //align right
        if (ovenTemp0 > -100 && ovenTemp0 < -10) {
          lcd.setCursor(13, 0);
        }
        else if (ovenTemp0 >= -10 && ovenTemp0 < 0) {
          lcd.setCursor(14, 0);
        }
        else if (ovenTemp0 >= 0 && ovenTemp0 < 10) {
          lcd.setCursor(15, 0);
        }
        else if (ovenTemp0 >= 10 && ovenTemp0 < 100) {
          lcd.setCursor(14, 0);
        }
        else if (ovenTemp0 >= 100) {
          lcd.setCursor(13, 0);
        }

        // print value
        lcd.print(ovenTemp0, 1);
      }
    }
  }
}

Might want to divide by 10 again, there.
C

Where? Please show the code with your proposed change included and the reasoning for the change.

calculate the difference between old and new value.
make it absolute
print it if the difference is larger than ... whatever you want as threshold.

// return true if new value differs enough
bool isNew(float oldValue, float newValue)
{
  const float threshold = 0.1;
  float diff = fabs(oldValue - newValue);
  if (diff >= threshold) return true;
  return false;
}

void setup() {
  Serial.begin(115200);
  Serial.println(isNew(3.11111, 3.2222));   // true
  Serial.println(isNew(3.11111, 3.1122));  // false
  Serial.println(isNew(3.2222, 3.1111));    // true
}

void loop() {
  // put your main code here, to run repeatedly:

}

elegant? I don't know.
But hopefully not more than one optional multiplication hidden in fabs() *)
No division.

*) honestly I don't know, but smarter guys have implemented this hopefully in a very efficent way.

1 Like

But there are cases where the difference is smaller than the threshold but a rounded result would result in a change of the first decimal. Maybe not relevant for what I do but not the same.

I went with a char solution now. This also makes the alignment on the display way easier.

By "clearing the display", I suggest the code in post #7 is doing the opposite of what you claim it is doing.

Something like the following might yield a better result

void loop() {

  if (currentMillis - previousMillis > 1000) {
    previousMillis = currentMillis;void printTemp0() {
  static unsigned long previousMillis = 0;
  static float previousOvenTemp = 0.0;
doStuff();
printTemp0();
}
}

void printTemp0()
         lcd.setCursor(13, 0);

        if (ovenTemp0 >= -10 && ovenTemp0 < 0) {
          lcd.print(" ");
        }
        else if (ovenTemp0 >= 0 && ovenTemp0 < 10) {
           lcd.print("  ");
        }
        else if (ovenTemp0 >= 10 && ovenTemp0 < 100) {
           lcd.print(" ");
        }
       
        lcd.print(ovenTemp0, 1);
      }
    }
  }
}

The third condition would be better linked to the first by OR, but I don't know how to do that in Arduinospeak.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.