[SOLVED] Garbage data on 4 bit 16x2 lcd using MG82F6D17 mcu

Thread Starter

funguamon

Joined Apr 19, 2024
6
I have a 16x2 lcd connected to the MG82F6D17 mcu with breadboard wires. The mcu has 0.1nf bypass cap. Here is my code

Code:
#include ".\include\REG_MG82F6D17.H"
#include ".\include\Type.h"
#include ".\include\API_Macro_MG82F6D17.H"
#include ".\include\API_Uart_BRGRL_MG82F6D17.H"
#include <Intrins.h>
sfr LCD_Port=0x90;        /* P1 port as data port */
#define rs P33            /* Register select pin */
#define en P34            /* Enable pin */
#define MCU_SYSCLK        12000000
#define MCU_CPUCLK        (MCU_SYSCLK)


void DelayXus(u8 xUs)
{
    while(xUs!=0)
    {
#if (MCU_CPUCLK>=11059200)
        _nop_();
#endif
#if (MCU_CPUCLK>=14745600)
        _nop_();
        _nop_();
        _nop_();
        _nop_();
#endif
#if (MCU_CPUCLK>=16000000)
        _nop_();
#endif

#if (MCU_CPUCLK>=22118400)
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
#endif
#if (MCU_CPUCLK>=24000000)
        _nop_();
        _nop_();
#endif        
#if (MCU_CPUCLK>=29491200)
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
#endif
#if (MCU_CPUCLK>=32000000)
        _nop_();
        _nop_();
#endif

        xUs--;
    }
}

/*************************************************
Function:         void DelayXms(u16 xMs)
Description:    dealy£¬unit:ms
Input:             u16 xMs -> *1ms  (1~65535)
Output:     
*************************************************/
void DelayXms(u16 xMs)
{
    while(xMs!=0)
    {
        CLRWDT();
        DelayXus(200);
        DelayXus(200);
        DelayXus(200);
        DelayXus(200);
        DelayXus(200);
        xMs--;
        
    }
}



void LCD_Command (char cmnd)    /* LCD16x2 command funtion */
{
    LCD_Port =cmnd;
    rs=0;            /* Command reg. */

    en=1; 
    DelayXus(100);
    en=0;
    DelayXus(1000);
}

void LCD_Char (char char_data)  /* LCD data write function */
{
    LCD_Port = char_data;
    rs=1;              /*Data reg.*/
    en=1;  
    DelayXus(100);
    en=0;
    DelayXus(1000);

}

void LCD_String (char *str)    /* Send string to LCD function */
{
    int i;
    for(i=0;str[i]!=0;i++)  /* Send each char of string till the NULL */
    {
        LCD_Char (str[i]);  /* Call LCD data write */
    }
}

void LCD_String_xy (char row, char pos, char *str)  /* Send string to LCD function */
{
    if (row == 0)
    LCD_Command((pos & 0x0F)|0x80);
    else if (row == 1)
    LCD_Command((pos & 0x0F)|0xC0);
    LCD_String(str);      /* Call LCD string function */
}

void LCD_Init (void)        /* LCD Initialize function */
{
    
    DelayXms(100);        /* LCD Power ON Initialization time >15ms */
    LCD_Command (0x02);    /* 4bit mode */
    LCD_Command (0x28);    /* Initialization of 16X2 LCD in 4bit mode */
    LCD_Command (0x0F);    /* Display ON Cursor OFF */
    LCD_Command (0x06);    /* Auto Increment cursor */
    LCD_Command (0x01);    /* clear display */
    LCD_Command (0x80);    /* cursor at home position */
}

void main()
{ 
    led = 0;
  PORT_SetP1PushPull(BIT0|BIT1|BIT5|BIT6|BIT7);
  PORT_SetP3PushPull(BIT3|BIT4);
    LCD_Init();    
    
    LCD_String("Garbage"); 
    LCD_Command(0xC0);    /* Go to 2nd line*/
    /*LCD_String_xy(1,0,"Hello World");  /*write string on 2nd line*/
    while(1);        
}
delay function was provided by megawin themselves.

The lcd just displays garbage text like " wg" and next line has "V". Port 1 on this mcu only has 5 pins -> P1.0,P1.1,P1.5,P1.6,P1.7, and i have my lcd connected (DB,4DB5,DB6,DB7) to (P1.1,P1.5,P1.6,P1.7). using P1.0~P1.6 shows nothing. Where exactly could the problem be?
 

geekoftheweek

Joined Oct 6, 2013
1,240
If I am understanding it right you are trying to use four bit mode, but only sending half the byte. To use four bit mode it takes two writes per enable cycle. One for the first four bits, and one for the second four bits.

Also in the initialization "LCD_Command (0x02);" looks out of place or not right. I don't have time to look up the sequence at the moment, but usually the first few bytes have other timing requirements and repeat the same byte several times.
 

Thread Starter

funguamon

Joined Apr 19, 2024
6
I changed some things. Here's the data and command write functions
Code:
void LCD_Command (char cmnd)    /* LCD16x2 command funtion */
{
    LCD_Port =((cmnd >> 4)& 0x0F);
    rs=0;            
    en=1; 
    DelayXus(1);
    en=0;
  
    LCD_Port = (cmnd & 0x0F);
    rs=0;            
    en=1; 
    DelayXus(1);
    en=0;



}

void LCD_Char (char char_data)  /* LCD data write function */
{
    LCD_Port = ((char_data >> 4) & 0x0F);
    rs=1;
    en=1;
    DelayXus(1);
    en=0;
    
    LCD_Port =(char_data & 0x0F);
    rs=1;
    en=1;
    DelayXus(1);
    en=0;



}
Still cannot figure out the command sequence. I did this so far with different garbage data now. 1st line has full contrast with
_
-
-
output on random positions and cursor blink

Code:
void LCD_Init (void)        /* LCD Initialize function */
{
    rs=0; en=0; LCD_Port = 0xFF;
    DelayXms(20);        
    LCD_Command(0x30);    
    DelayXms(10);
    LCD_Command(0x30);    
    DelayXms(1);
    LCD_Command(0x30);    
    DelayXms(1);
    LCD_Command(0x20);
    DelayXms(1);
    LCD_Command (0x02);
    
    LCD_Command (0x28);    
    
    LCD_Command (0x0C);    
    
    LCD_Command (0x01);
    
    LCD_Command (0x80);
}
 

Thread Starter

funguamon

Joined Apr 19, 2024
6
Code:
delay(15000);
display(0x30);
delay(4500);
display(0x30);
delay(300);
display(0x30);
delay(650);
lcdcmd(0x38);
delay(50);
lcdcmd(0x0F);
delay(50);
lcdcmd(0x01);
delay(50);
lcdcmd(0x06);
delay(50);
lcdcmd(0x80);
delay(50);
Was this the command sequence and timingu were talking about? @geekoftheweek
 

Thread Starter

funguamon

Joined Apr 19, 2024
6
1713587698631.png


This is the description of port 1. In all the tutorials ive found via google, the mcus they use have 8 pins on the port they use for lcd data communication, and the lcd is wired to the last 4 pins. Mine only has 5 and im using 1,5,6,7. Could this be an issue?
 

MrChips

Joined Oct 2, 2009
30,937
That makes the task difficult but not impossible. It would be more convenient to select four bits that are in a row.
 

trebla

Joined Jun 29, 2019
550
Maybe they avoid some unlucky numbers ;)

In situations like this i use often sructure unions for manipulating different bits.
Union for port bits:
typedef union {
    struct {
        unsigned P1_0                    :1;
        unsigned P1_1                    :1;
        unsigned P1_2                    :1;
        unsigned P1_3                    :1;
        unsigned P1_4                    :1;
        unsigned P1_5                    :1;
        unsigned P1_6                    :1;
        unsigned P1_7                    :1;
    }bit;
    struct {
        unsigned lowbits                 :3;
        unsigned unused                  :2;
        unsigned hibits                  :3;
    }nibs;
    struct {
        unsigned port;
        
    }byte;
} PORTbits_t;
 

Thread Starter

funguamon

Joined Apr 19, 2024
6
Alright I got it. Might be the most horrible inefficient piece of code but it works like a charm for me

Code:
#include ".\include\REG_MG82F6D17.H"
#include ".\include\Type.h"
#include ".\include\API_Macro_MG82F6D17.H"
#include ".\include\API_Uart_BRGRL_MG82F6D17.H"
#include <Intrins.h>
sfr LCD_Port=0x90;        /* P1 port as data port */
#define rs P22            /* Register select pin */
#define en P24            /* Enable pin */
#define MCU_SYSCLK        12000000
#define MCU_CPUCLK        (MCU_SYSCLK)

void DelayXus(u8 xUs)
{
    while(xUs!=0)
    {
#if (MCU_CPUCLK>=11059200)
        _nop_();
#endif
#if (MCU_CPUCLK>=14745600)
        _nop_();
        _nop_();
        _nop_();
        _nop_();
#endif
#if (MCU_CPUCLK>=16000000)
        _nop_();
#endif

#if (MCU_CPUCLK>=22118400)
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
#endif
#if (MCU_CPUCLK>=24000000)
        _nop_();
        _nop_();
#endif        
#if (MCU_CPUCLK>=29491200)
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
#endif
#if (MCU_CPUCLK>=32000000)
        _nop_();
        _nop_();
#endif

        xUs--;
    }
}

/*************************************************
Function:         void DelayXms(u16 xMs)
Description:    dealy£¬unit:ms
Input:             u16 xMs -> *1ms  (1~65535)
Output:     
*************************************************/
void DelayXms(u16 xMs)
{
    while(xMs!=0)
    {
        CLRWDT();
        DelayXus(200);
        DelayXus(200);
        DelayXus(200);
        DelayXus(200);
        DelayXus(200);
        xMs--;
        
    }
}




void pulsen(){
   en = 1;
     DelayXus(5);
     en = 0;
}

void writeBits(unsigned char val){
    if(val & 0x08)
        P17 = 1;
    else
        P17 = 0;
    if(val & 0x04)
        P16 = 1;
    else
        P16 = 0;
    if(val & 0x02)
        P15 = 1;
    else
        P15 = 0;
    if(val & 0x01)
        P11 = 1;
    else
        P11 = 0;
  pulsen();
}

void LCDreset(){
    P17=0;
    P16=0;
    P15=1;
    P11=1;
    
    pulsen();
    DelayXms(10);
    pulsen();
    DelayXms(10);
    pulsen();
    DelayXms(10);
    
    P17=0;
    P16=0;
    P15=1;
    P11=0;
    pulsen();
    DelayXms(10);

}

void LCD_Command (unsigned char cmnd)    /* LCD16x2 command funtion */
{
    rs=0; en=0;
    writeBits(cmnd >> 4);
    writeBits(cmnd);
    DelayXms(5);
}

void LCD_Char (unsigned char char_data)  /* LCD data write function */
{
     rs=1; en=0;
     writeBits( char_data >> 4);
     writeBits(char_data );
     DelayXms(5);

}
void LCD_Init (void)        /* LCD Initialize function */
{
    LCDreset();
    LCD_Command (0x28); 
    LCD_Command (0x0F);        
    LCD_Command (0x01);    
    LCD_Command (0x80);   
}

void main()
{ 

  PORT_SetP1PushPull(BIT1|BIT5|BIT6|BIT7);
  PORT_SetP2PushPull(BIT2|BIT4);
  LCD_Init();    
    LCD_Char('H'); 
    LCD_Char('e'); 
    LCD_Char('l'); 
    LCD_Char('l'); 
    LCD_Char('o'); 
  LCD_Command(0xC0);    /* Go to 2nd line*/
    LCD_Char('W'); 
    LCD_Char('o'); 
    LCD_Char('r'); 
    LCD_Char('l'); 
    LCD_Char('d'); 
    while(1);        
}
got half of it from https://github.com/sriharshaq/8051-Library/tree/master/LCD
Huge thanks to all of you members who took time to reply and help me make my first 8051 project come to fruition! Terrible choice of mcu for a first project but that's what I could get my hands on. Have a good day!2024-04-20-19-51-23-329.jpg
 

geekoftheweek

Joined Oct 6, 2013
1,240
Alright I got it. Might be the most horrible inefficient piece of code but it works like a charm for me
I know my first LCD project had me questioning my sanity for a while... I even went the eight bit route to make life easier. Information online has improved a lot since then.

I am not an expert by any means, but your code looks pretty good in my eyes. We all had to start somewhere...
 

MrChips

Joined Oct 2, 2009
30,937
Very inefficient coding but glad that you got it working.
Now work on writing efficient programming. Instead of repeated calls to LCD_Char( ) try creating LCD_Text( ) function.
Have a look at my LCD_txt( ) function. It takes one line of coding.
 

geekoftheweek

Joined Oct 6, 2013
1,240
Not to be rude, but doesn't LCD_Text() basically do the exact same thing as repeated calls to LCD_Char()? I question it's efficiency since it would actually take more instruction cycles to increment the pointer, check for null character, and call the function, but do agree it would clean up some code.

Edit:
Maybe I am looking at efficiency in a different context...
 
Top