16x2 lcd fails to intialize from time to time

Discussion in 'Embedded Systems and Microcontrollers' started by Anirban Raha, Feb 8, 2015.

  1. Anirban Raha

    Thread Starter Member

    Dec 4, 2013
    70
    0
    Hi! I'm using a AT89s52 and 16x2 LCD display(JHD 162A) in 8 bit mode. The problem is, when I power up my circuit, the LCD, sometimes does not display anything except black boxes on the first line. Other times, it is working fine. Does this mean that sometimes my LCD is not being initialized properly? This is happening on a breadboard, a perf-board, and also on a dev board(http://exploreembedded.com/wiki/8051_Ultra_Development_Kit) that I have recently purchased. Why is this happening? Can someone please help!

    Code (Text):
    1. #include<reg52.h>                             //including sfr registers for ports of the controller
    2. #include<lcd.h>
    3.  
    4. //LCD Module Connections
    5. sbit RS = P0^0;                                                                  
    6. sbit EN = P0^1;                          
    7. sbit D0 = P2^0;
    8. sbit D1 = P2^1;
    9. sbit D2 = P2^2;
    10. sbit D3 = P2^3;
    11. sbit D4 = P2^4;
    12. sbit D5 = P2^5;
    13. sbit D6 = P2^6;
    14. sbit D7 = P2^7;
    15. //End LCD Module Connections
    16. void Delay(int a)
    17. {
    18.     int j;
    19.     int i;
    20.     for(i=0;i<a;i++)
    21.     {
    22.         for(j=0;j<100;j++)
    23.         {
    24.         }
    25.     }
    26. }
    27. void main()
    28. {
    29.     int i;
    30.     Lcd8_Init();                                
    31.   while(1)
    32.   {                                  
    33.     Lcd8_Set_Cursor(1,1);
    34.       Lcd8_Write_String("TEST");
    35.     }
    36. }
    37.  
    The header file lcd.h :

    Code (Text):
    1. //LCD Functions Developed by electroSome
    2.  
    3. //LCD Module Connections
    4. extern bit RS;                                                                  
    5. extern bit EN;                          
    6. extern bit D0;
    7. extern bit D1;
    8. extern bit D2;
    9. extern bit D3;
    10. extern bit D4;
    11. extern bit D5;
    12. extern bit D6;
    13. extern bit D7;
    14. //End LCD Module Connections
    15.  
    16.  
    17. void Lcd_Delay(int a)
    18. {
    19.     int j;
    20.     int i;
    21.     for(i=0;i<a;i++)
    22.     {
    23.         for(j=0;j<400;j++)
    24.         {
    25.         }
    26.     }
    27. }
    28.  
    29. //LCD 8 Bit Interfacing Functions
    30. void Lcd8_Port(char a)
    31. {
    32.     if(a & 1)
    33.         D0 = 1;
    34.     else
    35.         D0 = 0;
    36.    
    37.     if(a & 2)
    38.         D1 = 1;
    39.     else
    40.         D1 = 0;
    41.    
    42.     if(a & 4)
    43.         D2 = 1;
    44.     else
    45.         D2 = 0;
    46.    
    47.     if(a & 8)
    48.         D3 = 1;
    49.     else
    50.         D3 = 0;
    51.    
    52.     if(a & 16)
    53.         D4 = 1;
    54.     else
    55.         D4 = 0;
    56.  
    57.     if(a & 32)
    58.         D5 = 1;
    59.     else
    60.         D5 = 0;
    61.    
    62.     if(a & 64)
    63.         D6 = 1;
    64.     else
    65.         D6 = 0;
    66.    
    67.     if(a & 128)
    68.         D7 = 1;
    69.     else
    70.         D7 = 0;
    71. }
    72. void Lcd8_Cmd(char a)
    73. {
    74.   RS = 0;             // => RS = 0
    75.   Lcd8_Port(a);             //Data transfer
    76.   EN  = 1;             // => E = 1
    77.   Lcd_Delay(5);
    78.   EN  = 0;             // => E = 0
    79. }
    80.  
    81. Lcd8_Clear()
    82. {
    83.       Lcd8_Cmd(1);
    84. }
    85.  
    86. void Lcd8_Set_Cursor(char a, char b)
    87. {
    88.     if(a == 1)
    89.       Lcd8_Cmd(0x80 + b);
    90.     else if(a == 2)
    91.         Lcd8_Cmd(0xC0 + b);
    92. }
    93.  
    94. void Lcd8_Init()
    95. {
    96.     Lcd8_Port(0x00);
    97.     RS = 0;
    98.     Lcd_Delay(200);
    99.     ///////////// Reset process from datasheet /////////
    100.   Lcd8_Cmd(0x30);
    101.     Lcd_Delay(50);
    102.   Lcd8_Cmd(0x30);
    103.     Lcd_Delay(110);
    104.   Lcd8_Cmd(0x30);
    105.   /////////////////////////////////////////////////////
    106.   Lcd8_Cmd(0x38);    //function set
    107.   Lcd8_Cmd(0x0C);    //display on,cursor off,blink off
    108.   Lcd8_Cmd(0x01);    //clear display
    109.   Lcd8_Cmd(0x06);    //entry mode, set increment
    110. }
    111.  
    112. void Lcd8_Write_Char(char a)
    113. {
    114.    RS = 1;             // => RS = 1
    115.    Lcd8_Port(a);             //Data transfer
    116.    EN  = 1;             // => E = 1
    117.    Lcd_Delay(5);
    118.    EN  = 0;             // => E = 04
    119. }
    120.  
    121. void Lcd8_Write_String(char *a)
    122. {
    123.     int i;
    124.     for(i=0;a[i]!='\0';i++)
    125.      Lcd8_Write_Char(a[i]);
    126. }
    127.  
    128. void Lcd8_Shift_Right()
    129. {
    130.     Lcd8_Cmd(0x1C);
    131. }
    132.  
    133. void Lcd8_Shift_Left()
    134. {
    135.     Lcd8_Cmd(0x18);
    136. }
    137. //End LCD 8 Bit Interfacing Functions
    138.  
    139. //LCD 4 Bit Interfacing Functions
    140.  
    141. void Lcd4_Port(char a)
    142. {
    143.     if(a & 1)
    144.         D4 = 1;
    145.     else
    146.         D4 = 0;
    147.    
    148.     if(a & 2)
    149.         D5 = 1;
    150.     else
    151.         D5 = 0;
    152.    
    153.     if(a & 4)
    154.         D6 = 1;
    155.     else
    156.         D6 = 0;
    157.    
    158.     if(a & 8)
    159.         D7 = 1;
    160.     else
    161.         D7 = 0;
    162. }
    163. void Lcd4_Cmd(char a)
    164. {
    165.     RS = 0;             // => RS = 0
    166.     Lcd4_Port(a);
    167.     EN  = 1;             // => E = 1
    168.   Lcd_Delay(5);
    169.   EN  = 0;             // => E = 0
    170. }
    171.  
    172. Lcd4_Clear()
    173. {
    174.     Lcd4_Cmd(0);
    175.     Lcd4_Cmd(1);
    176. }
    177.  
    178. void Lcd4_Set_Cursor(char a, char b)
    179. {
    180.     char temp,z,y;
    181.     if(a == 1)
    182.     {
    183.       temp = 0x80 + b;
    184.         z = temp>>4;
    185.         y = (0x80+b) & 0x0F;
    186.         Lcd4_Cmd(z);
    187.         Lcd4_Cmd(y);
    188.     }
    189.     else if(a == 2)
    190.     {
    191.         temp = 0xC0 + b;
    192.         z = temp>>4;
    193.         y = (0xC0+b) & 0x0F;
    194.         Lcd4_Cmd(z);
    195.         Lcd4_Cmd(y);
    196.     }
    197. }
    198.  
    199. void Lcd4_Init()
    200. {
    201.     Lcd4_Port(0x00);
    202.     Lcd_Delay(200);
    203.     ///////////// Reset process from datasheet /////////
    204.   Lcd4_Cmd(0x03);
    205.     Lcd_Delay(50);
    206.   Lcd4_Cmd(0x03);
    207.     Lcd_Delay(110);
    208.   Lcd4_Cmd(0x03);
    209.   /////////////////////////////////////////////////////
    210.   Lcd4_Cmd(0x02);  
    211.     Lcd4_Cmd(0x02);
    212.   Lcd4_Cmd(0x08);    
    213.     Lcd4_Cmd(0x00);
    214.     Lcd4_Cmd(0x0C);    
    215.   Lcd4_Cmd(0x00);  
    216.   Lcd4_Cmd(0x06);  
    217. }
    218.  
    219. void Lcd4_Write_Char(char a)
    220. {
    221.    char temp,y;
    222.    temp = a&0x0F;
    223.    y = a&0xF0;  
    224.      RS = 1;             // => RS = 1
    225.    Lcd4_Port(y>>4);             //Data transfer
    226.      EN = 1;
    227.      Lcd_Delay(5);
    228.      EN = 0;
    229.      Lcd4_Port(temp);
    230.      EN = 1;
    231.      Lcd_Delay(5);
    232.      EN = 0;
    233. }
    234.  
    235. void Lcd4_Write_String(char *a)
    236. {
    237.     int i;
    238.     for(i=0;a[i]!='\0';i++)
    239.      Lcd4_Write_Char(a[i]);
    240. }
    241.  
    242. void Lcd4_Shift_Right()
    243. {
    244.     Lcd4_Cmd(0x01);
    245.     Lcd4_Cmd(0x0C);
    246. }
    247.  
    248. void Lcd4_Shift_Left()
    249. {
    250.     Lcd4_Cmd(0x01);
    251.     Lcd4_Cmd(0x08);
    252. }
    253. //End LCD 4 Bit Interfacing Functions
    254.  
    The circuit is a standard interface between AT89s52 and 16x2 LCD with R/W grounded, Port P2 connected to D0-D7, P0.0 = RS, P0.1 = E of LCD. Contrast has been set using a 10k pot with Vee to Vss resistance set to 1.5kohm.
     
  2. Art

    Distinguished Member

    Sep 10, 2007
    785
    61
    Try delaying a whole second after powerup before talking to the LCD at all.
     
  3. Anirban Raha

    Thread Starter Member

    Dec 4, 2013
    70
    0
    Tried. Same thing happening. However, I have made another observation. If I press the reset button connected to the RST of my uC, the LCD displays correctly. Any explanations?
     
  4. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005
    Delays between commands to LCDS might not be long enough.

    Also post your schematic.
     
  5. Art

    Distinguished Member

    Sep 10, 2007
    785
    61
    That would be my next suggestion. You haven’t said what speed the micro is clocked.

    If all else fails you could do a hardware delay, but always preferable to find the problem.

    [​IMG]

     
  6. absf

    Senior Member

    Dec 29, 2010
    1,492
    372
    Port 1,2,3 has internal pullups while port 0 has open-drain outputs. Did you put pullup resistors on the EN and RS lines?

    Allen
     
  7. Anirban Raha

    Thread Starter Member

    Dec 4, 2013
    70
    0
    I've tried increasing delays to several seconds...didn't make any difference except making things slower when it's working. The schematic attached is of my perf-board. It does not have a reset button and thus the circuit works only occasionally. My dev board has a reset button. In my dev board, I need to press the reset button in case its not working just by turning on power. Do LCDs have some sort of exit mechanism? I mean, do I need to clear its registers before switching off power or something?
    Please find attached schematic.
     
  8. Anirban Raha

    Thread Starter Member

    Dec 4, 2013
    70
    0
    Yes. Without the pull ups, the LCD displays nothing(blank). This is happening after adding the pull ups.
     
  9. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    Put a 0.1uF ceramic capacitor across Vcc and GND right at the LCD module.
     
  10. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    The person who wrote that code does not understand binary.

    Lcd8_Port( ) and Lcd4_Port( ) are trash.
     
  11. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    Here's the solution. I have used them sometimes, and of course, random not-functioning at startup cant be accepted for professional circuit at all.

    Its simple. Power up the LCD through port IO. These LCDs dont like slowly rising supply voltage.
    After that, wait some time.

    Also add at least 20% to the delay time from the datasheet.

    On the internet there are some shortened initializations, which are incorrect, and may not work for 4 bit at all, or not on all displays. The correct method is complicated and lengthy.

    You can find info here: http://elm-chan.org/

    You can also use them at 3 volts, just the LCD bias needs to be slightly higher than that, and the delays must be much longer.
     
  12. Art

    Distinguished Member

    Sep 10, 2007
    785
    61
    Lol It could be a problem, but tjen it shouldn't be solved by reset.
    They are such trash it might not work if the micro was slowed down.
     
  13. Art

    Distinguished Member

    Sep 10, 2007
    785
    61
    Oh my, it might be that the micro is started in beat with the LCD cpu to get the bits of the port all set in time, or not.
     
  14. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    One problem could be that E is pulled up. During RESET, E will be '1' and the LCD could take transitions on the port as commands - putting it into some unknown state.. Relocate E to a push-pull output and add a pull-down.

    Hitachi calls out a 15ms delay after Vcc rises to 4.5V (40ms after 2.7V). You don't need to power it off a port.

    It's so that the data bus lines can go to arbitrary port pins. Usually not necessary.

    EDIT for TS: Here's the Hitachi 44780 datasheet that will answer questions about delays, inits etc.
     
    Last edited: Feb 8, 2015
  15. Art

    Distinguished Member

    Sep 10, 2007
    785
    61
    I forgot you have to pull a pin to get it to read the port.
    Otherwise I would have pointed out what happens if the LCD reads while the micro is part way through writing the port :D

    That not being the case, if you were going to address bits individual it’s still a waste of time & memory
    Code (Text):
    1.  
    2. //LCD 8 Bit Interfacing Functions
    3. void Lcd8_Port(char a)
    4. {
    5. D0 = 0; // or clear the whole port
    6. if(a & 1) {D0 = 1;}
    7.  
    8. bla bla...
    9.  
    10.  
     
    Last edited: Feb 8, 2015
  16. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    Thinking more about delays. The code makes no mention of the uC's oscillator frequency which will affect delays. It also does not calibrate delays to the oscillator freq - it just passes unscaled ints to a counter. If the oscillator is not what the code expects, the delays will be off.

    Note that the commands for Return Home and Clear Display take WAY longer to execute than the others. Hitachi says 1.52ms for Return Home and does not spec a time for Clear Display (but I can tell you, it takes a long time.) Another datasheet from OPTREX I have using the 44780 at the same internal frequency calls out 15.2ms for both. ??? This code does not automatically take these extra times (whatever they are) into account. Even if it did, different displays may run at different internal frequencies.

    Because of the uncertainty, I've always polled the BUSY flag in the 'send byte to LCD' routine just before I need to write the next character and wait there if necessary. An alternate way without the BF would be to set a timer to the time appropriate to the instruction just after doing it then check the timer before the next operation. If its been long enough since the last write, there's no sense in waiting. The WORST option is to have to monkey with LCD instruction-dependent delays in your code flow and have to remember that clearing the display takes longer etc.

    You can also avoid the long clearing process by 1) manually writing 20h (space) to only the visible characters - Clear Display clears the entire character RAM one byte at a time or 2)my favorite, just pad each line to the display width and always write 16 or 20 characters as required to overwrite what's currently on the screen.

    Good luck.
     
    Anirban Raha likes this.
  17. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    +1
    What John says. I poll the busy flag before sending.
    Instead of clearing the display I send 16 spaces to the line I am writing to.
     
  18. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    That might be part of the problem. If you power it off, set all to zero, then power on, you get rid of all possibilities.

    Its the most effective way of dealing with the problem. There are chips with so many small pins- why not use a few now and then?

    [
    Its akward to do it like that. Normally, its done with tables- one entry for the port address, another 2 for setting/resetting mask. If it is just a bit or two, can first write wrong value to buffer then correct it.

    Its hard to use these displays correctly- basically, you need a contrast potentiometer, and a constant voltage, to take care the startup, delays which could be longer depending on temp., and age.
    With the charge pump you need at 3v, a graphical LCD is cheaper, and not riddled with delays so much (basically they are faster than any small MCU software serial port).

     
  19. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    If you compare the LCD current requirements with the current source capabilities of the Atmel part, you'll see that a single pin is going to have problems driving the LCD display at anywhere near Vcc. The other problem is that even if you are lucky enough to get the current (its not guaranteed) the lightly loaded data outputs are likely to present a greater voltage than Vcc provided by the heavily loaded power source pin. The CMOS 44780 won't like that.

    True enough but you'll find that all of that table access will generate more code than the method described. But I am not advocating doing it either of those ways, just pointing out that this particular library takes care of arbitrary pin assignments by bit-flipping to make it more general. Personally, I don't use LCD libraries, preferring my own code.

    As far as using other displays, that's up to the TS. He asked about Hitachi 16x2
     
  20. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    Questionable for me. These LCDs need 1mA or less that's why people like them, can run long time from battery. Thats also the reason for the low clocking frequeny. A potential of o.2v or so through a high-impedance IO structure wont harm CMOS. I doubt its happening, it will sag down the rest of the port, but as I said, these Hitachi LCDs are very conservative in terms of using power.

    Sure its his choice, I just mention that it is hard to get everything right with these. Always powering up correctly one such requirement.

    Sure the tables arent fast, and would generate 100s of program words. But lately there's so much FLASH available. Its better if you need to change the source again and again, just define one set of const arrays, than to change the actual code. It can automatically configure Tristate too.

    At 3 volts these Hitachi modules arent bad, little current is needed.

    I have often programmed eco modes, which flash LED light or pheripherals to some complicate chopping algorithm, so you could use the battery much longer.
     
Loading...