yo234
July 19, 2022, 6:10pm
1
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.
PaulRB
July 19, 2022, 6:21pm
3
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
yo234
July 20, 2022, 8:46am
7
Board is a UNO R3, Sensor a Adafruit_MAX31865 with <Adafruit_MAX31865.h>.
Nick_Pyner:
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.
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
camsysca:
divide by 10 again
Where? Please show the code with your proposed change included and the reasoning for the change.
yo234:
Is there an elegant
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
yo234
July 20, 2022, 2:24pm
11
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.
system
Closed
January 17, 2023, 4:32am
13
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.