1
\$\begingroup\$

I am learning interfacing of Atmega 16a with 16X2 LCD. I have a written a header file for routines which will used frequently and every time I want to interface with LCD using Atmega 16a I use this header file.

here is my LCD header file:

#include<stdlib.h>
#include<avr/io.h>
#include<util/delay.h>
int cx=1;
int cy=1;
void LCD_Send(unsigned char c,unsigned char DC)
{

    if(DC==0)
    {
        PORTC=0x0F & (c>>4);
        PORTC=PORTC|(1<<5);
        _delay_ms(1);
        PORTC=PORTC & (~(1<<5));
        _delay_ms(1);
        PORTC=0x0F & (c);
        PORTC=PORTC | (1<<5);
        _delay_ms(1);
        PORTC=PORTC & (~(1<<5));
        _delay_ms(1);
    }
    else if(DC==1)
    {
        PORTC=0x0F & (c>>4);
        PORTC=PORTC | (1<<7);
        PORTC=PORTC|(1<<5);
        _delay_ms(1);
        PORTC=PORTC & (~(1<<5));
        _delay_ms(1);
        PORTC=0x0F & (c);
        PORTC=PORTC | (1<<7);
        PORTC=PORTC | (1<<5);
        _delay_ms(1);
        PORTC=PORTC & (~(1<<5));
        _delay_ms(1);
    }
    return ;
}
void LCD_init(void)
{
    DDRC=0b11101111;
    LCD_Send(0x01,0);
    LCD_Send(0x0F,0);
    LCD_Send(0x28,0);
    cx=1;cy=1;
    return ;
}
void LCD_Send_String(char* s)
{
    for(int i=0;s[i]!='\0';i++)
    {
        LCD_Send(s[i],1);
        if(cx==16)
        {
            cx=1;cy++;
            LCD_Send(0xC0,0);
        }
        else
        cx++;
    }
    return ;
}
void LCD_GotoXY(unsigned int x,unsigned int y)
{
    if(y==1)
    {
        char addr=0x80;
        addr=addr+(x-1);
        LCD_Send(addr,0);
    }
    else if(y==2)
    {
        char addr=0xC0;
        addr=addr+(x-1);
        LCD_Send(addr,0);
    }    
    cx=x; cy=y;
    return ;
}
void LCD_Print(int data,unsigned int x,unsigned int y)
{
    char string[10];
    LCD_GotoXY(x,y);
    itoa(data,string,10);
    LCD_Send_String(string);
    return ;
}

Here RS,R/W and E are PC7,PC6 and PC5 respectively, DB4,DB5,DB6,DB7 are PC0,PC1,PC2,PC3 respectively. I am using 4 bit mode for input.

here is my main.c file (the code which will be run on the microprocessor):

#include"lcd.h"
int main(void)
{
    LCD_init();
    char s[20]="1234567890123456789";
    LCD_Send_String(s);
    return 0;
}

When I flash the memory with the HEX file then reset the LCD is displaying fine

figure1

Then when I reset later it displays random variables(infact I can see that the second line doesnt change at all, it means that the screen is not cleared but a command was written to LCD_init() to clear screen)

figure2

I am pretty sure that nothing is wrong with board and the connections because it works with other header files, I am pretty sure that it is a fault in my code. I would really thankful if anyone help me fixing this code If i reset again it displays the correct sequence as in first image

\$\endgroup\$
7
  • \$\begingroup\$ What and how are you resetting it? \$\endgroup\$ Commented Aug 29, 2014 at 12:33
  • \$\begingroup\$ by reset i mean i have cold booted. \$\endgroup\$
    – Aditya
    Commented Aug 29, 2014 at 12:39
  • \$\begingroup\$ Once i get this werid output and then i reset again i can see the screen clear and see the correct sequence appear again. \$\endgroup\$
    – Aditya
    Commented Aug 29, 2014 at 12:43
  • \$\begingroup\$ so you are saying that if you remove and reconnect power it does not work but if you only reset the micro it does work? \$\endgroup\$ Commented Aug 29, 2014 at 12:45
  • 1
    \$\begingroup\$ try to add a 100ms delay as first thing in your code and see if it works \$\endgroup\$ Commented Aug 29, 2014 at 12:49

3 Answers 3

3
\$\begingroup\$

Your problem is that the display keeps its state during MCU reset. When cold-booting, the initial data mode is 8-bit which you immediately switch to 4-bit which reads data with a pair of EN pulses.

When you reset the MCU, you do not know whether even or odd number of EN pulses were sent. So you have to somhow reset the display even if it does not have reset pin.

This can be done by sending 0x33 0x33 (in 8-bit mode it will mean 4-times switch to 8-bit, in 4-bit mode it will mean once or twice switch to 8-bit). Then you can be sure that you always start from the same state.

Then proceed with regular 0x32 (or 4-bit 0x02 if you have single 4-bit write function), 0x28 to get into 4-bit 2-line mode.

\$\endgroup\$
5
  • \$\begingroup\$ Do u mean to write LCD_Send(0x33,0) twice before LCD_Send(0x01,0)? \$\endgroup\$
    – Aditya
    Commented Aug 29, 2014 at 13:35
  • \$\begingroup\$ As I read the HD44780 datasheet (p. 46) you must send 0x3? (the ? bits do not matter) 3 times, then send 0x2?, and after that you can start sending 8-bits command as two nibbles. This is equivalent to sending 0x33 0x32 as nibbles. \$\endgroup\$ Commented Aug 29, 2014 at 13:46
  • \$\begingroup\$ @WoutervanOoijen Yes, i just wanted to split two things (reverting to 8-bit mode and setting 4-bit mode) into two paragraphs of test. \$\endgroup\$
    – venny
    Commented Aug 29, 2014 at 13:50
  • \$\begingroup\$ @Aditya As others have stated, you also have to add some delay: _delay_ms(100);LCD_Send(0x33,0);LCD_Send(0x32,0);LCD_Send(0x28,0);LCD_Send(0x0f,0);LCD_Send(0x01,0);_delay_ms(5);LCD_Send(0x06,0);. The 0x33 is required only only once when it is followed by 0x32. \$\endgroup\$
    – venny
    Commented Aug 29, 2014 at 13:58
  • \$\begingroup\$ As I interpret what you wrote you send the 0x3 nibble 5 times, while the datasheet says 3 times. Maybe that does not matter. Anyway, @Anditya: this is for sure your problem. And do read the datasheet, there are some extra long waits required in this initialization. \$\endgroup\$ Commented Aug 29, 2014 at 13:59
1
\$\begingroup\$

LCDs tend to do this if the data stream becomes desynchronized somehow, for example by plugging it in while data transfer is in progress or by resetting either the screen or microcontroller but not both.

I notice from your code that there is no startup delay. LCDs often require a short period of time to "boot up" before you can start sending data. Add a small delay to the start of your code. Check the LCD datasheet for how much.

\$\endgroup\$
1
  • \$\begingroup\$ This is a very good point. ESD zaps can often desync these things so for commercial products (which have to survive ESD injection for complicane) it is a good idea to periodically reinitialize these LCDs. \$\endgroup\$
    – Will
    Commented Aug 29, 2014 at 12:46
0
\$\begingroup\$

Check the datasheet for the LCD. Often you have to wait a set time after power up before sending the init sequence. Perhaps your problem is this:

When you're programming the device it has already been powered on for a while so your init sequence works. When you cold boot it there is no delay so the LCD isn't ready for the init sequence yet.

Also please post a link to the datasheet

\$\endgroup\$
4
  • \$\begingroup\$ itron.com.cn/PDF_file/JHD162A%20SERIES.pdf this the link to the LCD i used \$\endgroup\$
    – Aditya
    Commented Aug 29, 2014 at 12:38
  • \$\begingroup\$ if i reset it second time it shows correct result i dont understand how the explanation u gave accounts for this. \$\endgroup\$
    – Aditya
    Commented Aug 29, 2014 at 12:44
  • \$\begingroup\$ Probably it still has enough power left to be ready for your init sequence. Try waiting longer before the second restart. The datasheet isn't very clear but it says that the controller is equivalent to a samsung part: lcd-module.de/eng/pdf/zubehoer/ks0066.pdf The samsung part says it needs a 30ms delay at start up. \$\endgroup\$
    – Will
    Commented Aug 29, 2014 at 12:45
  • \$\begingroup\$ i have put the delay but the problem persists \$\endgroup\$
    – Aditya
    Commented Aug 29, 2014 at 12:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.