Insufficient delay after reset in LiquidCrystal library

Hello all, new to the arduino here, but not new to microcontrollers in general. I took an old 4x20 display I had laying around and hooked it up. When I ran the hello world example, the display didn't work properly. Characters would show on the display, but not the right ones. After messing around a bit, I added a delay(1000) after the lcd.begin call in setup() and viola, it works perfectly now. Seems that writing the "hello world" string was happening too soon after initializing the display.

I had bought these displays surplus back when I started messing with PIC chips. I got them to work using the 44780 datasheet so I suspect they are within specs, but they are definitely much slower than newer displays I've had. I'll look at the library code and see if they missed a delay somewhere during init. I'm using the display in 4-bit mode with no read back ability (so no busy flag checking, just delays after I/O).

I believe the start up delay and even some of the special LCD commands (clear display?) takes time before it can accept further characters or commands. I forget all the gory details but embedding delay()s following writing some commands to an LCD display is part of the freight you have to pay working with LCD displays. At least that is my memory, unless the library is now doing it for you?

Let us know what you find out.

Lefty

Most likely your display controller is running slower than normal and it may even be out of spec. The LiquidCrystal440 library was written to handle such displays. LiquidCrystal440 for the Arduino 1.0 is called LiquidCrystal1.0

To get a copy start here:--> Google Code Archive - Long-term storage for Google Code Project Hosting. and follow the Downloads link to get to the latest version.

Don

Thanks for the replies. Yeah lefty, I've bit banged these in the past and you absolutely have to insert the appropriate delays if you can't check the busy flag by reading the display. The library should be doing this.

Don, it's pretty old and slow but should be within spec from past experience. I was able to use a 44780 datasheet and get them working on a PIC by strictly following the delays required in the datasheet. It's funny that I only have to add the one delay after calling the begin method. After that I can call the library routines without worry so it keeps up in all other respects. I have an UNO R3 board if that matters, but it seems to work fine with the distributed library as long as I add the one delay.

From what I recall, the only really long delay that you have to do is after doing a reset, but the library must be doing that ok or it wouldn't be able to get the display into 4-bit mode.

@afremont
The LiquidCrystal library does follow the nominal delay recommendations in the datasheet but I'm not sure if it deals properly with the stuff in the stipulation that "Execution time changes when frequency changes". You might be interested in following the LCD Initialization link at http://web.alfredstate.edu/weimandn. Be sure to scroll all the way to the end and read "About the Delays".

I've done a little LCD work with PICs but it was quite a while ago and it was done in assembly language. It's around here somewhere, probably on a 5.25" floppy.

Don

Same here, all my PIC stuff was in assembler. It's been quite some time since I got started with those, but they were flash chips at least. It looks like the library allows plenty of time for the commands to execute. What's weird to me is that the clear screen is the thing I'd be most concerned about, but it issues the EntryModeSet stuff after clearing the screen and that is apparently working. I'm going to experiment with the library a little and see if allowing more clear screen time helps.

... but they were flash chips at least.

Mine were older, EEPROM versions if I remember corrrectly.

I'm going to experiment with the library a little and see if allowing more clear screen time helps.

Why re-invent the wheel if you are just interested in getting your display to work?

John already did all the work when he wrote the original LiquidCrystal440. He had a whole bunch of really substandard displays and while he was working on his 40x4 implementation he spent a lot of time on getting those substandard displays to work as well.

'FM' has also done a lot of work in this regard. Check out his 'New LiquidCrystal' library here --> https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home .

If you do go and tinker around with the library then you should also fix up the Display On/Off steps in the initialization sequence. The library does not follow the sequence recommended by Hitachi in the datasheet.

If you are interested in how things are done in assembly language I have lots of examples that I can find.

Don

I started messing with 16f84 PIC chips about 10 years ago or so, I've also done a bunch of 8052 and 6800 tinkering in assembler. My first "home computer" was a COSMAC ELF that I put together. I've been writing assembler for about 35 years now. I mostly play with the ARM7 stuff now, but I wanted to check out these Arduino do-dads to see how easy they are to work with. I kinda like them.

As for re-inventing the library, I'm not planning on that. I just want to know EXACTLY what the issue is. I'm kinda like that about mysterious or unexplained behavior. :slight_smile: I have the display working fine, I just don't like having to add the delay. It's reading an LM34 right now and displaying the temperature, updating twice per second. It's also writing the info out the serial port. Not bad for day 1 on the Arduino.

I'm thinking I may have misunderstood your offer on assembly language. At first I thought you were referring to PICs, now I suspect you meant the Arduino. I'd appreciate anything you have to offer. I'll be looking to make use of the timers and capture/compare features on the Arduino if I can. I have a PIC project that I'd like to duplicate with the Arduino if possible. It captures the rising edge of a pin and writes the number of uS since the last INT occurred out the serial port. It has to be exactly right for the project to work. The output is fed into a VB program that I use to set the beat and timing of clocks and watches. From what I've seen, it looks like I should be able to do this using C and the Arduino and still achieve perfect timing.

Yes, I did mean assembly language using the Arduino hardware.

Have you followed the link in Reply #4? There's information there that will help with the Interrupts, the Timer/Counters and with the USART. None of that information is specific to any programming language so it is applicable to anyone doing regular C based Arduino programming as well.

All of the drawings were created while I was doing assembly language work so I should be able to dig up working examples for at least some of what you want. This would certainly be off-topic for this thread but maybe not for the forum as a whole since my work is heavily (excessively ??) commented. A competent programmer could probably strip out the assembly language code and replace it with C without much trouble.

Don

Ok, thanks for the offer; I can use all the help I can get. :slight_smile: I've been around some in the micro world, but this is uncharted waters here. I checked out the rest of the stuff in the link, that's going to be quite useful, thanks. Saves allot of time by not having to scrutinize the datasheet for that info. Those interrupt routing diagrams are invaluable. Did you do those write ups? Nice.

I'm not entirely sure if this fits in this thread or if it should be a new thread, but I think it may be related, so here goes:

I'm trying to help a friend with a very simple sketch using a Mega and a 20x4 display in 4-bit mode. Initially the display was updating 10 or so characters on the display with every cycle of the main loop and the display would flicker and occasionally go blank just briefly. We assumed it was just refreshing the display too fast and added a timer of sorts such that we can reprint the characters we need at whatever interval we choose (500ms seems to be pretty good for what we need.)

After slowing down the display refresh rate, we've got stable viewing of our data now (no flicker) most of the time, but occasionally the whole display goes blank (backlight still on, but no characters displayed.) The strange thing is that when the display comes back, ALL the characters are back, not just the ones we've reprinted (half of what's on the display only gets drawn at the start of the sketch, and the other half is dynamic data that updates regularly.) If the display had been cleared or had lost power temporarily, you would think that only the newly transmitted data would appear after the blank time. The other odd thing is that the timing of the blank screen corresponds to our programmed display timer - if we have a 500ms refresh rate, the screen will go blank for exactly 500ms whenever it does go blank. If we set a 200ms refresh rate, the blank screen time is 200ms, etc.

I know there's an lcd.displayoff function which would blank the screen entirely without "forgetting" what was on the screen - is there some way we could be accidentally triggering this behavior in our code (like if we accidentally lcd.print the exact wrong string of numbers or something?) If so, would it automatically turn display function back on the next time we lcd.printed something, thereby bringing the whole display back up? Could a bad LCD initialization, as discussed above, lead to this sort of thing?

For what it's worth, I run an identical display board (a custom board made for espresso machine displays) on my Uno at home with no trouble at all, regardless of refresh rate, and we've also tried several of the same model of display (we have an unlimited supply of them at work) on my friend's Mega with the same problem each time, so I'm fairly certain that it's not just a bad display board (which is what we initially hoped!) We just can't tell if it's our code, the lcd library, or possibly something unique to his Mega that's causing these dropouts.

We assumed it was just refreshing the display too fast...

...The strange thing is that when the display comes back, ALL the characters are back, not just the ones we've reprinted ...

It sounds to me as if your whole program structure is incorrect due to a misunderstanding of how the display works.

The display does not require refreshing. After you send a character to the display it remains there until it is overwritten or until the power is removed.

Therefore any characters that do not change should ideally be sent to the display in setup() and any characters that change should be dealt with in loop() by resetting the cursor to the appropriate point and then overwriting the old information with the new.

We just can't tell if it's our code, the lcd library, or possibly something unique to his Mega that's causing these dropouts.

Neither can we without seeing the code.

Don

Ok, so "refresh" was a poor choice of words! What really happens in our sketch is that there are 4 different pages we display on the LCD. Any time you change pages, the LCD is cleared, the appropriate headings for that page ("WEIGHT", "<-NEW SET POINT", etc.) are written to the LCD, and the current data (weights, settings, etc.) is written to the LCD. Once that is done, the characters which contain current data are cleared and re-written with fresh data at whatever interval we choose (currently 500ms.) The rest of the display is left alone (no "refreshing") until we change pages again.

Our problem is that occasionally the entire screen will go blank at one of those regular intervals when only the data fields are supposed to be getting updated, and then the whole screen will come back at the next interval (headings and data fields, even though no new information for the headings was sent at that point.) I'm trying to figure out what is making the entire screen go blank and then come back, more or less on its own. Most situations I can think of that would clear the entire screen (power loss, crash of some sort, etc.) would not then restore the entire screen (including headings) automatically the next time you sent just a few characters (the data fields) to display.

Thanks in advance for any help or insights into our situation. Our code as it stands made this post too long to submit, so I've summarized the purpose of a few procedures below to save space (leaving all LCD related code untouched so you can see what's going on)

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(26, 40, 35, 33, 31, 28);


// These constants won't change:
const int sensorPin = A0;   	// pin that the sensor is attached to
const byte ledPin = 2;           // pin that the LED is attached to
const byte buttonUp = 27;   	
const byte buttonDown = 29;   
const byte buttonOne = 36;
const byte buttonTwo = 34;
const byte buttonThree = 32;
const byte buttonFour = 30;
const int stableCount = 1000; //How many times the stable loop must run before the value is accepted


// variables:
float sensorValue = 0;      // the sensor value
float sensorSet = 0;        // sensor set point
int timer = 0;		    //timer
float calibrateLow = 0;  //
float calibrateHigh = 1000;     //
float stableLoop = 5000;
boolean upState = true;    //Pressing a button pulls the pin low. Since low == false...
boolean downState = true;  //...we set these all to true (high)
boolean oneState = true;
boolean twoState = true;
boolean threeState = true;
boolean fourState = true;
byte page = 0;
const byte numValues = 50;     // Define the number of samples to keep track of.  The higher the number,
// the more the readings will be smoothed, but the slower the output will
// respond to the input.
float values[numValues];      // the readings from the analog input
byte valueIndex = 0;           // the index of the current reading
float valueTotal = 0;         // the running total
float valueAverage = 0;       // the average
long lastDisplay=0;

void setup() {
  delay(1000);
  pinMode(buttonUp, INPUT);
  pinMode(buttonDown, INPUT);
  pinMode(buttonOne, INPUT);
  pinMode(buttonTwo, INPUT);
  pinMode(buttonThree, INPUT);
  pinMode(buttonFour, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(sensorPin, INPUT);
  lcd.begin(20, 4);  // set up the LCD's number of columns and rows:
  delay(1000);
  for (byte thisValue = 0; thisValue < numValues; thisValue++){
    values[thisValue] = 0;
  }
  lcdPage();      //set display to page 0
}

// Main Loop
void loop() {
  switch(checkButtons()){      //first, check for a button press
  case 1:                      //first button is pressed
    switch(page){              //what page are we on
    case 0:                    //do nothing on page 0
      break;
    case 1:                    //pages 1-3 use stableValue to set variables
      sensorSet=stableValue();
      break;
    case 2:
      calibrateHigh=stableValue();
      break;
    case 3:
      calibrateLow=stableValue();
      break;
    }
  case 4:
    while(fourState == LOW ){
      checkButtons();
    }
    break;
  case 5:                      //button 5 (up) is pressed
    if (page==0){              //cycle backwards through pages
      page=3;
    }
    else{
      page--;
    }
    lcdPage();                 //display new page
    break;
  case 6:
    if (page==3){              //cycle forward through pages
      page=0;
    }
    else{
      page++;
    }
    lcdPage();                 //display new page
    break;
  case 0:                      //0= no button press
    if ((millis()-500)>lastDisplay){
      switch(page){                //idle behavior - no button presses
      case 0:                      //screen 0
        lcd.setCursor(7,0);
        lcd.print("       ");
        delay(0);
        lcd.setCursor(7,0);
        lcd.print(mapValue(smoothValue()));  //use smoothValue to display current reading
        break;
      default:
        lcd.setCursor(8,3);
        lcd.print("       ");
        delay(0);
        lcd.setCursor(8,3);
        lcd.print(smoothValue());
        break;        
      }
      lastDisplay=millis();
    }
  }
}

float mapValue(float value){
  // code to map values based on calibration points goes here
  return (value*0.01);
}

float smoothValue(){
  // code to average values goes here
  return valueAverage;
}

byte checkButtons(){    //when called, checks each button against the xState boolean
  // button checking code goes here
  return 0;                      //if no buttons are turned on, send 0 to main
}

float stableValue(){  //used by the set and calibrate functions to find a stable scale value
  // stable-value-finding code goes here
    }
     if ((millis()-500)>lastDisplay){      //every 500 ms...
      lcd.setCursor(8,3);                   //clear each field
      lcd.print("      ");
      lcd.setCursor(13,1);
      lcd.print("      ");
      lcd.setCursor(16,3);
      lcd.print("    ");
      lcd.setCursor(8,3);
      lcd.print(sensorValue);                //output current sensor value
      lcd.setCursor(13,1);
      lcd.print(stableLoop);                 //output current loop value
      lcd.setCursor(16,3);
      lcd.print(timer);      //output current count
      lastDisplay=millis();
    } 
    timer++;                                 //increment timer
  }
  lcd.setCursor(19,0);
  lcd.print(" ");
  return stableLoop;    //loop value has not changed in [stableCount] counts, output value.
}

void lcdPage(){
  lcd.clear();
  switch(page){
  case 0:
    lcd.setCursor(0,0);
    lcd.print("WEIGHT");
    lcd.setCursor(0,1);
    lcd.print("SET");
    lcd.setCursor(7,1);
    lcd.print(mapValue(sensorSet));
    break;
  case 1:
    lcd.setCursor(0,0);
    lcd.print("<-NEW SET POINT");
    lcd.setCursor(0,1);
    lcd.print("RUNNING SET");
    lcd.setCursor(0,3);
    lcd.print("READING");
    break;
  case 2:
    lcd.setCursor(0,0);
    lcd.print("<-CALIBRATE HIGH");
    lcd.setCursor(0,1);
    lcd.print("RUNNING HIGH");
    lcd.setCursor(0,3);
    lcd.print("READING");
    break;
  case 3:
    lcd.setCursor(0,0);
    lcd.print("<-CALIBRATE LOW");
    lcd.setCursor(0,1);
    lcd.print("RUNNING LOW");
    lcd.setCursor(0,3);
    lcd.print("READING");
    break;
  }
  return;
}

Thanks in advance for any help or insights into our situation.

I can provide an insight but no real solution at this point.

Since you are dealing with a 20x4 display this means that there are no 'hidden characters'. The LCD controller has memory space for 80 characters and your display can display 80 characters. This rules out any cursor positioning problems since no matter what position you use it will be relate to some location that is visible on your screen. The same is true for any inadvertent display shifting problems.

I haven't done much with the commands that turn the LCD ON and OFF (other than during the initialization) but it sounds as if this may be what is happening ... somehow. If you have some characters on your display and you turn the display OFF the characters will disappear. When you subsequently turn the display back on they should reappear since the memory is not cleared. This sounds like what is happening in your case.

Is your cursor normally visible? If not then you could try making it visible and and see if it remains visible when your characters disappear. If it goes away that would be consistent with the display being turned off, if not then you have a completely different problem.

Don