[LCD] 4 Bit Mode not showing anything on the LCD

Thread Starter

Rafael Adel

Joined Aug 7, 2015
11
I'm trying to implement a function that displays the letter `c` on the LCD using 4-bit mode. But when I run the code on Proteus I get a blank lcd.
I tried the code with 8 bit mode (without the bits manipulation) and works perfectly. So there's nothing wrong with lcd_send() and lcd_save() i guess.
I know there's tons of libraries for that, but i'm trying to write it for learning purpose.

Here's my code:
Code:
void init_lcd()
{
 //Setting DDRA and DDRC to output
    struct conf con;
    con.port_pointer = PINA_ADDR;
    con.value= 0xff;
    set_direction_port(con);
  
    con.port_pointer = PINC_ADDR;
    con.value= 0xff;
    set_direction_port(con);
  
    lcd_send_cmd(0x28);
    lcd_send_cmd(0x0c);
}
void lcd_send_char(char c)
{
        // Sets direction to write
    set_lcd_dir(0);
       // Enables data register
    set_control_reg(1);

    lcd_send(c & 0xf0);
    lcd_save();
    set_lcd_dir(0);
    set_control_reg(1);
    lcd_send((c & 0x0f) << 4);
    lcd_save();
}

void lcd_send(char c)
{
    struct conf con;
    con.port_pointer = PINC_ADDR;
    con.value= c;

    write_port(con);
}

void lcd_save()
{
    //Saving
    set_lcd_enable(0);
    _delay_ms(1);
    set_lcd_enable(1);
    _delay_ms(1);
    set_lcd_enable(0);
}
I will attach the code with proteus file in case you needed it.

If there's any information needed, please tell me. Thanks.
 

Attachments

Last edited:

ErnieM

Joined Apr 24, 2011
7,991
There are several very necessary delays you need to add to get the LCD up and running. There allow the display to do its power on reset, and also time to process the commands.

These delays vary all over the place so you need to read the data sheet of the specific device you have.
 

spinnaker

Joined Oct 29, 2009
7,815
I am not seeing where you are telling the lcd it is 4 bit mode.

This is what I do for the LCD library I use.

Code:
  LCD_nybble(0x02,0);  //Enable 4 bit mode
   delay_ms(1);

   LCD_cmd(0b00101100);       //set 4-bit mode and 2 lines @ 5x7
   delay_us(160);
And you need delays like Ernie mentioned unless it is in your other functions which you seem reluctant to post all of your relevant code for some reason.
 

Thread Starter

Rafael Adel

Joined Aug 7, 2015
11
I am not seeing where you are telling the lcd it is 4 bit mode.

This is what I do for the LCD library I use.

Code:
  LCD_nybble(0x02,0);  //Enable 4 bit mode
   delay_ms(1);

   LCD_cmd(0b00101100);       //set 4-bit mode and 2 lines @ 5x7
   delay_us(160);
And you need delays like Ernie mentioned unless it is in your other functions which you seem reluctant to post all of your relevant code for some reason.
Here in the init function:
Code:
    lcd_send_cmd(0x28);
I've attached the whole project files.
 

Thread Starter

Rafael Adel

Joined Aug 7, 2015
11
There are several very necessary delays you need to add to get the LCD up and running. There allow the display to do its power on reset, and also time to process the commands.

These delays vary all over the place so you need to read the data sheet of the specific device you have.
So what're you saying is that it maybe a delay problem ? not a bit fiddling problem for instance ?
 

spinnaker

Joined Oct 29, 2009
7,815
I would have to analyze what a 0x28 does as I have not worked with LCDs for some time now. Just showing you what works for me. You can do with that what you want.

And it might be helpful if you gave a bit more information when posting so others can help you.
 

spinnaker

Joined Oct 29, 2009
7,815
So what're you saying is that it maybe a delay problem ? not a bit fiddling problem for instance ?
The delay in sending commands is extremely important in the LCD. And you can't just send your init routine at power up. I delay 40 ms before sending init data.
 

ErnieM

Joined Apr 24, 2011
7,991
Since this is a Proteus simulation it may work fine without delays, such is a limitation of simulation. It will not work on the real world hardware.

If you use the same routine to send a character in either an 8 bit or a 4 bit mode then you are doing it wrong. 4 bit mode means you literally send the 8 bit character 4 bits at a time, in 2 separate transactions.

Look, everyone who tries this gets stuck for some time, most make it thru anyway. The ones who get thru the fastest start with some example they read off the interwebs. Google is your friend here, try searching for "Proteus LCD example" and add in the processor you are using. I suspect someone else who did this and got it to work will have posted his code somewhere.
 

dannyf

Joined Sep 13, 2015
2,196
But when I run the code on Proteus I get a blank lcd.
That means the LCD isn't properly initialized - if you look at your init_lcd() routine vs. the datasheet, the errors are obvious.

Embedded programming is easy in that you just need to code to the datasheet of the device that you are programming to / on. In this case, your code isn't even close to the datasheet.
 

Thread Starter

Rafael Adel

Joined Aug 7, 2015
11
That means the LCD isn't properly initialized - if you look at your init_lcd() routine vs. the datasheet, the errors are obvious.

Embedded programming is easy in that you just need to code to the datasheet of the device that you are programming to / on. In this case, your code isn't even close to the datasheet.
Could you please give me a link for that datasheet ?
 

dannyf

Joined Sep 13, 2015
2,196
Google is your best friend here.

BTW, Proteus is very realistic. If you get your code working on Proteus, it has a great chance to work in the real world.
 

jpanhalt

Joined Jan 18, 2008
7,691
Here is assembly for the initialization:
Code:
POR
;POR according to Hitachi datasheet.  NB: RB<0:3> are mapped to display lines
;DB<4:7>, in order.  Use PutNib for the POR unitl 4-bit mode is set.   A swapf
;is not needed in PutNib as the lower 4 bits of PORTB are sent first and only
;those bits are sent.

     DelayCy   (100*msecs)
     movlw     0x03       
     call      PutNib
     DelayCy   (5*msecs)
     movlw     0x03
     call      PutNib
     DelayCy   (1*msecs)
     movlw     0x03
     call      PutNib       
     movlw     02           ;Function set: read as 0x20
     call      PutNib         ;4-bit mode is now set, N & F not defined yet

;LCD is now in 4-bitmode and 8-bit instructions and data are sent as two nibbles.

     movlw     0x28           ;Function set: 8 bits sent 4-bit mode
     call      PutCmd         ;N & F are now defined
     movlw     0x08           ;Display on/off control: display off
     call      PutCmd     
     DelayCy   (150*msecs)    ;blinks screen (optional)
     DelayCy   (150*msecs)    ;blinks screen (optional)
     movlw     0x01           ;Clear display: clears display
     call      PutCmd     
     DelayCy   (2*msecs)
        movlw     0x06           ;Entry mode set: increment address (cursor)
      call       PutCmd     
      movlw     0x0C           ;Display on/off: display on/cursor off/blink off
      call       PutCmd
        return
Don't know if that helps. Here is a link to the Hitachi datasheet: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf

John

Edit: That code was written before I started using the busy signal for timing. Once you enter 4-bit mode, using busy removes doubts about how long the delays should be.
 
Last edited:

ErnieM

Joined Apr 24, 2011
7,991
Google is your best friend here.

BTW, Proteus is very realistic. If you get your code working on Proteus, it has a great chance to work in the real world.
I would turn that statement around as such:
"If you can't get your code working on Proteus, you have no chance it will work in the real world."

Simulators cannot possibly cover all real world possibilities.
 

spinnaker

Joined Oct 29, 2009
7,815
Here is assembly for the initialization:
Code:
POR
;POR according to Hitachi datasheet.  NB: RB<0:3> are mapped to display lines
;DB<4:7>, in order.  Use PutNib for the POR unitl 4-bit mode is set.   A swapf
;is not needed in PutNib as the lower 4 bits of PORTB are sent first and only
;those bits are sent.

     DelayCy   (100*msecs)
     movlw     0x03      
     call      PutNib
     DelayCy   (5*msecs)
     movlw     0x03
     call      PutNib
     DelayCy   (1*msecs)
     movlw     0x03
     call      PutNib      
     movlw     02           ;Function set: read as 0x20
     call      PutNib         ;4-bit mode is now set, N & F not defined yet

;LCD is now in 4-bitmode and 8-bit instructions and data are sent as two nibbles.

     movlw     0x28           ;Function set: 8 bits sent 4-bit mode
     call      PutCmd         ;N & F are now defined
     movlw     0x08           ;Display on/off control: display off
     call      PutCmd    
     DelayCy   (150*msecs)    ;blinks screen (optional)
     DelayCy   (150*msecs)    ;blinks screen (optional)
     movlw     0x01           ;Clear display: clears display
     call      PutCmd    
     DelayCy   (2*msecs)
        movlw     0x06           ;Entry mode set: increment address (cursor)
      call       PutCmd    
      movlw     0x0C           ;Display on/off: display on/cursor off/blink off
      call       PutCmd
        return
Don't know if that helps. Here is a link to the Hitachi datasheet: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf

John

Edit: That code was written before I started using the busy signal for timing. Once you enter 4-bit mode, using busy removes doubts about how long the delays should be.

Op is programming in C.

I have attached the code that I use in C. You will need to customize it.
 

Attachments

jpanhalt

Joined Jan 18, 2008
7,691
Op is programming in C.

I have attached the code that I use in C. You will need to customize it.
That was obvious, hence my comment. Nevertheless, converting the algorithm/sequence from Assembly to C should not be difficult. In fact, that is why I didn't include the code for PutCmd, etc. The OP was simply not following the datasheet.

John
 
Top