HD44780 Display does not work at 16MHZ

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
I bought several 16x2 LCD displays on eBay. They are HD44780 compatible. My pic is has an internal IRC OSC capable of 31KHz, 250Khz, 500khz, 1Mhz, 4mhz, 8mhz and 16mhz.


I have tested the displays with 250khz to 16mhz. And it works fine on all frequencies except 16mhz.

At 16MHZ, it sort of works but displays either all or some garbage characters.

I am guessing the problem is a timing issue. Could it be the internal IRC is just unstable at 16MHZ? I do not have a 16MHZ crystal on hand.

Here is my code for my delay at 16MHZ. It appears to be accurate.

Rich (BB code):
extern unsigned char macro_delay;
            

#define delay_us(a) _asm movlw a\
                      movwf macro_delay,1\
              loop:      nop\
                      decfsz macro_delay,1,1\
                      bra loop\
                 _endasm


void delay_ms(unsigned int x);

    
unsigned char macro_delay;

void delay_ms(unsigned int x)
 {unsigned int i;
    for(i=0; i<x;i++)     
    {
    
        delay_us(200);
        delay_us(200);
        delay_us(200);
        delay_us(200);
        delay_us(200);
    }
}
 

thatoneguy

Joined Feb 19, 2009
6,359
20 milliseconds from power on to first command to LCD
5 milliseconds between commands
200 microseconds between characters

If you are getting garbage between characters, try increasing the inter-character delay by double or so.

I can write to LCD using the internal RC at 20Mhz, so I doubt that is the issue.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
20 milliseconds from power on to first command to LCD
5 milliseconds between commands
200 microseconds between characters

If you are getting garbage between characters, try increasing the inter-character delay by double or so.

I can write to LCD using the internal RC at 20Mhz, so I doubt that is the issue.

But why would it work at 8mhz? Same code and hopefully same delay if I am calcualting my delay correctly. But I will give it a try.


Got any code you want to share?

What I like about the code I have is I can pick each pin as opposed to having to use a PORT like the XLCD microchip code appears to be.


What is strange is if I power off the pic and lcd and turn it back on, it works for the first line or two. Then it starts to get all messed up.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
Thanks looks like it was the delays. The original code had no delays between characters and short delays between commands. I just spent the whole day trying to figure that one out :(. :)
 

thatoneguy

Joined Feb 19, 2009
6,359
I use the compiler delay_ms(xx) and delay_us(xx) functions, rather than the assembly call. The compiler gets it correct with various delays. Example, went for a 25 Hz blinking LED, measured it at 25.001 Hz, toggling to 25 Hz. That was it's only task, but it's still impressive using only the delay function.

Here is this one from Myke Predko - cLCD.c Works in BoostC when I change the variables, only raw LCD one I had handy (others require a lot of surgery to get just the LCD routines from).

For BoostC, it's just a matter of changing PORTC.RC2 to portc.2 or whichever defines. That and the config word to match sourceboost's definitions. Works on 16F877A.
Rich (BB code):
#include 
/*  cLCD.c - Write a String to a 4 Bit Hitachi 44780 LCD I/F

This Program Initializes Hitachi 44780 Based LCD in 4 Bit Mode
  and then writes a simple string to it.  The simulator was used
  to time delay values.  

LCD Write Information can be found at http://www.myke.com

RC3:RC0 - LCD I/O D7:D4 (Pins 14:11)
RC4     - LCD 6 Clocking Pin
RC5     - LCD 4 Pin

myke predko
04.11.08
*/

__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT \
  & UNPROTECT & BORDIS & IESODIS & FCMDIS);

int i, j, k, n;                 //  Use Global Variables for Debug

//                         1234567890123456
const char TopMessage[] = "    PIC MCU     ";
const char BotMessage[] = "  Evil Genius   ";

#define E  RC4                  //  Define the LCD Control Pins
#define RS RC5

const int Twentyms = 1250;      //  Declare a Constant for 20 ms Delay
const int Fivems = 300;
const int TwoHundredus = 10;

LCDWrite(int LCDData, int RSValue)
{

    PORTC = (LCDData >> 4) & 0x0F;  //  Get High 4 Bits for Output
    RS = RSValue;
    E = 1;  E = 0;              //  Toggle the High 4 Bits Out

    PORTC = LCDData & 0x0F;     //  Get Low 4 Bits for Output
    RS = RSValue;
    E = 1;  E = 0;              //  Toggle the Low 4 Bits Out

    if ((0 == (LCDData & 0xFC)) && (0 == RSValue))
        n = Fivems;             //  Set Delay Interval
    else
        n = TwoHundredus;

    for (k = 0; k < n; k++);    //  Delay for Character

}  //  End LCDWrite

main()
{

    PORTC = 0;                  //  Start with Everything Low
    CMCON0 = 7;                 //  Turn off Comparators
    ANSEL = 0;                  //  Turn off ADC
    TRISC = 0;                  //  All of PORTC are Outputs

//  Initialize LCD according to the Web Page
    j = Twentyms;
    for (i = 0; i < j; i++);    //  Wait for LCD to Power Up

    PORTC = 3;                  //  Start Initialization Process
    E = 1;  E = 0;              //  Send Reset Command
    j = Fivems;
    for (i = 0; i < j; i++);

    E = 1;  E = 0;              //  Repeat Reset Command
    j = TwoHundredus;
    for (i = 0; i < j; i++);

    E = 1;  E = 0;              //  Repeat Reset Command Third Time
    j = TwoHundredus;
    for (i = 0; i < j; i++);

    PORTC = 2;                  //  Initialize LCD 4 Bit Mode
    E = 1;  E = 0;
    j = TwoHundredus;
    for (i = 0; i < j; i++);

    LCDWrite(0b00101000, 0);    //  LCD is 4 Bit I/F, 2 Line

    LCDWrite(0b00000001, 0);    //  Clear LCD 

    LCDWrite(0b00000110, 0);    //  Move Cursor After Each Character

    LCDWrite(0b00001110, 0);    //  Turn On LCD and Enable Cursor

    for (i = 0; TopMessage != 0; i++)
        LCDWrite(TopMessage, 1);

    LCDWrite(0b11000000, 0);    //  Move Cursor to the Second Line

    for (i = 0; BotMessage != 0; i++)
        LCDWrite(BotMessage, 1);

    while(1 == 1);              //  Finished

}  //  End cLCD

 

thatoneguy

Joined Feb 19, 2009
6,359
Thanks looks like it was the delays. The original code had no delays between characters and short delays between commands. I just spent the whole day trying to figure that one out :(. :)
Glad you got it working!

LCDs are picky sometimes. At the same time, I've found the RC oscillator remarkably stable for a given temperature.

Do you have the code that you wrote the the LCD with? 4 bit or 8 bit mode? I almost always use 4, unless it is GLCD.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
Let me clean it up and make it more user friendly. I will then post it.

I am guessing that under 16MHZ the LCD was tolerant of delays under 16MHZ,
 

ELECTRONERD

Joined May 26, 2009
1,147
I had this same experience as well, and it would appear that your PIC is going too fast for the LCD to understand. Thus, as it picks up information, it might catch one or two but then rush into the next data information, some characters will be lost.
 
Top