How to read data from a loop into the LCD I2C

Hi folks,

Can You please help me out with my issue.

I´m trying to display the temperature to the LCD from inside a loop.
Probraly not the right way to do it, but I have not been able to search for a solution that works for me.

The temperature read out works in the serial monitor.

I have tryed to put this into the void setup, but that didn´t work:

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

Please tell me what I´m doing wrong.

Thanks in advance!

The complete Sketch:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);

int ThermistorPin = 0;
int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

int fan = 6;       // the pin where fan is
int led = 8;        // led pin
int temp;
int tempMin = 40;   // the temperature to start the fan
int tempMax = 90;   // the maximum temperature when fan is at 100%
int readTemp() {  // get the temperature and convert it to celsius
  temp = analogRead(ThermistorPin);
  //return temp * 0.48828125;
}
void setup() {

  {
    // initialize the LCD
    lcd.init();

    // Turn on the blacklight and print a message.
    lcd.backlight();
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("FAN CONTROLLER");
    lcd.setCursor(0, 1);
    lcd.print("Temp: ");
    lcd.print(Tc);
    lcd.print(" ");
    lcd.print((char)223);
    lcd.print("C");
    delay(2000); //Delay 2 sec.
  }
  {
    Serial.begin(9600);

    pinMode(fan, OUTPUT);
    pinMode(led, OUTPUT);
    pinMode(ThermistorPin, INPUT);
  }
}
void loop() {

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;


  Serial.print("Temperature: ");
  // Serial.print(Tf);
  // Serial.print(" F; ");
  Serial.print(Tc);
  Serial.println(" C");

  delay(500);
  if (Tc < tempMin) {  // if temp is lower than minimum temp
    digitalWrite(fan, LOW);
  }

  if (Tc >= tempMin)  {  // if temp is lower than minimum temp
    digitalWrite(fan, HIGH);
    //analogWrite(A5, fanSpeed);  // spin the fan at the fanSpeed speed
  }

  if (Tc  >= tempMax) {       // if temp is higher than tempMax
    digitalWrite(led, HIGH);  // turn on led
    Serial.print("TEMP IS TO HIGH!");
  }
  else {                    // else turn of led
    digitalWrite(led, LOW);
  }

}

Can you see "FAN CONTROLLER" on the LCD?

Yes, I can see

  1. line: FAN CONTROLLER
  2. line: Temp: 0.00 "((Char)223)" C

And you can see the correct temperature printed on the serial monitor?

I can't see where you're printing the temperature to the LCD.

Yes I can see the temp. in serial monitor.

It is lcd.print(Tc); as I use for the serial monitor in the void loop

{
    // initialize the LCD
    lcd.init();

    // Turn on the blacklight and print a message.
    lcd.backlight();
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("FAN CONTROLLER");
    lcd.setCursor(0, 1);
    lcd.print("Temp: ");
    lcd.print(Tc);
    lcd.print(" ");
    lcd.print((char)223);
    lcd.print("C");
    delay(2000); //Delay 2 sec.
  }

But you haven't calculated the temperature at that point in setup()

You function readTemp doesn't appear to return a value.

Well, I thing that calculating the temperature is going on here in the void loop?

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;

and here before the void setup

float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

But you're not displaying it in the loop function.
You have only serial prints in the loop function.

Yes, i know, but I can´t figure out how I´m going to display the temperature (Tc) from the loop.

If I do this in the loop:

  if (Tc >= tempMin)  {  // if temp is lower than minimum temp
    digitalWrite(fan, HIGH);
 
    // initialize the LCD
    lcd.init();

    // Turn on the blacklight and print a message.
    lcd.backlight();
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("FAN CONTROLLER");
    lcd.setCursor(0, 1);
    lcd.print("Temp: ");
    lcd.print(Tc);
    lcd.print(" ");
    lcd.print((char)223);
    lcd.print("C");
    delay(2000); //Delay 2 sec. }

I don´t get anything in the display but only the backlight.

Sorry, but I think, that I´m totaly lost here. :-[

You should initialize the LCD once, in the setup function

I have now moved it to the loop like this:

void loop() {

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;


  Serial.print("Temperature: ");
  // Serial.print(Tf);
  // Serial.print(" F; ");
  Serial.print(Tc);
  Serial.println(" C");

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("FAN CONTROLLER");
    lcd.setCursor(0, 1);
    lcd.print("Temp: ");
    lcd.print(Tc);
    lcd.print(" ");
    lcd.print((char)223);
    lcd.print("C");
    delay(2000); //Delay 2 sec.

I have attached a picture of the result

I'm guessing that you have grabbed and installed one of the many "LiquidCrystal_I2C" libraries out there and happened to get one that has a bug in its write() routine.

This bug will cause only the first character of a string to be printed.
i.e. you can print single characters but if you attempt to print a string you will only get the first character.

If you see this in your LiquidCrystal_I2C.cpp code, you have the broken library.

inline size_t LiquidCrystal_I2C::write(uint8_t value) {
 send(value, Rs);
 return 0;
}

That return 0 needs to return 1 instead.
A 0 tells the Print class there was an output error and to stop sending characters.
That is what causes a string to only print a single character.

I believe that the LiquidCrystal_I2C library currently available from IDE library manager has this issue fixed.
But even that library is no longer being maintained and the current maintainer, johnrickman, appears to now have moved the code repository to another git sever (which isn't used by the IDE manager) and has abandoned the one on github.
He has also violated the copyright of the library by replacing the libraries LGPL license with an MIT license.
This is not legal.

github repository for LiquidCrystal_I2C used by Arduino IDE:

gitlab repository:
https://gitlab.com/tandembyte/LCD_I2C
reported license issue:
https://gitlab.com/tandembyte/LCD_I2C/-/issues/39

If you want a better maintained library, that has additional features, is faster, and works with newer platforms like STM and esp32, you could switch over to the hd44780 library and use the hd44780_I2Cexp i/o class.

UPDATE:
Looks like johnrickman is looking at the copyright issue.
So the license on gitlab may get updated soon.

--- bill

Disp1.JPG

Thank you all!

I checked the LiquidCrystal_I2C.cpp and it seems to be fixed in the one I got.

I think I have resolved my issue (don´t ask me how), but still sometimes after uploading the sketch to the Arduino, not all characters are displayed. :confused:
I can fix this by making changes in the code and uploading again.

Don´t know if it is my code, Arduino Uno or the Arduino IDE (1.8.13) which is the problem...

You are welcome to look into my sketch and if you find something weird, you are very welcome to comment on this.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);

uint8_t bell[8]  = {0x4, 0xe, 0xe, 0xe, 0x1f, 0x0, 0x4};
uint8_t note[8]  = {0x2, 0x3, 0x2, 0xe, 0x1e, 0xc, 0x0};
uint8_t clock[8] = {0x0, 0xe, 0x15, 0x17, 0x11, 0xe, 0x0};
uint8_t heart[8] = {0x0, 0xa, 0x1f, 0x1f, 0xe, 0x4, 0x0};
uint8_t duck[8]  = {0x0, 0xc, 0x1d, 0xf, 0xf, 0x6, 0x0};
uint8_t check[8] = {0x0, 0x1, 0x3, 0x16, 0x1c, 0x8, 0x0};
uint8_t cross[8] = {0x0, 0x1b, 0xe, 0x4, 0xe, 0x1b, 0x0};
uint8_t retarrow[8] = {  0x1, 0x1, 0x5, 0x9, 0x1f, 0x8, 0x4};

int ThermistorPin = 0;
int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

int fan = 6;       // the pin where fan is
int led = 8;        // led pin
int temp;
int tempMin = 40;   // the temperature to start the fan
int tempMax = 90;   // the maximum temperature when fan is at 100%
int readTemp() {  // get the temperature and convert it to celsius
  temp = analogRead(ThermistorPin);
  //return temp * 0.48828125;
}
void setup() {

  {
    // initialize the LCD
    lcd.init();
    lcd.backlight();

    lcd.createChar(0, bell);
    lcd.createChar(1, note);
    lcd.createChar(2, clock);
    lcd.createChar(3, heart);
    lcd.createChar(4, duck);
    lcd.createChar(5, check);
    lcd.createChar(6, cross);
    lcd.createChar(7, retarrow);
    lcd.home();

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("FAN CONTROLLER");
    lcd.setCursor(0, 1);
    lcd.print("Temp: ");
    lcd.print(Tc);
    lcd.print(" ");
    lcd.print((char)223);
    lcd.print("C");
    delay(2000); //Delay 2 sec.
  }
  {
    Serial.begin(9600);

    pinMode(fan, OUTPUT);
    pinMode(led, OUTPUT);
    pinMode(ThermistorPin, INPUT);
  }
}
void loop() {

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  Tc = T - 273.15;
  Tf = (Tc * 9.0) / 5.0 + 32.0;


  Serial.print("Temperature: ");
  // Serial.print(Tf);
  // Serial.print(" F; ");
  Serial.print(Tc);
  Serial.println(" C");
  delay(500);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("FAN CONTROLLER");
  lcd.setCursor(0, 1);
  lcd.print("Temp: ");
  lcd.print(Tc);
  lcd.print(" ");
  lcd.print((char)223);
  lcd.print("C");
  delay(2000); //Delay 2 sec.


  if (Tc < tempMin) {  // if temp is lower than minimum temp
    digitalWrite(fan, LOW);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write(3);
    lcd.print(" ");
    lcd.print("TEMP ");
    lcd.print("IS ");
    lcd.print("OK");
    lcd.print(" ");
    lcd.write(3);
    //lcd.print((char)126);
    lcd.setCursor(0, 1);
    lcd.print("Temp: ");
    lcd.print(Tc);
    lcd.print(" ");
    lcd.print((char)223);
    lcd.print("C");
    delay(2000);
  }

  if (Tc >= tempMin)  {  // if temp is lower than minimum temp
    digitalWrite(fan, HIGH);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("WARNING !");
    lcd.setCursor(0, 1);
    lcd.print("Temp: ");
    lcd.print(Tc);
    lcd.print(" ");
    lcd.print((char)223);
    lcd.print("C");
    delay(2000);
    //analogWrite(A5, fanSpeed);  // spin the fan at the fanSpeed speed
  }

  if (Tc  >= tempMax) {       // if temp is higher than tempMax
    digitalWrite(led, HIGH);  // turn on led
    Serial.print("TEMP IS TO HIGH!");
  }
  else {                    // else turn of led
    digitalWrite(led, LOW);
  }

}

The initial image you provided showed a display that was consistent with using one of the LiquidCrystal_I2C libraries with the write() function issue.
Now with no library changes but sketch changes, it seems to be kind of sort of sometimes "working", but not really?
(If it doesn't work all the time, it really isn't working)

Something odd is going on.

I would recommend installing the hd44780 library and running the included I2CexpDiag sketch to test your LCD h/w.
It will test the i2c signals for pullups and then do a RAM test on the internal LCD memory to see if things are working ok.

I very much prefer using the hd44780_I2Cexp i/o class from the hd44780 library over the LiquidCrystal_I2C library,
but then I am the author of the hd44780 library. :smiley:

--- bill

Thanks Bill,

I will look into this.

Do I have to change anything in the code besides from the #include <LiquidCrystal_I2C.h> to the hd44780.h?

jeor:
Thanks Bill,

I will look into this.

Do I have to change anything in the code besides from the #include <LiquidCrystal_I2C.h> to the hd44780.h?

Yes.

The diagnostic sketch will not need any changes to run.
You don't even have to set any sort of i2c address.

However, for your own sketches there are a few more changes.
The hd44780 library supports several different communication interfaces and display types so you have to include the appropriate i/o class.

You must include the appropriate headers
<hd44780.h>
<hd44780ioClass/hd44780_I2Cexp.h>

And you must change your lcd object to use the constructor for the hd44780_I2Cexp class.
See the included examples for the hd44780_I2Cexp i/o class.

--- bill

Hi Bill

Thanks! :slight_smile: