LCD shows strange behavior upon micro-controller reset

lcdpicxc8

I have written a code for the 'PIC18F4550' micro-controller (20MHz xtal) which shows "Speed = xxx RPMs" on an HD44780 LCD in 4-bit mode, where the xxx is the value contained in the variable called 'input'. The compiler used is xc8 and I'm programming using the PICKIT3. I have run the simulation in proteus and it all goes good until I reset the PIC using the MCLR pin. It really shows an anomalous output where I can't seem to understand which part is going wrong. I've also implemented this on hardware and it behaves exactly like it does in the simulation. I read something similar to this problem and people were suggesting that the enable pin must be messing up at reset but I don't see how that might be happening here so please try to help guys. I'm out of ideas here.

Behavior upon power up and reset

#include <p18F4550.h>
#include <stdio.h>
#include <stdlib.h>
#include <delays.h>
#include <string.h>
#define _XTAL_FREQ 20000000
#define LCD_out PORTD
#define rs PORTCbits.RC0
#define rw PORTCbits.RC1
#define en PORTCbits.RC2


//---------------------//

void lcd_cmd(unsigned char a);      //for LCD commands
void lcd_data(unsigned char b);     //for LCD data
void lcd_reset(void);               //to initialize 4-bit mode
void lcd_init(void);                //primary initialization instructions
void string_display(char *p);       //to display character strings/arrays
void shift_right(int a);            //right cursor shift
void shift_left(int b);             //left cursor shift
void delay_10ms(int t);             //delay in multiples of 10ms
void fragment (int x);              //fragments,processes & displays int data

//.....................//

void main(void)

{
    TRISC=0;
    TRISD=0;
    int input=0;
    char text1[] = "Speed = ";
    char text2[] = "RPMs ";

    lcd_init();
    string_display(text1);
    shift_right(4);

    string_display(text2);
    shift_left(9);

    while(1)
    {
        input++;
        fragment(input);
    }
}


void fragment (int x)
{
    int number[3];
    char final_num[4];
    int flag = 0;

    number[2]= (x/1)%10;
    number[1]= (x/10)%10;
    number[0]= (x/100)%10;

    if(number[0]==0)
        flag++;
    if(number[1]==0 && number[0]==0)
        flag++;

    int temp=0;
    for(int i=flag;i<=2;i++)
    {
        final_num[temp]='0' + number[i];
        temp++;
    }

    if(x<1000)
    {
        string_display(final_num);
        shift_left(temp);
    }

    else
    {
        char nul[]="NUL";
        string_display(nul);
        shift_left(3);
    }

}

void delay_10ms(int t)
{
    for(int i=0; i<t;i++)
    {
        __delay_ms(10);
    }
}

void shift_right(int a)
{
    for(int i=0; i<a;i++)
    {
        lcd_cmd(0x14);
    }
}

void shift_left(int b)
{
    for(int i=0; i<b;i++)
    {
        lcd_cmd(0x10);
    }

}

void string_display(char *p)
{
    while(*p!=0)
    {
        lcd_data(*p);
        p++;
    }
}

void lcd_init(void)
{
    TRISC=0;
    TRISD=0;
    en = 0;
    rw = 0;

    LCD_out = 0;
    lcd_reset();
    lcd_cmd(0x28);
    lcd_cmd(0x01);
    lcd_cmd(0x0C);
}

void lcd_reset(void)
{
    __delay_ms(20);
    LCD_out=0x03;
    en=1;
    __delay_ms(5);
    en=0;

    __delay_ms(10);
    LCD_out=0x03;
    en=1;
    __delay_ms(5);
    en=0;

    __delay_ms(1);
    LCD_out=0x03;
    en=1;
    __delay_ms(5);
    en=0;

    __delay_ms(1);
    LCD_out=0x02;
    en=1;
    __delay_ms(5);
    en=0;
    __delay_ms(5);
}

void lcd_cmd(unsigned char cmd)
{
    rs=0;
    unsigned char temp;
    temp=cmd;

    //sends the upper four bits
    temp=temp>>4;
    LCD_out=temp;
    en=1;
    __delay_ms(1);
    en=0;
    __delay_ms(1);

    //sends the lower 4 bits
    temp=cmd;
    LCD_out=temp;
    en=1;
    __delay_ms(1);
    en=0;
    __delay_ms(1);
}

void lcd_data(unsigned char data)
{
    rs=1;
    unsigned char temp;
    temp=data;

    //sends the upper four bits
    temp=temp>>4;
    LCD_out=temp;
    en=1;
    __delay_ms(1);
    en=0;
    __delay_ms(1);

    //sends the lower 4 bits
    temp=data;
    LCD_out=temp;
    en=1;
    __delay_ms(1);
    en=0;
    __delay_ms(1);
}

Best Answer

I will start with mistakes on the circuit:

  • The oscillator is not connected properly.
  • I think you should not limit the LCD current with resistor and capacitor. (R2,C1)
  • In Proteus, you do not have to simulate 5V, since the PIC pins are connected to Vcc(5v). You can replace all connection for 5V to Vcc, it is same.
  • Make sure you are supplying 7805 with enough Vin. (check datasheet)

Mistakes in the code:

If you are using XC8 compiler as you stated, you should not include all these:
If you are totally sure that you want to use the specified header, then include it.

#include <p18F4550.h>
#include <stdio.h>
#include <stdlib.h>
#include <delays.h>
#include <string.h>

Instead you should include only:

#include <xc8.h>

It will include all headers needed.

I also can not see the configuration bits in the code. Include them too.

It might be all this shifting left and right which makes your code not work properly. Instead of shifting right or left, I would print the whole screen at once. Example:

while(1)
{
    lcd_reset();

    input++;
    fragment(input);

    string_display(text1);
    char_display(number[0]);
    char_display(number[1]);
    char_display(number[2]);
    string_display(text2);
}