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.

[SOLVED] LCD 16x2 4 bit interfacing problem

Status
Not open for further replies.

Ranbeer Singh

Full Member level 5
Full Member level 5
Joined
Jul 30, 2015
Messages
259
Helped
22
Reputation
44
Reaction score
22
Trophy points
1,298
Location
Faridabad India
Activity points
3,266
Hello All,

I am unable to send the 4 bit data to Pic18f2520 PORTC upper nibbles. Actually i do'not have any idea to send 4 bit data to 8 bit port. If i work with LCD library, It works fine...but i have manufactured my PCB's. So i am unable to change pins and gate it's benefit.

Pin description : -

EN = RC3
RS = RC2
R/W = GND
PORTC upper nibble = data out​

My code are here

Code:
#include <p18f2520.h>

#define RS_PIN   PORTCbits.RC2   /* PORT for RS */
#define E_PIN    PORTCbits.RC3   /* PORT for E  */

//--------------------------------------------------------------------------
void LCD_Init(void);
void Str_LCD( const rom char *buffer);
void Chr_LCD(char data);
void Clear_LCD(void);
void Move_Corsor( char Line, char Pos);
//--------------------------------------------------------------------------

void Start_Display(void);
void Time_10ms(void);

void main()
{
	TRISA=0xFF;
	TRISC=0x00;
	PORTC=0x00;
	TRISB=0x01;
	PORTB=0x00;	
	T0CON=0x06;
	LCD_Init();
	while(1)
	{
		Start_Display();
	}	
}

void Start_Display()
{
	Str_LCD("SPEED- ");
	Str_LCD("0000");
	Str_LCD(" RPM");
	Move_Corsor(2,0);
	Str_LCD("Current- ");
	Str_LCD("2.2");
	Str_LCD(" A");
}

//---------------------------------------------------------------------------------------
void LCD_Init()
{
	RS_PIN=0;   		   //LCD instructions (RS) pin no. 4
	Chr_LCD(0x28);		   //LCD clear	   
	Chr_LCD(0x01);		   //LCD 4 bit, 2line, 5x7
	Chr_LCD(0x0C);		   //LCD diplay-on cursor not blinking
	Chr_LCD(0x80);		   //LCD cursor Pos. begain
	RS_PIN=1;  			   //LCD Data (RS)
}
	
void Str_LCD( const rom char *buffer)
{
     while(*buffer)                 // Write data to LCD up to null
        {
             Chr_LCD(*buffer); 		// Write character to LCD
             buffer++;              // Increment buffer
        }
        return;
}

void Chr_LCD(char data)
{
	TRISC &= 0x0F;
	PORTC &= 0x0F;
	PORTC |= data&0xF0;
	Time_10ms();
	Time_10ms();
	Time_10ms();
	E_PIN=1;
	Time_10ms();
	Time_10ms();
	Time_10ms();
	E_PIN=0;

    PORTC &= 0x0F;
    PORTC |= ((data<<4)&0xF0);
	Time_10ms();
	Time_10ms();
	Time_10ms();
	E_PIN=1;
	Time_10ms();
	Time_10ms();
	Time_10ms();
	E_PIN=0;

	TRISC |= 0xF0;
}
void Clear_LCD(void)
{
	RS_PIN=0;
	Chr_LCD(0x01);
	Chr_LCD(0x80);
	RS_PIN=1;
}
void Move_Corsor( char Line, char Pos)
{
	RS_PIN=0;
	if(Line==1)Chr_LCD(0x80);
	if(Line==2)Chr_LCD(0xC0);
	while(Pos!=0)
	{
		Chr_LCD(0x14);
		Pos--;
	}
	RS_PIN=1;
}
//---------------------------------------------------------------------------------------

void Time_10ms()
{
	TMR0H=0xFE;
	TMR0L=0x7A;
 	T0CONbits.TMR0ON=1;
	while(INTCONbits.TMR0IF==0);
	T0CONbits.TMR0ON=0;
	INTCONbits.TMR0IF=0;
}

Please help
 

void Lcd_Write_Char(char a)
{
char temp,y;
temp = a&0x0F;
y = a&0xF0;
RS = 1; // => RS = 1
Lcd_Port(y>>4); //Data transfer
EN = 1;
__delay_us(40);
EN = 0;
Lcd_Port(temp);
EN = 1;
__delay_us(40);
EN = 0;
}

Thank you for your reply.

I want to know how is it working? I mean you are shifting data to upper nibble...but how did you?

- - - Updated - - -

Please..... Can you explain me?
 

hi, eventually
check datasheet of microcontroller for each pin you use with LCD. It happened to me that some pins did not have internal pull up rezistor so i had to add them on the back of pcb . Code was ok .
Just to be shore is not hardware problem
 

hi zsolt1

I have tested my code on Proteus simulator. When i make a 8 bit interface. It work fine. But when i want to interface with 4 bits... nothing works. I know that any problem with my void Chr_LCD(char data). Because when i send data to all port.. works fine.

- - - Updated - - -

What do you feel for void Chr_LCD(char data)
 

Hi,

Lcd_Port(y>>4); //Data transfer
This is a shift right. So the upper nibble become the lower nibble.
I think this is wrong.
You should shift the lower nibble 4 bits left, so it becomes the upper nibble.

Klaus
 

Anybody can explain me how it's shifting.

For example: -

data = 'A'; // In ascii
data = 01000001 // in binary

Now then we send data in 2 parts. Upper nibble is 0100 and lower nibble is 0001.
What nibble should be send first?
 

Hi,

What nibble should be send first?
I don't know, but it surely is in the display's datasheet.

">>" is the shift right operator
"<<" is the shift left operator.
The parameter (4) behind the operator says the count of bits it is shifted.

You should also find the information in your compiler's documentation. Look for "shift", or "shift operator".

Klaus
 

As per your guidance i am trying to understanding it's consent. i make 2 local variable for this function. I will store upper nibble in one and lower in second variable. Now it will lock like this.

Code:
char up, down;

up = data & 0xF0;
down = data & 0x0F;

Result will come : -

up = 0000 0100 // Distance sow only for understanding
down = 0000 0001


Code:
PORTC = up<<4;     // up lower nibble send to PORTC upper nibble
EN = 1;
Delay();
EN = 0;

PORTC = down<<4;    // Down lower nibble send to PORTC upper nibble
EN = 1;
Delay();
EN = 0;

It is write?
I have connected EN & RS pines to PORTC lower nibble. Will these pins not wrong functioning?

- - - Updated - - -

It is write?
Sorry...I was writing Is it right?
 

If you use 'up = data & 0xF0;' it makes the lower 4 bits all zero (read about the logical AND instructions). Therefore 'PORTC = up<<4;' will always output zero on it's upper bits. As explained, the << instruction moves all the bits in the variable to the left (towards the most significant bit) by the number of places following it. You have an 8-bit value to be split into top 4-bit and bottom 4-bit halves. The top already holds the bits you need so all you have to do is remove the bottom part before sending it to the port.
Code:
PORTC = up;     //  send to PORTC upper nibble
EN = 1;
Delay();
EN = 0;
the lower 4 bits have to be moved up to the positions of the high bits by shifting to the left 4 times:
Code:
PORTC = (down << 4) & 0XF0;    // Down lower nibble send to PORTC upper nibble
EN = 1;
Delay();
EN = 0;

Beware of the potential trap here, by writing to PORTC you change ALL the bits in the port so bits 3:0 are also changed (set to zero in this case). If that will cause problems in your hardware, the trick is to read PORTC to a variable, AND it's value with 0X0F so the top bits are all zero, then OR it with the LCD bits you just generated. The variable will then contain the original lower bits and the new upper bits, you then write it back to PORTC.

Brian.
 

    V

    Points: 2
    Helpful Answer Positive Rating
Hi,

up = data & 0xF0;
down = data & 0x0F;
Imagine the data byte is 0x69.
then after your "masking":
up = 0x60
down = 0x09

for a clean implementation i recommend a read-modify-write technique.
(I´m not familiar with C, so pleas see it as a guidance, not as C code)

x = portc (read in previous state of portC)
x = x AND 0x0F (clear upper = data bits) (!!! corrected: here was an OR instead an AND)
portC = x OR up (set NEW upper = data bits)

Klaus
 
Last edited:
hi
i'll write from memory ...
I remember that i used PORTB high nibble B7...B4 connected to lcd 13,12,11,10 . So my function was like

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
void TxChLCD(char word, char i)
//and looked like this 
{
 RS=i ; // i=1 wrt data word  , i=0 wrt instruction word
PORTB=PORTB & 0b00001111; // clear data bus to lcd 
PORTB=PORTB  | (word & 0b11110000); // put high nibble first on the data bus
EN=1; _delay(2);EN=0; // tell the lcd to take in the data present on the bus
PORTB=PORTB & 0b00001111; // clear data bus to lcd 
PORTB=PORTB | (word<<4);  // put the lower nibble on the  bus
 EN=1; _delay(2);EN=0;// tell the lcd to take in the data present on the bus
_delay(140);
}




I don't know for shore what pins i used ... maybe lower bits of PORTB , B3,B2,B1,B0 connected to 13 ,12,11,10 of lcd
Than code would be like so:



Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
void TxChLCD(char word, char i)
//and looked like this 
{
 RS=i ; // i=1 wrt data word  , i=0 wrt instruction word
PORTB=PORTB & 0b11110000; // clear data bus to lcd 
PORTB=PORTB  | (word >>4); // put high nibble first on the data bus
EN=1; _delay(2);EN=0; // tell the lcd to take in the data present on the bus
PORTB=PORTB & 0b11110000; // clear data bus to lcd 
PORTB=PORTB | (word & 0b1111000);  // put the lower nibble on the  bus
 EN=1; _delay(2);EN=0;// tell the lcd to take in the data present on the bus
_delay(140);
}




It was a stroboscopic rpm meter , if i'll found it i'll post it (i think i did somewhere here :thinker: )

This is your function:

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void Chr_LCD(char data)
{
    TRISC &= 0x0F;
    PORTC &= 0x0F;
    PORTC |= data&0xF0;
    Time_10ms();
    Time_10ms();
    Time_10ms();
    E_PIN=1;
    Time_10ms();
    Time_10ms();
    Time_10ms();
    E_PIN=0;
 
    PORTC &= 0x0F;
    PORTC |= ((data<<4)&0xF0);
    Time_10ms();
    Time_10ms();
    Time_10ms();
    E_PIN=1;
    Time_10ms();
    Time_10ms();
    Time_10ms();
    E_PIN=0;
 
    TRISC |= 0xF0;
}



I would try it like this :

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Chr_LCD(char data)
{
    TRISC &= 0x0F; //  this is what you do first after cpu setup so would not use it here
    PORTC &= 0x0F;
    PORTC |= (data&0xF0);
        _delay (1);                  // ok let's say  i'd put here 1 us delay , thus not needed at all 
    E_PIN=1;
        _delay(3);                 // 3 us is more then enough for the lcd to reed the bus
    E_PIN=0;
 
    PORTC &= 0x0F;
    PORTC |= (data<<4);  // when you shift 4 positions to the left the lower part fills with 0 by default
                                      //  x x x x 0 0 0 0
    E_PIN=1;
    _delay(3);
    E_PIN=0;
 
     // why to make the pins input by  TRISC |= 0xF0; are you going to disconnect the lcd or what ?
}


PS: i was using Hi tec c compiller of Microchip. It had _delay (x); function to call to do microsecond delay
 
Last edited by a moderator:
Actually i am using PORTC for LCD and PWM is also there. Please see circuit given below and remark PWM also.

Untitled.png
 

Dear

When i send data to port C. It will make PORTC lower nibble 0000. But i don't want to make these pins 0. i want to leave these pins in previous status. Because if PORTC = xxxx0000 ... It will make EN = 0 & RS = 0 also. It mean LCD data receiving = No & Data instruction = Yes. So how it will work.
Actually i don't want to disturb lower nibble.
 

There are several code examples in this thread that solve this problem, e.g. the OR operation in post #1 and post #13. Using this method you shouldn't have a problem of overwriting port bits inadvertantly.
 
Hi,

One issue is "input/output" (direction)
The other is "data".

They are different.
Direction: as far as I can see the whole port may be configured as output. Continously.

Data: See solutions above.

Klaus
 

There are several code examples in this thread that solve this problem, e.g. the OR operation in post #1 and post #13. Using this method you shouldn't have a problem of overwriting port bits inadvertantly.

Ok

I will try to these replies (#1 & #13) codes.
 

I was referring to the way the port nibbles are controlled, I don't think that the codes should be used as is in all details. There are many unreasonable points, e.g. huge delays. It's required that you study the LCD interface requirements and correct the codes respectively.

There are tons of similar codes on the internet and code examples shipped with LCD displays or compilers. Many of them are probably better considered than the code examples posted in this thread,
 

Hi,

You have to send only 4 bits to the port
Most probably this is an 8 bit access, so you can´t send only 4 bits.

Klaus
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top