Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Interfacing PIC18F4550 and a 16x1 Character LCD

Status
Not open for further replies.

M4X

Newbie level 3
Joined
May 29, 2011
Messages
4
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Location
localhost
Activity points
1,320
Hello everybody :smile:

Being a beginner in the [wanderful ^^] world of MCUs, I've been doing some simulations in ISIS with mikroC code as application to various tutorials found on the net before buying any real kit/programmer...
Lately I was interested in interfacing PICs and LCDs without using mikroC's LCD_Library, it worked perfectly [after many tries, of course :wink: ] when I used a PIC16F84A and the LM020L [both found in ISIS's library] to display some "Hello world" stuff...
So I tried to do something more interesting with a PIC18F4550: reading 4 analog and 16 digital inputs, and then displaying the values on the LCD

But things didn't work at all, from the beginning, when I first tried to display some text on the LCD: I'm not sure, but I think it's something related to the PIC18F4550 features that I don't nedd to use [comparators and other stuff that I don't understand, yet...], or maybe it is some wrong mikroC project config, or even a clock/oscillator issue since ISIS tells me that the LCD "received command whilst busy"

Here are the mikroC PRO for PIC 4.60 and Proteus ISIS 7.7 projects: View attachment PIC18F4550_LCD.zip

And for those who don't want to download it :wink: :
ISIS Schematic:
**broken link removed**

mikroC Code:
prog.c
Code:
#include "lcd_interfacing.h"

void main()
{
    //OSCCON  = 0x72;
    //T1CON   = 0x00;
    CMCON   = 0x07; // deactivate comparators
    ADCON1  = 0x0B; // RA0-RA3: Analog, the rest: Digital, voltage references: Vss and Vdd
    ADCON2 &= 0x80; // Adc_read() will return a right-justified binary value
    
    // Input
    TRISA |= 0x0F;  // Analog: RA0-RA3: In
    TRISB = 0x0F;   // Digital buttons: RB4-RB7: Out, RB0-RB3: In
    // Output
    TRISC &= 0x00;  // LCD Command: RC0-RC2: Out
    TRISD = 0x00;   // LCD Data: RD0-RD7: Out [some functions, like LCD_Wait_BF()
                    // might need RD0-RD7: In, but they restore it Out when finished]
    // Misc
    //TRISE |= 0x07;   // we could use it later, I don't know...
    
    LCD_Init_LCD();
}

lcd_interfacing.h
Code:
sbit LCD_RS at RC0_bit;
sbit LCD_RW at RC1_bit;
sbit LCD_EN at RC2_bit;
/*
sbit LCD_D0 at RD0_bit;
sbit LCD_D1 at RD1_bit;
sbit LCD_D2 at RD2_bit;
sbit LCD_D3 at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;
*/
sbit LCD_BF at RD7_bit;

#define LCD_Data PORTD
#define LCD_Data_Direction TRISD

void LCD_Wait_BF ();
void LCD_Init_LCD ();
void LCD_Write_Command (unsigned char cmd);
void LCD_Write_Data (unsigned char dat);
void LCD_Write_String (unsigned char* str);

lcd_interfacing.c
Code:
#include "lcd_interfacing.h"

void LCD_Wait_BF ()
{
    TRISD = 0xFF;
    LCD_RS = 0;
    LCD_RW = 1;
    LCD_EN = 1;
    while (LCD_BF)
    {
        LCD_EN = 0;
        LCD_EN = 1;
    }
    LCD_EN = 0;
    TRISD = 0x00;
}

void LCD_Init_LCD ()
{
    LCD_Write_Command(0x34); // 8-bit interface, 1 line, 5x10-dot font
    LCD_Write_Command(0x0E); // Display ON, Cursor ON, Blink OFF
    //LCD_Write_Command(0x01); // clear dispalay
    LCD_Write_Command(0x06); // Entry Mode: I/D: 1 [increment], S: 0 [don't accompany display shift]
    LCD_Write_Command(0x80); // set DDRAM adress
    
    LCD_Write_Data('M');
}

void LCD_Write_Command (unsigned char cmd)
{
    LCD_Data = cmd;
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_EN = 1;
    LCD_EN = 0;
    
    LCD_Wait_BF();
}

void LCD_Write_Data (unsigned char dat)
{
    LCD_Data = dat;
    LCD_RS = 1;
    LCD_RW = 0;
    LCD_EN = 1;
    LCD_EN = 0;
    
    LCD_Wait_BF();
}

void LCD_Write_String(unsigned char* str)
{
    while (str[0] != '\0')
    {
        LCD_Write_Data(str[0]);
        str++;
    }
}

Thanks in advance for your help.
M4X.​
 

LCD is not fast enough to respond to MCU instructions. There must be delays to give LCD ample time to respond. In your program, I could not see any delay. Check datasheet of LCD you are using. For example give at least 5ms delay for LCD control commands such as cursor on off. Give at least 20ms delay for writing text on LCD. Mikroc manual provides good example in peripheral library section of LCD.
 
  • Like
Reactions: M4X

    M4X

    Points: 2
    Helpful Answer Positive Rating
LCD is not fast enough to respond to MCU instructions. There must be delays to give LCD ample time to respond. In your program, I could not see any delay. Check datasheet of LCD you are using. For example give at least 5ms delay for LCD control commands such as cursor on off. Give at least 20ms delay for writing text on LCD. Mikroc manual provides good example in peripheral library section of LCD.
Thanks for your reply :smile:
I don't understand where exactly I should put the delay you're talking about ?

Also, I think the LCD_Wait_BF() function does this job, no ?
Code:
void LCD_Wait_BF ()
{
    TRISD = 0xFF; // set portD as input [for reading the BF]
    LCD_RS = 0; // selecting Command Register
    LCD_RW = 1; // it's a Read operation
    LCD_EN = 1; // the "enable signal"
    while (LCD_BF) // reading the BF
    {
        LCD_EN = 0;
        LCD_EN = 1;
    }
    LCD_EN = 0;
    TRISD = 0x00; // "restoring" portD as output
}
I've coded that as shown in this tutorial [well, I wasn't exactly using the same components as him, but still, I tried to "accomodate" :wink: ], and it seems quite logic, I guess... It's the same code I used with a PIC16F84A @ 8MHz too and it worked perfectly.
 

In your code, change the statement
#define LCD_Data PORTD
with
#define LCD_Data LATD

and check the results if it works or not.

---------- Post added at 19:13 ---------- Previous post was at 19:10 ----------

Upload your proteus project along with source code. Let me troubleshoot it.

---------- Post added at 19:14 ---------- Previous post was at 19:13 ----------

Upload your proteus project along with source code. Let me troubleshoot it.
 

In your code, change the statement
#define LCD_Data PORTD
with
#define LCD_Data LATD

and check the results if it works or not.

---------- Post added at 19:13 ---------- Previous post was at 19:10 ----------

Upload your proteus project along with source code. Let me troubleshoot it.

---------- Post added at 19:14 ---------- Previous post was at 19:13 ----------

Upload your proteus project along with source code. Let me troubleshoot it.
LATX or PORTX seems to be the same thing in mikroC, so this this appears not to be the problem...

But, when I've changed the LCD_Wait_BF() like this:
Code:
void LCD_Wait_BF ()
{
    LCD_EN = 0;
    LCD_Data_Direction = 0xFF;
    LCD_RS = 0;
    LCD_RW = 1;
    LCD_EN = 1;
    Delay_ms(2);  // wait for command to be interpreted/executed
    while (LCD_BF)
    {
        LCD_EN = 0;
        LCD_EN = 1;
        Delay_ms(2);  // wait for command to be interpreted/executed
    }
    LCD_EN = 0;
    LCD_Data_Direction = 0x00;
}
... it worked !!
yes2.gif

I don't know if it's the "right thing to do", but it seems to get the job done...
What do you think ?
Why did it work ?
Does the LCD needd a delay \[{ \theta }_{ 1 }\] for "interprating" a command [just after the LCD_EN=1], and an other delay \[{ \theta }_{ 2 }\] for "executing" the command [just after the LCD_EN=0] ?


PS: I've already uploaded the projects in a zip in the first post: View attachment PIC18F4550_LCD.zip :wink:
 

Yes, actually there are several different delays involved with interfacing a Hitachi LM020L and same is true with every LCD or GLCD. Whenever you begin the job of designing a new circuit, you should always collect the relevant datasheets for the components you have incorporated in your design. This procedure reduce stress and aspirin intake during the design process.

Here's the LM020L datasheet, it's an old scanned version, you could of found an equivalent LCD based on the HD44780 chipset, most of this style LCD are by the way:

Hitachi LM020L

Check it out it's amazing the handy information included in a component datasheet.

What's even more amazing is people attempting to actually design a viable circuit without even a glimpse of the components' datasheets used in their design.

Hope the info helps in your endeavors.
 
  • Like
Reactions: M4X

    M4X

    Points: 2
    Helpful Answer Positive Rating
As i mentioned in my previous post
For example give at least 5ms delay for LCD control commands such as cursor on off. Give at least 20ms delay for writing text on LCD.
You need delays for control commands.
 

Yes, actually there are several different delays involved with interfacing a Hitachi LM020L and same is true with every LCD or GLCD. Whenever you begin the job of designing a new circuit, you should always collect the relevant datasheets for the components you have incorporated in your design. This procedure reduce stress and aspirin intake during the design process.

Here's the LM020L datasheet, it's an old scanned version, you could of found an equivalent LCD based on the HD44780 chipset, most of this style LCD are by the way:

Hitachi LM020L

Check it out it's amazing the handy information included in a component datasheet.

What's even more amazing is people attempting to actually design a viable circuit without even a glimpse of the components' datasheets used in their design.

Hope the info helps in your endeavors.
Interesting indeed [even though some technical details increase aspirin intake for a beginner like me
blush.gif
], I found it quite similar to the View attachment HD44780 datasheet.pdf [but if you look closer LM020_page16/HD44780_page24, the LM020L is a little bit slower]
Thanks :smile:

As i mentioned in my previous post
You need delays for control commands.
As mentioned by the datasheets LM020_page16/HD44780_page24, the maximum execution time for any command can't be more than 2ms and reading BF doesn't need more than 1µs, so, if I've understood, it means that I need a 1-2µs delay after each LCD_EN = 1, and a 2ms delay after each LCD_EN = 0

Am I right ?

PS: I've studied a little bit of microprocessor architecture, and, just to help me understand things better, are the following statements equivalent ?
LCD_EN = 1 <=> "fetch" and "decode"
LCD_EN = 0 <=> "execute"
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top