20x4 I2C LCD crashing on Spark Core

I’m currently trying to build central heating controller for my house but i ran into bit of trouble regarding LCD.
This is the library i used: https://gist.github.com/anonymous/dc7ecc5e6574105b4fbd

Everything is working fine but after certain time has passed LCD locks up and displays some random chars.
If i then run lcd->clear(); in code then it comes back and works until next crash.

Probably smth related to library? Can someone fix it or point me towards some better library?

LCD is use is : http://www.dx.com/p/arduino-iic-i2c-serial-3-2-lcd-2004-module-display-138611#.VIMhTsmwiBU

Could you please show your own code too? Or are you experiancing this problem with the provided LiquidCrystal_I2C_example.ino?

The description you provided would also fit to some buffer overflow.

It also happens when i use example.ino
If i increase loop delay LCD works normally longer. In my code i have delay(1000);

I have 2’nd LCD too and it has same problem (to rule out hardware issue).

Since I can’t test this lib without one of these displays, I can only guess and throw some further ideas at you.

Have you got a way to check if it’s an electrical issue (e.g. missing I2C pull-up resistors, 3.3V not enough, …)?

I’ve used the SPI_LCD lib successfully. Do you see any chance that you “port” this for I2C yourself?

We can also tag @BDub as he did some research on a similar display
http://community.spark.io/t/liquidcrystal-shift-register/2179/32

Some more reads here (if you haven’t already been there)

1 Like

I use 5V to power LCD and i have 4,7k resistors in place.
I have to use lcd->init(); (in first post i wrote clear(); it was typo) for lcd to display properly again once corrupt letters appear.

Unfortunetly there is no way i can port or modify library since my programming skills are weak at best.

My curreny code (sketch to test sensors and lcd):

// This #include statement was automatically added by the Spark IDE.
#include "OneWire/OneWire.h"

// This #include statement was automatically added by the Spark IDE.
#include "spark-dallas-temperature/spark-dallas-temperature.h"






//#include "application.h"
#include "LiquidCrystal_I2C.h"
#include "SparkTime/SparkTime.h" 




DallasTemperature dallas(new OneWire(D3));

int led1 = D4;

LiquidCrystal_I2C *lcd;
UDP UDPClient;
SparkTime rtc;

unsigned long currentTime;
unsigned long lastTime = 0UL;
String timeStr;

void setup(){
    dallas.begin();
    rtc.begin(&UDPClient, "north-america.pool.ntp.org");
    rtc.setTimeZone(+2); // gmt offset
    Serial.begin(9600);
    lcd = new LiquidCrystal_I2C(0x27, 20, 4); // set the LCD address to 0x20 for a 16x2 //SparkCore bug, address is actually 27 but shifted (0x27*2)
    lcd->init(); // initialize the lcd
    lcd->backlight();
    lcd->clear();
    pinMode(led1, OUTPUT);
    }
    

void loop(){
 
    currentTime = rtc.now();
    if (currentTime != lastTime) {
        byte sec = rtc.second(currentTime);
        
         
        // Just the time in 12 hour format
        timeStr = "";
        timeStr += rtc.hour12String(currentTime);
        timeStr += ":";
        timeStr += rtc.minuteString(currentTime);
        timeStr += ":";
        timeStr += rtc.secondString(currentTime);    
        timeStr += " ";    
        timeStr += rtc.AMPMString(currentTime);
        
        lastTime = currentTime;
    }
    
    lcd->setCursor(5,0);
    lcd->print(timeStr);

    dallas.requestTemperatures();
    delay(1000);

    float Radikasse = dallas.getTempCByIndex( 0 );
    float Toatemp = dallas.getTempCByIndex( 1 );
    float Toatemp2 = dallas.getTempCByIndex( 2 );

    Serial.println("Temperature: "); Serial.println(Radikasse) ;Serial.println(Toatemp) ;
    lcd->setCursor(5,1);
    lcd->print(Radikasse, 1);
    lcd->setCursor(5,2);
    lcd->print(Toatemp, 1);  
    lcd->setCursor(5,3);
    lcd->print(Toatemp2, 1);
    
    if (Toatemp <23) {
        digitalWrite(led1, LOW);
    } else {
        lcd->init();
        //digitalWrite(led1,HIGH);
    }
    

}

After playing around with it i can say how this text corruption acts:
Some of my text corrupts and part of it remains intact and text in all the lines (my lcd has 4 lines) starts running from left to right.

Might it be some sort of memory overflow or what causes that sort of behaviour?
Sorry for my bad English :slight_smile:

@qwerty009, I suggest you add Serial.print() before any of your lcd->print commands to see what you are sending to the display. Second, what is the purpose of the lcd->init() in:

if (Toatemp <23) {
    digitalWrite(led1, LOW);
} else {
    lcd->init();
    //digitalWrite(led1,HIGH);
}

Did LiquidCrystal_I2C_example.ini work without any problems? Are there pull-up resistors on the serial board of the LCD? If not, did you add some in your circuit?

1 Like

@qwerty009, it could well be that the source of the problem isn’t actually the LCD, but the String.
The String class is known to have some memory issues, if not used with care.

The first thing to check would be to Serial.print() the string you want to display on your LCD.

The way you’re using String (a lot of frequent concatinations) causes the String class to permanently reallocate the string, which may - due to running out of heap space - cause the corruption of data.
Maybe you should try char[] instead.


Darn, again I was tooooooooooooo slow - @peekay123 's response just popped up, while writing this

1 Like

I did ask this already :wink:

While my above answer might apply to @qwerty009 's code, I've no clue why it would happen with the example.ino, as he pointed out in the third post.

@ScruffR, LOL I need to better read the posts! Your comments on the String stuff are valid. However, the first thing to focus on is the example. I would first remove the loop() code and modify the lcd = new line in setup() for the 20x4 display. If that works, then add the loop() code back in and see if that works. If that works, I would let it run for a while to see if it corrupts.

The problem seems to be that the issue only seems to appear after running for some time - so it’s bound to be in connection with the loop, that first runs OK but eventually starts tripping up.

@ScruffR, I would increase the delay(200) to delay(1000) and see what that does. Other members have brought up a similar issue with I2C dropping or freezing after some time. This may be related.

1 Like

Increasing delay() in Loop from 200ms to 1000ms makes it alot more stable, but it still crashes (example file).
200ms delay it lasts usually max 90sec, with 1000ms delay it lasts several minutes.

Peekay what did you mean to modify LCD new to 20x4? Don’t i have it set up for it? If not what would i need to do exactly?

@qwerty009, line 8 of your example is:

   lcd = new LiquidCrystal_I2C(0x27, 16, 2);

I thought you had a 20x4 display, not 16x2

When you say a lot longer - is it about 5 times as long :wink: which would suggest that it is more likely to be a case of iterations rather than timing.

Here’s my current code:

[code]// This #include statement was automatically added by the Spark IDE.
#include “analogSmooth.h”

// This #include statement was automatically added by the Spark IDE.
#include “OneWire/OneWire.h”

// This #include statement was automatically added by the Spark IDE.

#include “LiquidCrystal_I2C.h”
#include “SparkTime/SparkTime.h”

String writeAPIKey = “xxx”;
String channelID = “20611”;

// TCP socket initialize
TCPClient client;

int ledRed = A0; //if ON then indicates that there is 230V present and boiler pump is OFF
int ledGreen = A1; // is ON then boiler pump is ON

int radikatemp = A2;
int toatemp = A3;
int pliiditemp = A4;
int pliidiveetemp = A5;

int relayRadiator = D2; //relay to turn ON/OFF radiator pump
int relayBoiler = D3; // relay to turn ON/OFF boiler pump.

int c = 0;

LiquidCrystal_I2C *lcd;
UDP UDPClient;
SparkTime rtc;

unsigned long currentTime;
unsigned long lastTime = 0UL;
String timeStr;

AnalogSmooth as100 = AnalogSmooth(100);
AnalogSmooth as101 = AnalogSmooth(100);
AnalogSmooth as102 = AnalogSmooth(100);
AnalogSmooth as103 = AnalogSmooth(100);

void setup(){

Serial.begin(9600);
Serial.println("===Starting===");
rtc.begin(&UDPClient, "north-america.pool.ntp.org");
rtc.setTimeZone(+2); // gmt offset
lcd = new LiquidCrystal_I2C(0x27, 20, 4); // set the LCD address to 0x20 for a 16x2 //SparkCore bug, address is actually 27 but shifted (0x27*2)
lcd->init(); // initialize the lcd
lcd->backlight();
lcd->clear();

pinMode(radikatemp, INPUT_PULLDOWN);
pinMode(toatemp, INPUT_PULLDOWN);
pinMode(pliiditemp, INPUT_PULLDOWN);
pinMode(pliidiveetemp, INPUT_PULLDOWN);

pinMode(ledRed, OUTPUT);
pinMode(ledGreen, OUTPUT);
pinMode(relayRadiator, OUTPUT);
pinMode(relayBoiler, OUTPUT);


digitalWrite(relayRadiator, LOW);
digitalWrite(relayBoiler, LOW);
analogWrite(ledRed,150);
}

void loop(){

currentTime = rtc.now();

if (currentTime != lastTime) {
    timeStr = "";
    timeStr += rtc.hour12String(currentTime);
    timeStr += ":";
    timeStr += rtc.minuteString(currentTime);
    timeStr += ":";
    timeStr += rtc.secondString(currentTime);    
    timeStr += " ";    
    timeStr += rtc.AMPMString(currentTime);
    
    lastTime = currentTime;
}

lcd->setCursor(5,0);
lcd->print(timeStr);

double radikaC = (as100.analogReadSmooth(radikatemp) * 3.3) / 4095*100;  //getting the voltage reading from the temperature sensor
double toaC = (as101.analogReadSmooth(toatemp) * 3.3) / 4095*100;
double pliidiC = (as102.analogReadSmooth(pliiditemp) * 3.3) / 4095*100;

// double pliidiveeC = (analogRead(pliidiveetemp) * 3.3) / 4095*100;

lcd->setCursor(1,1);
lcd->print("Radikasse");
lcd->setCursor(11,1);
lcd->print(radikaC, 1);
lcd->setCursor(1,2);
lcd->print("Toatemp");
lcd->setCursor(11,2);
lcd->print(toaC, 1);  
lcd->setCursor(1,3);
lcd->print("Pliita");
lcd->setCursor(11,3);
lcd->print(pliidiC, 1);

c = tempkontroll(radikaC, toaC, c);

byte sec = rtc.second(currentTime);
  if (sec == 10) {
          if(Spark.connected())
            {
                ThingSpeakUpdate("field1="+String(toaC)+"&field2="+String(radikaC));
            }
}

byte min = rtc.minute(currentTime);
if ((min == 10 && sec ==30) || (min == 20 && sec ==30) || (min == 30 && sec ==30) || (min == 40 && sec ==30) || (min == 50 && sec ==30) || (min == 01&& sec ==30)) {
lcd->init();
}

delay(1000);

}

void ThingSpeakUpdate(String tsData)
{
Serial.println("Date string: " + tsData);

Serial.println("...Connecting to Thingspeak");
 
// Connecting and sending data to Thingspeak
if(client.connect("api.thingspeak.com", 80))
{
    Serial.println("...Connection succesful, updating datastreams");
     
    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(tsData.length());
    client.print("\n\n");
     
    client.println(tsData); //the ""ln" is important here.
 
    // This delay is pivitol without it the TCP client will often close before the data is fully sent
    delay(200);
     
    Serial.println("Thingspeak update sent.");
}
else{
    // Failed to connect to Thingspeak
    Serial.println("Unable to connect to Thingspeak.");
}
 
if(!client.connected()){
    client.stop();
}
client.flush();
client.stop();

}

int tempkontroll(double radikaC, double toaC, int c)
{

    if(toaC < 21 && radikaC > 35 && c == 0) {
    c = 1;
    digitalWrite(relayRadiator, HIGH); //paneb relee "HIGH" asendisse
    }

    else if((toaC > 22 || radikaC < 35) && c == 1) {
    c = 0;
    digitalWrite(relayRadiator, LOW); //paneb relee "LOW" asendisse
    } 
    return c;
}

[/code]
atm i added

byte min = rtc.minute(currentTime); if ((min == 10 && sec ==30) || (min == 20 && sec ==30) || (min == 30 && sec ==30) || (min == 40 && sec ==30) || (min == 50 && sec ==30) || (min == 01&& sec ==30)) { lcd->init(); } that should do the trick but it’s not a solution.

ScruffR - yea id say bout 5x longer. What do you suggest me to try?

@qwerty009, are you trying to reset the display every 10 minutes?

and


And, does this lcd->init(); actually cure the problem?

1 Like

Yes lcd->init(); resets lcd and cures it if it's been crashed.