Me 8 You 4 ( LCD PIC Interface With C)

Thread Starter

walid el masry

Joined Mar 31, 2009
133
i have written C code to interface 16x2 LCD with PIC16f876 using Mikroc compiler and with help of the RICKEY'S WORLD tutorial at

http://www.8051projects.net/lcd-interfacing/

which was very helpful and i was successful with 8 bit programing mode and thats is the result

Rich (BB code):
/*LCD 8 bit example
rs => Register Select [Command : Data]
     0 => Command
     1 => Data
rw => Read/Write [Write : Read]
     0 => Write
     1 => Read
en => Enable signal [High to Low]
*/
#define LCD_data PORTB
#define LCD_rs   PORTC.B0
#define LCD_rw   PORTC.B1
#define LCD_en   PORTC.B2
#define LCD_D7   PORTB.B7
void LCD_busy() {
  delay_ms(5);//it is very important to return to the manual for it
}
void LCD_write_command () {
  LCD_rs   = 0;        //Selected command register
  LCD_rw   = 0;        //We are writing in data register
  LCD_en   = 1;        //Enable H->L
  LCD_en   = 0;
  LCD_busy();          //Wait for LCD to process the command
}
void LCD_clear_display () {
  LCD_data = 0x01;     //Clear LCD
  LCD_write_command();
}
void LCD_return_home () {
  LCD_data = 0x02;     //Return LCD to Home
  LCD_write_command();
}
void LCD_entry_mode_set (unsigned int ID,unsigned int S) {
  /*
  ID => [Decrement : Increment]
        0 => Decrement
        1 => Increment
  S  => accompanies display shift
        0 => OFF
        1 => ON
  */
  LCD_data = 0x00;
  ID = ID << 1;
  LCD_data = LCD_data + 0x04 + ID + S;
  LCD_write_command();
}
void LCD_display_control (unsigned int D,unsigned int C,unsigned int B) {
  /*
  D  => Display ON/OFF
        0 => OFF
        1 => ON
  C  => Cursor ON/OFF
        0 => OFF
        1 => ON
  B  => Blink the character at the cursor position
        0 => OFF
        1 => ON
  */
  LCD_data = 0x00;
  C = C << 1;
  D = D << 2;
  LCD_data = LCD_data + 0x08 + D + C + B;
  LCD_write_command();
}
void LCD_cursor_display_shift (unsigned int SC,unsigned int RL) {
  /*
  Moves the cursor and shifts the display without changing the DDRAM contents
  SC  => [Cursor : Display]
        0 => Cursor
        1 => Display
  RL  => [Left : Right]
        0 => Left
        1 => Right
  */
  LCD_data = 0x00;
  RL = RL << 2;
  SC = SC << 3;
  LCD_data = LCD_data + 0x10 + SC + RL;
  LCD_write_command();
}
void LCD_function_set (unsigned int DL,unsigned int N,unsigned int F) {
  /*
  DL  => Data Width [4 bit : 8 bit]
        0 => 4 bit
        1 => 8 bit
  N  => Number of lines in display[1 : 2]
        0 => 1 Line
        1 => 2 Lines
  F  => Character font[5x7 : 5x10]
        0 => 5x7
        1 => 5x10
  */
  LCD_data = 0x00;
  F = F << 2;
  N = N << 3;
  DL = DL << 4;
  LCD_data = LCD_data + 0x20 + DL + N + F;
  LCD_write_command();
}
void LCD_cgram_address (unsigned int cgadrs) {
  /*
  cgadrs => CGRAM Address Binary 6 bit
  i didn't use it yet
  */
  LCD_data = 0x00;
  LCD_data = cgadrs;
  LCD_write_command();
}
void LCD_ddram_address (unsigned int ddadrs) {
  /*
  ddadrs => DDRAM Address Binary 7 bit
            Line 1 Column 1
            Binary Address : 0B10000000
            HEX Address     : 0X80
 
            Line 1 Column 16
            Binary Address : 0B10001111
            HEX Address     : 0X8F
 
            Line 2 Column 1
            Binary Address : 0B11000000
            HEX Address     : 0XC0
 
            Line 2 Column 16
            Binary Address : 0B11001111
            HEX Address     : 0XCF
            [][][][][][][][][][][][][][][][]
            [][][][][][][][][][][][][][][][]
                 C1    C2    C3    C4    C5    C6    C7    C8    C9    C10   C11   C12   C13   C14   C15   C16
            L1 [0X80][0X81][0X82][0X83][0X84][0X85][0X86][0X87][0X88][0X89][0X8A][0X8B][0X8C][0X8D][0X8E][0X8F]
            L2 [0XC0][0XC1][0XC2][0XC3][0XC4][0XC5][0XC6][0XC7][0XC8][0XC9][0XCA][0XCB][0XCC][0XCD][0XCE][0XCF]
  */
  LCD_data = 0x00;
  LCD_data = ddadrs;
  LCD_write_command();
}
void LCD_write_data(unsigned int output) {
  LCD_data = output;     //
  LCD_rs   = 1;        //Selected data register
  LCD_rw   = 0;        //We are writing in data register
  LCD_en   = 1;        //Enable H->L
  LCD_en   = 0;
  LCD_busy();
}
/*void LCD_write_string(unsigned char output) {
  LCD_data = output;     //Entry mode, auto increment with no shift
  LCD_rs   = 1;        //Selected data register
  LCD_rw   = 0;        //We are writing in data register
  LCD_en   = 1;        //Enable H->L
  LCD_en   = 0;
  LCD_busy();
}*/
void LCD_init() {
  LCD_function_set (1,1,0);//Function set: 2 Line, 8-bit, 5x7 dots
  LCD_display_control (1,1,1);//Display on, Curson blinking command
  LCD_clear_display();
  LCD_entry_mode_set (1,0);//Entry mode, auto increment with no shift
  LCD_ddram_address(0X80);//Line 1 Column 1
}
void main() {
  TRISB = 0x00;
  TRISC = 0x00;
  LCD_init();
  LCD_ddram_address(0X83);
  //"All"
  LCD_write_data(0x41);//'A'
  LCD_write_data(0x6C);//'l'
  LCD_write_data(0x6C);//'l'
  //space
  LCD_write_data(0x20);//space
  //"About"
  LCD_write_data(0x41);//'A'
  LCD_write_data(0x62);//'b'
  LCD_write_data(0x6F);//'o'
  LCD_write_data(0x75);//'u'
  LCD_write_data(0x74);//'t'
  LCD_ddram_address(0XC4);
  //"Circuits"
  LCD_write_data(0x43);//'C'
  LCD_write_data(0x69);//'i'
  LCD_write_data(0x72);//'r'
  LCD_write_data(0x63);//'c'
  LCD_write_data(0x75);//'u'
  LCD_write_data(0x69);//'i'
  LCD_write_data(0x74);//'t'
  LCD_write_data(0x73);//'s'
}
 

Attachments

Last edited by a moderator:

Thread Starter

walid el masry

Joined Mar 31, 2009
133
but i tried very well in 4 bit mode but the is some thing wrong as i checked it many times
here is the code

Rich (BB code):
/*LCD 4 bit example
  rs => Register Select [Command : Data]
        0 => Command
        1 => Data
  rw => Read/Write [Write : Read]
        0 => Write
        1 => Read
  en => Enable signal [High to Low]
*/
#define LCD_data PORTB
#define LCD_rs   PORTB.B2
#define LCD_en   PORTB.B3
//************************************

//************************************
void LCD_reset () {
     LCD_data = 0XFC;
     delay_ms(20);
     LCD_data = 0X34;//Data = 34H, EN = 1, RS = 0, First Init
     LCD_data = 0X30;//Data = 30H, EN = 0, RS = 0
     delay_ms(10);
     LCD_data = 0X34;//Data = 34H, EN = 1, RS = 0, Second Init
     LCD_data = 0X30;//Data = 30H, EN = 0, RS = 0
     delay_ms(1);
     LCD_data = 0X34;//Data = 34H, EN = 1, RS = 0, Third Init
     LCD_data = 0X30;//Data = 30H, EN = 0, RS = 0
     delay_ms(1);
     LCD_data = 0X44;//Data = 44H, EN = 1, RS = 0, Select Data width (4bit)
     LCD_data = 0X40;//Data = 40H, EN = 0, RS = 0
     delay_ms(1);
}
void LCD_write_command () {
     unsigned int temp;
     temp = LCD_data;
     LCD_data = temp & 0XF0;
     LCD_rs   = 0;        //Selected command register
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_data = (temp << 4) & 0XF0;
     LCD_rs   = 0;        //Selected command register
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     delay_ms(1);
}
void LCD_clear_display () {
     LCD_data = 0x01;     //Clear LCD
     LCD_write_command();
}
void LCD_return_home () {
     LCD_data = 0x02;     //Return LCD to Home
     LCD_write_command();
}
void LCD_entry_mode_set (unsigned int ID,unsigned int S) {
     /*
     ID => [Decrement : Increment]
           0 => Decrement
           1 => Increment
     S  => accompanies display shift
           0 => OFF
           1 => ON
     */
     LCD_data = 0x00;
     ID = ID << 1;
     LCD_data = LCD_data + 0x04 + ID + S;
     LCD_write_command();
}
void LCD_display_control (unsigned int D,unsigned int C,unsigned int B) {
     /*
     D  => Display ON/OFF
           0 => OFF
           1 => ON
     C  => Cursor ON/OFF
           0 => OFF
           1 => ON
     B  => Blink the character at the cursor position
           0 => OFF
           1 => ON
     */
     LCD_data = 0x00;
     C = C << 1;
     D = D << 2;
     LCD_data = LCD_data + 0x08 + D + C + B;
     LCD_write_command();
}
void LCD_cursor_display_shift (unsigned int SC,unsigned int RL) {
     /*
     Moves the cursor and shifts the display without changing the DDRAM contents
     SC  => [Cursor : Display]
           0 => Cursor
           1 => Display
     RL  => [Left : Right]
           0 => Left
           1 => Right
     */
     LCD_data = 0x00;
     RL = RL << 2;
     SC = SC << 3;
     LCD_data = LCD_data + 0x10 + SC + RL;
     LCD_write_command();
}
void LCD_function_set (unsigned int DL,unsigned int N,unsigned int F) {
     /*
     DL  => Data Width [4 bit : 8 bit]
           0 => 4 bit
           1 => 8 bit
     N  => Number of lines in display[1 : 2]
           0 => 1 Line
           1 => 2 Lines
     F  => Character font[5x7 : 5x10]
           0 => 5x7
           1 => 5x10
     */
     LCD_data = 0x00;
     F = F << 2;
     N = N << 3;
     DL = DL << 4;
     LCD_data = LCD_data + 0x20 + DL + N + F;
     LCD_write_command();
}
void LCD_cgram_address (unsigned int cgadrs) {
     /*
     cgadrs => CGRAM Address Binary 6 bit
     i didn't use it yet
     */
     LCD_data = 0x00;
     LCD_data = cgadrs;
     LCD_write_command();
}
void LCD_ddram_address (unsigned int ddadrs) {
     /*
     ddadrs => DDRAM Address Binary 7 bit
               Line 1 Column 1
               Binary Address : 0B10000000
               HEX Address     : 0X80

               Line 1 Column 16
               Binary Address : 0B10001111
               HEX Address     : 0X8F

               Line 2 Column 1
               Binary Address : 0B11000000
               HEX Address     : 0XC0

               Line 2 Column 16
               Binary Address : 0B11001111
               HEX Address     : 0XCF
               [][][][][][][][][][][][][][][][]
               [][][][][][][][][][][][][][][][]
                    C1    C2    C3    C4    C5    C6    C7    C8    C9    C10   C11   C12   C13   C14   C15   C16
               L1 [0X80][0X81][0X82][0X83][0X84][0X85][0X86][0X87][0X88][0X89][0X8A][0X8B][0X8C][0X8D][0X8E][0X8F]
               L2 [0XC0][0XC1][0XC2][0XC3][0XC4][0XC5][0XC6][0XC7][0XC8][0XC9][0XCA][0XCB][0XCC][0XCD][0XCE][0XCF]
     */
     LCD_data = 0x00;
     LCD_data = ddadrs;
     LCD_write_command();
}
void LCD_write_data(unsigned int output) {
     /*
     output => Data to be written
     */
     unsigned int output;//
     output = LCD_data;
     LCD_data = output & 0XF0;
     LCD_rs   = 1;        //Selected data register
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_data = (output << 4) & 0XF0;
     LCD_rs   = 1;        //Selected data register
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     delay_ms(1);
}
void LCD_init ()
{
     LCD_reset();         // Call LCD reset
     LCD_function_set (0,1,0);//Function set: 2 Line, 4-bit, 5x7 dots
     LCD_display_control (1,1,1);//Display on, Curson blinking command.
     LCD_clear_display();
     LCD_entry_mode_set (1,0);//Entry mode, auto increment with no shift
     LCD_ddram_address(0X80);//Line 1 Column 1
 }
void main() {
     TRISB = 0x00;
     LCD_init();
     LCD_write_data(0xff);//'A'
}
and the result is that the LCD switched on with no data on it
SOS PLZ :D :D
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
here is the instruction set i written in my code

Rich (BB code):
--------------------------------------------------------
LCD_clear_display ();
--------------------------------------------------------
LCD_return_home ();
--------------------------------------------------------
LCD_entry_mode_set (unsigned int ID,unsigned int S);
     ID => [Decrement : Increment]
           0 => Decrement
           1 => Increment
     S  => accompanies display shift
           0 => OFF
           1 => ON
--------------------------------------------------------
LCD_display_control (unsigned int D,unsigned int C,unsigned int B);
     D  => Display ON/OFF
           0 => OFF
           1 => ON
     C  => Cursor ON/OFF
           0 => OFF
           1 => ON
     B  => Blink the character at the cursor position
           0 => OFF
           1 => ON
--------------------------------------------------------
LCD_cursor_display_shift (unsigned int SC,unsigned int RL);
     Moves the cursor and shifts the display without changing the DDRAM contents
     SC  => [Cursor : Display]
           0 => Cursor
           1 => Display
     RL  => [Left : Right]
           0 => Left
           1 => Right
--------------------------------------------------------
LCD_function_set (unsigned int DL,unsigned int N,unsigned int F)
     DL  => Data Width [4 bit : 8 bit]
           0 => 4 bit
           1 => 8 bit
     N  => Number of lines in display[1 : 2]
           0 => 1 Line
           1 => 2 Lines
     F  => Character font[5x7 : 5x10]
           0 => 5x7
           1 => 5x10
--------------------------------------------------------
LCD_cgram_address (unsigned int cgadrs);
     cgadrs => CGRAM Address Binary 6 bit
     i didn't use it yet
--------------------------------------------------------
LCD_ddram_address (unsigned int ddadrs);
     ddadrs => DDRAM Address Binary 7 bit
               Line 1 Column 1
               Binary Address : 0B10000000
               HEX Address     : 0X80

               Line 1 Column 16
               Binary Address : 0B10001111
               HEX Address     : 0X8F

               Line 2 Column 1
               Binary Address : 0B11000000
               HEX Address     : 0XC0

               Line 2 Column 16
               Binary Address : 0B11001111
               HEX Address     : 0XCF
               [][][][][][][][][][][][][][][][]
               [][][][][][][][][][][][][][][][]
                    C1    C2    C3    C4    C5    C6    C7    C8    C9    C10   C11   C12   C13   C14   C15   C16
               L1 [0X80][0X81][0X82][0X83][0X84][0X85][0X86][0X87][0X88][0X89][0X8A][0X8B][0X8C][0X8D][0X8E][0X8F]
               L2 [0XC0][0XC1][0XC2][0XC3][0XC4][0XC5][0XC6][0XC7][0XC8][0XC9][0XCA][0XCB][0XCC][0XCD][0XCE][0XCF]
--------------------------------------------------------
LCD_write_data(unsigned int output);
     output => Data to be written
--------------------------------------------------------
and the manual LCD commands


 

rjenkins

Joined Nov 6, 2005
1,013
Do you have the correct four data lines of the LCD connected to the high half of Port B?

If they are OK, it could be timing - the LCD 'E' pulse must be 450nS minimum, unless you are using a very low CPU clock you may have to add some NOPs between setting E High & Low again.

You could also try the '8 Bit' program, just substituting the 4 bit LCD Write Command & Write Data routines substituted for the 8 bit versions, with any required tweaks and the different init values.

That gives you a lot less code to debug!
 

rjenkins

Joined Nov 6, 2005
1,013
I've used the LM016 in 8 bit mode, but never 4 bit.

In the data sheet for the HD44780 controller chip, it says the Busy line *must* be checked after each write.

I wonder if it needs transitions on the R/W line to sync the High & Low nibbles of the data transfer..

I woudl try single-stepping your code in the simulator and check each value sent out of the data port against the LCD controller data sheet to make sure it is sending the right commands.

HD44780 Data:
http://users.ece.gatech.edu/~hamblen/UP3/HD44780u.pdf
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
you are correct about the buzy flag but i have the option to check it or to wait for the correct delay of time and send another data or command and i have to say that i have already programed it in 4 bit mode but in assembly for the same chip but it just not working and iam wery sure about the code for 8 bit mode and have tested it successfully and it doesn't need a big modification to work in 4 bit mode just the
LCD_write_command & LCD_write_data that i have to change it and i tested them also
successfully away from the code and they take the higher nibbles and send it then enable signal then the same for the lower nibbles and wait for the time which suppose the lcd will not buzy after it but it just not working :( :(
 

rjenkins

Joined Nov 6, 2005
1,013
I don't know as a fact, but the only thing I can think of is it *needs* a transition on the R/W line to synchronise when in 4 bit mode.

If you look at the timing diagrams for 4 bit mode, the R/W transitions are always between the pairs of H/L nibble transfers.

Until it sees such a transition, how does it sync high and low nibbles??
- the ONLY key appears to be that the High half is first after any R/W change.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
if you mean with the transition of R/W the changing in the state from H to L i guess its not a big deal cause it is just about to read the buzy flag not to synchronise between the higher and lower nibbles which controlled by the enable signal after sending each nibble it goes fro H to L which synchronise between them , see this from the manual you give me at the page 23



there is no need to change the state of R/W from L to H just to read the buzy flag
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133


what i have done in the code is that write a functions to handle every instruction and you just need to enter the value of the parameters as you like and then put them in the LCD_data and then let the functions
LCD_write_command() or the LCD_write_data() write them to the LCD and it was successful in the 8 bit mode so the thing i need to change is the way i send the command or the data to the LCD and as we know in 4 bit mode we take the higher nibble and send it then enable signal then lower nibble then enable signal then wait the buzy flag or check it by reading it so lets test the concept of my code there

Rich (BB code):
void LCD_write_command () {
     unsigned int temp;
     temp = LCD_data;//take a temp copy of the output of each function which will be send to LCD
     LCD_data = temp & 0XF0;//mask the higher nibble
     LCD_rs   = 0;        //Selected command register
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     //****1
     LCD_data = (temp << 4) & 0XF0;//swap lower nibble with the higher and mask it
     LCD_rs   = 0;        //Selected command register
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     delay_ms(1);//****2
}
and to be sure if the program working i tried to blink the LCD_data or the PORTB after

Rich (BB code):
LCD_write_data(0xff);//'A'
in

Rich (BB code):
void main() {
     TRISB = 0x00;
     LCD_init();
     LCD_write_data(0xff);//'A'
}
and the program reached it normally , i can't know that is the wrong but i guess it is the timing and i guess it will be at the point
****1 or ****2 or both of them , what do you think
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
i forgot , or in the timing of the initialization sequence of the 4 bit mode

Rich (BB code):
Rich (BB code):
    void LCD_reset () {
     LCD_data = 0XFC;
     delay_ms(20);
     LCD_data = 0X34;//Data = 34H, EN = 1, RS = 0, First Init
     LCD_data = 0X30;//Data = 30H, EN = 0, RS = 0
     delay_ms(10);
     LCD_data = 0X34;//Data = 34H, EN = 1, RS = 0, Second Init
     LCD_data = 0X30;//Data = 30H, EN = 0, RS = 0
     delay_ms(1);
     LCD_data = 0X34;//Data = 34H, EN = 1, RS = 0, Third Init
     LCD_data = 0X30;//Data = 30H, EN = 0, RS = 0
     delay_ms(1);
     LCD_data = 0X44;//Data = 44H, EN = 1, RS = 0, Select Data width (4bit)
     LCD_data = 0X40;//Data = 40H, EN = 0, RS = 0
     delay_ms(1);
}

 

THE_RB

Joined Feb 11, 2008
5,438
1. You do know that the MikroC compiler you are using already has a full set of 8bit and 4bit LCD functions, you don't need to write your own?

2. Since you have written your own, you might want to post your code on the MikroE forum, people are often asking for LCD code because the MikroC built in code requires the use of specific port pins and they want to use LCD with different pins.
 

rjenkins

Joined Nov 6, 2005
1,013
We are at cross purposes; I do not mean you must USE the busy signal, I mean that the transition of the R/W line could be needed.

Think about the data and control pattern as seen by the LCD Controller; every nibble sent has an E pulse.

How does the controller know which is the Low data and which is the High data?

It's not E, so it must be one of the other control lines that only changes between Byte transfers & resets the internal state machine so it uses the next transfer as a High nibble.


Re. other timing, depending on the exact type of controller chip, the minimum E cycle time (from one rising edge to the next) is either 1uS or 500nS and the minimum E pulse width or separation is half of that.

What clock speed is your PIC running at?
(Also, what compiler are you using?)

Edit: Sorry, you mentioned MikroC compiler..
 
Last edited:

rjenkins

Joined Nov 6, 2005
1,013
I've just checked the driver routines supplied with my C compiler (CCS).
There is an LCD module included and it is for Four bit operating mode.

They have a few 'delay_cycles(1)' scattered about, most of which are not actually required. The possibly critical differences between their timings and yours are:
A: Use of busy check loop before each byte write sequence (so toggling R/W).
B: A 'delay_us(2)' between setting E high and low at each transfer.

That's way longer than required, but some delay may be required to get the minimum E pulse width of 500 or 250nS.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
i tried checking the busy and as i expected it works for the 8 bit mode :D

and here is the code

Rich (BB code):
void LCD_busy() {
     //delay is in case you don't want to check the buzy flag
     //delay_ms(5);//it is very important to return to the manual for it
     //in case of chicking the buzy flag
     LCD_D7 = 1;           //Make D7th bit of LCD as i/p
     LCD_en = 1;           //Make port pin as o/p
     LCD_rs = 0;
     LCD_rw = 1;
     while (LCD_D7) {
           LCD_en = 0;
           LCD_en = 1;
     }
}
it works but i have to ask is that true the i can change the state of pin or port while running from output to input specially for PIC ?

and unfortunately the 4 bit mode still not working after modification
let's see it



see the code but 1st i i should mention that when testing on 8 bit or 4 bit it gives me in Proteus

Rich (BB code):
Logic connection(s) detected on net #
and also that

Rich (BB code):
Controller received command whilst busy
and

Rich (BB code):
[HD44780] Attempted to read after writing a single nibble
&
[HD44780] Attempted to write after reading a single nibble
and that is the code for write commad

Rich (BB code):
void LCD_write_command () {
     unsigned int temp;
     temp = LCD_data;
     LCD_data = temp & 0XF0;
     LCD_rs   = 0;        //Selected command register
     LCD_rw   = 0;        //we are writing
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_data = (temp << 4) & 0XF0;
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_D7   = 1;           //Make D7th bit of LCD as i/p
     LCD_en   = 1;           //Make port pin as o/p
     LCD_rs = 0;
     LCD_rw   = 1;        //we are reading
     while(LCD_D7){          //read busy flag again and again till it becomes 0
           LCD_en   = 0;     //Enable H->L
           LCD_en   = 1;
     }
}
and writing data

Rich (BB code):
void LCD_write_data(unsigned int output) {
     /*
     output => Data to be written
     */
     output = LCD_data;
     LCD_data = output & 0XF0;
     LCD_rs   = 1;        //Selected data register
     LCD_rw   = 0;        //we are writing
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_data = (output << 4) & 0XF0;
     LCD_en   = 1;        //Enable H->L
     LCD_en   = 0;
     LCD_D7   = 1;           //Make D7th bit of LCD as i/p
     LCD_en   = 1;           //Make port pin as o/p
     LCD_rs = 1;
     LCD_rw   = 1;        //we are reading
     while(LCD_D7){          //read busy flag again and again till it becomes 0
           LCD_en   = 0;     //Enable H->L
           LCD_en   = 1;
     }
}
:confused:
 

rjenkins

Joined Nov 6, 2005
1,013
In 4 bit mode, EVERY 'transaction' with the LCD must be 8 bit (2x4 bits) including reading the busy flag; see the timing diagram (Figure 9) in the data sheet link I posted earlier.
(But you can discard the low nibble when just checking Busy).

LCD_D7 = 1; will not work, it just sets the pin High rather than make it an input.

You should change the TRIS register to change pins between input and output, eg.
You should have

TRISB = 0x00; to set all as output,
and
TRISB = 0xF0; to set high nibble as input and low still output.

The Busy flag is part of the address register, when you do a read you are reading data on all data lines, so all the data lines at the PIC end must be set to the matching direction before E is active to avoid conflicts or damage.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
(But you can discard the low nibble when just checking Busy).
iam 100 % with you

LCD_D7 = 1; will not work, it just sets the pin High rather than make it an input.
i belive it will never work but the problem is that it works and that what make me ask in the last post

but i have to ask is that true the i can change the state of pin or port while running from output to input specially for PIC ?
and from the testing of the code i add to my question

without TRIS ?!!!!
The Busy flag is part of the address register, when you do a read you are reading data on all data lines, so all the data lines at the PIC end must be set to the matching direction before E is active to avoid conflicts or damage.
good thinking and logically also but without TRIS thats what mde me crazy and also it works for the 8 bit :D :(
 

rjenkins

Joined Nov 6, 2005
1,013
Just noticed something rather wrong;
you are using 'LCD_Data' as a temporary store at the start of the routines (temp = LCD_Data and output = LCD_Data; ) but LCD_Data also appears to be you output port, the low half of which is the LCD control lines.

Any time you write to LCD_Data it sets ALL EIGHT pins to the values in that byte, including the control pins.

This is almost certainly messing up the 'nibble sync' with the LCD as every time you set up to write a byte/character with bit 3 set, it activates E before the LCD_write_xxx routines are called.
 
Top