Go Down

Topic: LCD problem (Read 499 times) previous topic - next topic

rickwise



I'm having trouble with an LCD display, a 16x2 from Adafruit (product ID 181).  It's based on HD44780.  I'm driving it directly, no serial adapter.

The thing runs okay for a while, then either blanks out or starts displaying nonsense.  A sketch is attached, just the LCD "hello world" example, modified for my pinouts.   One interesting thing is that the nonsense seems to change every second, as if a particular bit of nonsense is triggered by the value in the call to lcd.print().  I have a pushbutton, and when I press it, it calls lcd.begin().  When the display goes wrong, I can push the button and it goes right back to showing seconds.  If I'm attached to the computer and monitoring serial, that agrees: everything is fine except the display.

The circuit is trivial: I have a 10k pot from +5 to gnd, wiper to pin 3 (LCD v0).  I have a pot configured as a rheostat between +5 and pin 3 (LED+, the backlight).  VSS, LED-, and RW are grounded, VDD to +5.  Then I have RS, EN, and data 4-7 connected to Ardiuno pins.  I have a momentary switch, connected to Arduino pin DIO 10.

As part of troubleshooting, I've tied the unused Data 0-3 pins to ground, no improvement.   Having seen something about current concerns in another thread, I've tested it with an AC adapter, no improvement.

cattledog

OP's code
Code: [Select]
#include <LiquidCrystal.h>

int   pin_RS = 8;
int   pin_EN = 9;
int   pin_DB4 = 4;
int   pin_DB5 = 5;
int   pin_DB6 = 6;
int   pin_DB7 = 7;
int   pin_control = 10;

LiquidCrystal lcd (pin_RS, pin_EN, pin_DB4, pin_DB5, pin_DB6, pin_DB7);

void lcdBegin()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!"); 
}

void setup() {
  // enable debug
  Serial.begin(9600);
  // initialize LCD
  lcdBegin();
  // set up the control pin as input
  pinMode(pin_control, INPUT_PULLUP);
}

void loop() {

  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis() / 1000);
  // show loop in debug
  Serial.println(millis());

  if (digitalRead(pin_control) == LOW) {
    lcdBegin();
  }
}


You should not update the lcd every pass through loop.

You can print when data changes--that is if millis()/1000 != to previous value. You will need an additional variable to hold the previous value.

Alternatively, refresh the lcd periodically with a millis() timer following the "blink without delay()" method. Your eye can't follow fast changes, and a 200 ms period is probably as fast as you ever want. In your case, looking at seconds, the updates could be at 500ms or 1000ms.

Paul__B

If you must refer to code, please post it in-line according to the instructions.  :smiley-lol:

I haven't looked at your code as cattledog has already addressed the matter, but offer a useful hint.  Do not connect the 10k contrast potentiometer to 5 V - just leave that end unconnected (or tie it to the wiper).  This is a mistake that has become ingrained in hobby (and no doubt, some professional) designs since the "early days".  Disconnecting it makes contrast setting twice as easy!

rickwise


Sorry about not including code.

Cattledog, the trouble isn't that it flickers, it sporadically changes to displaying nonsense, which I can fix by hitting the pushbutton, which calls lcd.begin().  I left the code updating every time in loop() so as to change least from the example.  In my real code, it displays periodically.

Paul__b, I'll try changing the contrast pot: do you suggest this could affect the display problem, or is it just good practice?

dougp

Just curious, why the second

Code: [Select]
lcdBegin();
?
Everything we call real is made of things that cannot be regarded as real.  If quantum mechanics hasn't profoundly shocked you, you haven't understood it yet. - Niels Bohr

No private consultations undertaken!

cattledog

Quote
In my real code, it displays periodically.
Please post the actual code which demonstrates the problem. Best would be a MCVE "minimal complete verifiable example". Ideally, others should be able to run your code and replicate the problem. If there are libraries other than the IDE's LiquidCrystal.h involved, please indicate their source.

Are there any relays or motors involved with your project. Is the lcd in an electronically noisy environment?

rickwise

Code: [Select]
#include <LiquidCrystal.h>

int   pin_RS = 8;
int   pin_EN = 9;
int   pin_DB4 = 4;
int   pin_DB5 = 5;
int   pin_DB6 = 6;
int   pin_DB7 = 7;
int   pin_control = 10;

LiquidCrystal lcd (pin_RS, pin_EN, pin_DB4, pin_DB5, pin_DB6, pin_DB7);

void lcdBegin()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!"); 
}

void setup() {
  // enable debug
  Serial.begin(9600);
  // initialize LCD
  lcdBegin();
  // set up the control pin as input
  pinMode(pin_control, INPUT_PULLUP);
}

void loop() {

  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis() / 1000);
  // show loop in debug
  Serial.println(millis());

  if (digitalRead(pin_control) == LOW) {
    lcdBegin();
  }
}


This is the minimum verifiable example.  The actual application is a smart thermostat.

The reason for the second lcd.begin() is that it clears the display.  I tried calling lcd.noDisplay() then lcd.display(), but it doesn't help.

There's no major source of EMI, like motors, but it is a breadboard at this time, so it could be more sensitive than a finished circuit to ordinary stuff like bluetooth and laptops.  There will be a relay, but so far I'm still working on UI and controls, so there's no relay yet.

cattledog

There is no print control in the code you attached. It is still writing to the lcd every pass through loop().

rickwise

I updated the code as shown below.  Cattledog, do you think the every-loop call to the LCD is the source of it going crazy?  If so, why?

In any event, it's running this code now, and I'll post the results.

BTW, Paul__B, the data sheet for the LCD module (TC1602A-09T) shows the contrast pot with end terminals to VDD (+5) and VSS, with the wiper to V0.  Is there a reason you recommend removing the +5?

Code: [Select]
#include <LiquidCrystal.h>

int   pin_RS = 8;
int   pin_EN = 9;
int   pin_DB4 = 4;
int   pin_DB5 = 5;
int   pin_DB6 = 6;
int   pin_DB7 = 7;
int   pin_control = 10;

#define INTERVAL  1000    // update every second

unsigned long display_t;

LiquidCrystal lcd (pin_RS, pin_EN, pin_DB4, pin_DB5, pin_DB6, pin_DB7);

void lcdBegin()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!"); 
}

void setup() {
  // enable debug
  Serial.begin(9600);
  // initialize LCD
  lcdBegin();
  // set up the control pin as input
  pinMode(pin_control, INPUT_PULLUP);
  display_t = 0;
}

void loop() {

  if (millis() - display_t >= INTERVAL) {
    unsigned long t = millis();
    display_t = t;
    // set the cursor to column 0, line 1
    // (note: line 1 is the second row, since counting begins with 0):
    lcd.setCursor(0, 1);
    // print the number of seconds since reset:
    lcd.print(t / 1000);
    // show in debug
    Serial.println(t);
  }

  if (digitalRead(pin_control) == LOW) {
    lcdBegin();
  }
}

rickwise


The version of the code shown in the previous post just went into crazy mode, so no improvement with limiting the frequency of update.

Paul__B

I updated the code as shown below.  Cattledog, do you think the every-loop call to the LCD is the source of it going crazy?  If so, why?
Well, it probably does not explain "going crazy", but updating ridiculously often will result in a flickering and unreadable display.  Your code has problems and will take a bit of work.

The rule for display updates is - update only when the data to be display changes, update only the part of the display that needs to be changed and not more than every 200 ms - five times a second.  Your code needs to be written to follow each part of this rule.  Sorry, I haven't looked at it in detail.

BTW, Paul__B, the data sheet for the LCD module (TC1602A-09T) shows the contrast pot with end terminals to VDD (+5) and VSS, with the wiper to V0.  Is there a reason you recommend removing the +5?
Yes!  You are right!  :smiley-lol: The datasheet does show that.  So it is wrong!

It is a hotchpotch of snippets from the original datasheets, put together by people with limited engineering competence - just sufficient to make a product work.  This is the problem; the HD44780 chip was produced, one or two manufacturers made use of it and made a mistake by copying a "test" circuit from one version of the datasheet and this design was copied and copied and copied, and copied and copied ad infinitum.  The suggestion of a 20 to 50k pot is even more stupid than a 10k pot as it will make setting the contrast even more difficult.

Don't connect it to 5 V, not connecting it makes contrast setting twice as easy!  Using a 1k pot makes it even easier.

cattledog

Quote
The version of the code shown in the previous post just went into crazy mode, so no improvement with limiting the frequency of update.
Your results are very atypical, particularly with an adafruit display. These displays are very reliable when they are not around motors and relays. In noisy environments, it can be a struggle to keep them "garbage" free.

If you soldered the headers on, can you please provide a photo of the soldering. Also, a photo of your breadboard arrangement would be helpful.

As a first effort, try placing the largest capacitor you have across the Vcc and ground pins of the display.


rickwise


OK, I'll admit it in public, I'm a moron.  Decoupling caps (smacks head).

I added some 1uF caps, and things have been stable for a couple of days.

Thanks, Cattledog!

PS: Paul__B, I tied the high side of the contrast pot to the wiper, no +5, works fine.

Go Up