I'm on my first arduino project and don't understand the behaviour of lcd.print().
I declared float ovenTemp and ran the function below. Serial.println(ovenTemp, 1) results in the temperature beeing printed with one decimal e.g. 27.6
But for the same value of ovenTemp lcd.print(ovenTemp, 1) results in 27.69.
The last digit seems to be random and changes if I put the line somewhere else in the code. It is not an actual digit from the value of ovenTemp. It is static and doesn't change when the function runs again while the other digits update as expected.
If I print with more decimals the random digit is still added to the end.
I switched to an I2C display and this didn't change the behaviour. What am I missing?
void getTemp() {
static const int numReadings = 10; // determines the size of the readings array
static int readings[numReadings]; // the readings from the analog input
static int readIndex = 0; // the index of the current reading
static int total = 0; // the running total
// initialize all the readings to 0 on the first run
static bool hasInitialized = false;
if (hasInitialized == false) {
for (int i = 0; i < numReadings; i++) {
readings[i] = 0;
}
hasInitialized = true;
}
// calculate running average of last sensor readings
total = total - readings[readIndex]; // subtract the previous reading with the current index
readings[readIndex] = analogRead(sensorPin0); // read from the sensor
Serial.print("reading: ");
Serial.print(readings[readIndex]);
total = total + readings[readIndex]; // add the reading to the total
readIndex = readIndex + 1; // advance to the next position in the array
if (readIndex >= numReadings) { // if at the end of the array...
readIndex = 0; // ...wrap around to the beginning
}
int smoothReading = total / numReadings; // calculate the average
Serial.print(", smooth reading: ");
Serial.print(smoothReading);
float voltage = (smoothReading / 1024.0) * 5.0;
Serial.print(", V: ");
Serial.print(voltage);
ovenTemp = (voltage - .5) * 100;
Serial.print(", C: ");
Serial.println(ovenTemp, 1);
lcd.setCursor(10, 1);
lcd.print(ovenTemp, 1);
}
Thanks, both clearing and overwriting before every print does fix the random digit. However I don't quite understand how writing to the display works. Why does this write to a cursor position that should not be affected by the written text?
I use a 20x4 display and wanted to print the temperature unit right behind the value. With both methods the unit get's erased obviously. So do I have to print that everytime, too?
Is it good practice to just update some cursor positions?
No, not if you use the cursor control and print just enough spaces to overwrite the old data and not the units.
This demo will illustrate what I say. Connect a pot to A0 and run this. I use the hd44780 library for I2C LCDs because it is the best available at this time. The library is available via the IDE library manager. I intentionally use 15 (versus 1023) for the divisor to get more significant digits to show how it works with the changing data length.
#include <Wire.h>
#include <hd44780.h> // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip
// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;
const byte anaInPin = A0;
void setup()
{
Serial.begin(115200);
lcd.begin(LCD_COLS, LCD_ROWS);
lcd.print("LCD Voltmeter");
lcd.setCursor(0, 1);
lcd.print("VOLTS = ");
lcd.setCursor(14, 1);
lcd.print("Vdc");
}
void loop()
{
static unsigned long timer = 0;
unsigned long interval = 500;
if (millis() - timer >= interval)
{
timer = millis();
int anaIn = analogRead(anaInPin);
float volts = anaIn * (5.0 / 15.0); // to give more significant digits
lcd.setCursor(8, 1);
lcd.print(" "); // just enough spaces to overwrite old data (6) and not units.
lcd.setCursor(8, 1);
lcd.print(volts, 1);
}
}
All of the labels are set in setup(). The only thing printed is the changing data.
Yes, I get the idea but it doesn't work for me. I want to print 27.6 so I set the cursor and overwrite 4 characters. But with lcd.print(ovenTemp, 1) it prints the random fifth character and overwrites my unit.
Post a minimal program that reproduces the problem. Then I can load the code and see what is going on. Incomplete snippets, out to context, are not as helpful.
If you work with simple code till you get it working and understand the process you will be better off.
But this produces the fifth random digit which overwrites the unit. So could it be related to the smoothing of the sensor value?
//LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
//sensors
const int sensorPin0 = A0;
float ovenTemp;
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(14, 0);
lcd.print(String(char(223)) + String("C"));
}
void loop() {
while (true) {
getTemp();
printTemp();
delay(100);
}
}
void getTemp() {
static const int numReadings = 10; // determines the size of the readings array
static int readings[numReadings]; // the readings from the analog input
static int readIndex = 0; // the index of the current reading
static int total = 0; // the running total
// initialize all the readings to 0 on the first run
static bool hasInitialized = false;
if (hasInitialized == false) {
for (int i = 0; i < numReadings; i++) {
readings[i] = 0;
}
hasInitialized = true;
}
// calculate running average of last sensor readings
total = total - readings[readIndex]; // subtract the previous reading with the current index
readings[readIndex] = analogRead(sensorPin0); // read from the sensor
total = total + readings[readIndex]; // add the reading to the total
readIndex = readIndex + 1; // advance to the next position in the array
if (readIndex >= numReadings) { // if at the end of the array...
readIndex = 0; // ...wrap around to the beginning
}
int smoothReading = total / numReadings; // calculate the average
float voltage = (smoothReading / 1024.0) * 5.0;
ovenTemp = (voltage - .5) * 100;
}
void printTemp() {
lcd.setCursor(10, 0);
lcd.print(" ");
lcd.setCursor(10, 0);
lcd.print(ovenTemp, 1);
}
I found the problem. During the beginning of the smoothing the temperature is negative. This adds a minus which moves all characters one position to the right. After a few readings the temperature turns positive and the mysterious fifth character remains.
Had nothing to do with the display. Thanks for your support anyway. It showed me to break the problem down into smaller increments.