LCD just show grey square box

Status
Not open for further replies.

winson

New Member
Hello,

I was trying to write a simple LCD testing program to display "P" on 1st line and display "L" on the 2nd line, but my 16x2 LCD just show 2 line of grey square. I was using the Port C & Port D of my PIC16F877A and using 8-bits interface to display character on my LCD. I also try to put a pullup resistor to all the port's pins that used but the results is still the same. The 8 data pins of the LCD is connect to Port D and RS, RW, E is connect to the first 3 pins(RA0, RA1, RA2) of Port C.

I was using CCS C compiler, to write this testing program i was refer to the information provided in the HD44780U datasheet.

Anybody can give some suggestions regarding the error that i have make?
The testing program is shown below.

Any suggestion will be greatly appreciate.
Thanks.

Code:
#include <16F877A.h>
#fuses hs, nowdt, nolvp, noprotect   //Config
#use delay (clock = 20000000)      //20MHz Crystal

void init(void);      //Function Prototype
void busy_test(void);
void display(void);
void send_command(void);
void send_data(void);

unsigned char PORTC, TRISC, PORTD, TRISD, RS, RW, E, BF;
unsigned char command, data;

#byte PORTC = 0x07
#byte TRISC = 0x87
#byte PORTD = 0x08
#byte TRISD = 0x88

#bit RS = PORTC.0
#bit RW = PORTC.1
#bit E  = PORTC.2
#bit BF = PORTD.7

void main()
{
   init();
   display();
   while (1)
   {

   }   
}

void init()
{
   PORTC = 0x00;   //Clear Port C
   PORTD = 0x00;   //Clear Port D

   TRISC = 0x00;   //Set Port C As Output
   TRISD = 0x00;   //Set Port D As Output

   delay_ms (500);   //Power-On Delay
         //Busy Flag Valid Here

   //busy_test();   //Check Busy Flag
   command = 0x38;   //8-Bits, 2-Lines, 5x7 Dots
   send_command();   //Send Command To LCD

   delay_ms (10);

   //busy_test();   //Check Busy Flag
   command = 0x38;   //8-Bits, 2-Lines, 5x7 Dots
   send_command();   //Send Command To LCD

   delay_us (500);

   //busy_test();   //Check Busy Flag
   command = 0x38;   //8-Bits, 2-Lines, 5x7 Dots
   send_command();   //Send Command To LCD

   delay_ms (1);

   busy_test();   //Check Busy Flag
   command = 0x38;   //8-Bits, 2-Lines, 5x7 Dots
   send_command();   //Send Command To LCD

   delay_ms (1);

   busy_test();   //Check BF
   command = 0x08;   //Display Off, Cursor Off, No-Blink
   send_command();   //Send

   delay_ms (1);

   busy_test();
   command = 0x01;   //Clear Display
   send_command();

   delay_ms (5);

   busy_test();
   command = 0x06;   //Increment Cursor Position, No-Shift
   send_command();

   delay_ms (1);

   busy_test();
   command = 0x0F;   //Display On, Cursor On, Blink
   send_command();

   delay_ms (1);
}


void display()
{

   busy_test();
   command = 0x80;   //Set DDRAM Address To 0x00
   send_command();

   delay_ms (1);

   busy_test();
   data = 0x50;   //Display "P"
   send_data();

   delay_ms (1);

   busy_test();
   command = 0xC0;   //Set DDRAM Address To 0x40
   send_command();

   delay_ms (1);

   busy_test();
   data = 0x4C;   //Display "L"
   send_data();

   delay_ms (1);

}


void busy_test()
{
   while (1)
   {
      TRISD = 0xFF;      //Set Port D As Input
      //RS = 0;            //Command
      //RW = 1;            //Read Busy Flag
      PORTC = 0x02;

      delay_cycles (2);   //Control Setup Time
      //E  = 1;            //E-Line High
      PORTC = 0x06;

      delay_cycles (6);   //Wait Data Return

      if (BF == 0)
      {
         TRISD = 0x00;   //Set Port D Back To Output
         //E  = 0;         //E-Line Low
         PORTC = 0x02;
         return;
      }

      //E  = 0;            //E-Line Low
      PORTC = 0x02;
   }      //End while loop
}      //End Function


void send_command()
{   
   //RS = 0;            //Command
   //RW = 0;            //Write Instruction
   PORTC = 0x00;

   delay_cycles (2);   //Control Setup Time
   //E  = 1;            //E-Line High
   PORTC = 0x04;

   delay_cycles (3);   
   PORTD = command;   //Put Command To Port D

   delay_cycles (3);   //Data Setup Time
   //E  = 0;            //E-Line Low
   PORTC = 0x00;
   delay_cycles (1);   //Control & Data Hold Time
}


void send_data()
{
   //RS = 1;            //Data
   //RW = 0;            //Write data
   PORTC = 0x01;
   
   delay_cycles (2);   //Control Setup Time
   //E  = 1;            //E-Line High
   PORTC = 0x05;

   delay_cycles (3);
   PORTD = data;      //Put Data To Port D

   delay_cycles (3);   //Data Setup Time
   //E  = 0;            //E-Line Low
   PORTC = 0x01;
   delay_cycles (1);   //Control & Data Hold Time
}
 
You have to write the data before you make the enable line high.

Swap it around so data is written first,
Code:
void send_data()
{
   //RS = 1;            //Data
   //RW = 0;            //Write data
   PORTC = 0x01;
   
   delay_cycles (3);
   PORTD = data;      //Put Data To Port D

   delay_cycles (2);   //Control Setup Time
   //E  = 1;            //E-Line High
   PORTC = 0x05;

   delay_cycles (3);   //Data Setup Time
   //E  = 0;            //E-Line Low
   PORTC = 0x01;
   delay_cycles (1);   //Control & Data Hold Time
}

Same with the write command routine.

Mike.
 
Hi Pommie,

Thanks for reply, just now i have try to swap the code to make it first write the data to Port D then toggle the E pin from high to low for both the send command routine and the send data routine, and what i observe now is the LCD still display 2 line of grey block just like last time, is it possible i have make some other mistake?
 
Last edited:
I haven't looked at your code, but have you tried adjusting the contrast control on the LCD?
 
Hi Pommie,

What you means "stop the code"? Is it just try load some portion of the code to the LCD?
 
Hi kchriste,

Yes i have adjust the contrast, For my LCD, i was using a 3.3k resistor to limits the current of the 5V Vdd to 1.5mA, and for the contrast pin Vo i was connect it to a voltage divider which is form by a 10K resistor in series with a 5K variable resistor, the LCD's Vo pin is connect to the point in between the 10k resistor and 5k VR, the 10K resistor side is connect to the 1.5mA, 5V supply and the 5K VR side is connect to ground. To control the contrast i was turn the variable resistor, in order to see the grey block i need turn the VR to almost 0 ohms and when i turn the VR to full 5K ohms then the grey block will slowly disappear.
 
Last edited:
How confident are you about the LCD wiring. It is easy to get two mixed up, or reverse the order.

I have a small PCB with resistors and LEDs that has the same wiring as a LCD. I put it in place and step through the code using the debugger to ensure first that all bits work and then that each bit is in the right place.
 
Finally the LCD is WORKING!

The problem is in the power supply. The 5V Vdd supply voltage drop to 4.33V when it is connect to the LCD. I was using a battery for the LCD, due to high supply current of the 9V battery, thus have to put a current limiting resistor to limit the current that goes into the LCD, And i think because of the LCD consist of certain amount of internal resistance(from calculation it is around 23.23K ohms), this resistance will form a voltage divider with my current limiting resistor and make the supply voltage to the LCD drop to 4.33V. Normally, for LCD it's Vdd range is from 4.5V to 5.5V in order for it to work correctly.

After adjust the value of the current limiting resistor to get back a Vdd which is around 4.6V then the LCD work nicely. Besides, for the Vo of the LCD i was directly connect it to ground to get maximum contrast, this is to avoid the variable resistor(pot) that use to control the contrast from disturbing the voltage value of the Vdd.

For the send_command() and send_data() function i was modify the code to first load the data to the Port D then toggle the E signal from low to high then goes back to low again. I think it also work by set the E signal to high first then load data to Port D and after that set E to low, but since the LCD is working then i will follow the modified code.

Thanks everybody for giving all the useful suggestion!
 

You don't need, and shouldn't use, any resistor in the power supply feed. You need a 5V regulator, that provides a constant 5V for the circuit - trying to feed it directly from a 9V battery is going to fry something, it's EXTREMELY foolhardy, and you'll never see it done.

Check my tutorial hardware for simple examples.
 

I just checked the datasheet and you are correct, the data is latched on the falling edge of the enable signal. I learnt something new.

Mike.
 

Hi Nigel,

Thanks for your suggestion.
Yes i'm using a LM7805 IC to regulate the power supply to the entire board(this is what i forget to tell in my previous reply). For the LM7805 IC it just able to limit it's output current to a range of 700mA to 1000mA, and this value of current is consider very large for the Vdd of an LCD which is in the range of 1.5mA to 3mA and no choice for me to put a current limiting resistor to the Vdd pin.

I was thinking is it possible just fed a 700mA to the Vdd pin of an LCD(to avoid using current limiting resistor), so anybody have any suggestion, is it possible?

From my point of view, the LCD may be can act as a resistor and just withdraw the current that it need although there are 700mA giving to it, like the 8 data pins of the LCD we do not put any resistor when connect it the PIC i/o pin which can supply 25mA to the LCD, it is something like the pins of the LCD having some high impedance. But anyway i still not try to directly give 700mA to LCD(afraid the LCD will damage).

The Vdd pin of a PIC16F877A can accept 5A of current and it does not damaged, this is my experience when i accidently forget to put a current limiting resistor to the output of the LM7805 IC.(Just measure again the 9V battery that i'm using, it's current already become weak a bit but still maintain in 2A.)

Can anybody give some comment on this?

Thanks
 
Last edited:
I just checked the datasheet and you are correct, the data is latched on the falling edge of the enable signal. I learnt something new.

Mike.

Hi Pommie,

Yes it is in falling edge, but the code swapping you suggest by first load the data then toggle the E signal is also correct and it work for me now(as long as during the falling edge of the E signal there are data available then the LCD will work). Last time it does not work is because of the power supply problem and thus make the LCD fail to initialize.

Thanks a lot
 
You don't need any current limiting resistor. The LCD won't drain any more current than it needs.

Wow! This is really a good news for me! By throwing away the current limiting resistor then all the headache will disappear together.

So is it also apply for the power supply of the LCD backlight? I know that a typical LCD backlight will need 60mA to 100mA for enough brightness, if the supply is more that 100mA then the LED will just drain the amount that they need?
 
You WILL need a current limiting resistor for the LCD backlight because they are usually just LEDs which need a resistor to limit the current. The PIC and LCD Vdd lines should NOT have a resistor in series with them as you now know.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…