Electrical – Problem with displaying characters on LCD

lcdpic

I tried to interface PIC16f722A with LM016L LCD in proteus. I had wrote the C-code for initializing (LCD) and displaying characters on LCD.
The problems are as follows:

1)When I transfer X number of characters, it just shows (X-1) number of characters, ignoring the last character.

2)LCD shows Numbers and Special characters BUT NOT ALPHABETS.

Here is the screenshot of sending four characters i.e. (1,2,3,4) and it only shows 1 2 3. Here is the screenshot.
enter image description here

#include <stdio.h>
#include <stdbool.h>
#define LCD_DATA PORTB
#define LCD_CTRL PORTA

sbit LCD_EN at PORTA.B0;        // LCD Latch pin (Enable)
sbit LCD_RS at PORTA.B1;       // Command/Data select PIN | Command(RS=0) | DATA(RS=1)
sbit LCD_RW at PORTA.B2;       // READ/WRTIE pin | Read (1) | Write (0)


#define LCD_DATA_DIRECTION TRISB
sbit LCD_EN_Direction at TRISA0_bit;
sbit LCD_RS_Direction at TRISA1_bit;
sbit LCD_RW_Direction at TRISA2_bit;

#define CHECK_High_BIT(var,pos) (((var)>>(pos)) & 1)


// =========================    LCD FUNCTIONS =========================

void lcd_ready(){

             LCD_DATA_DIRECTION=0xff;    // Data ports input
             LCD_RS=0; // Command register
             LCD_RW=1; // Read from LCD
             Delay_ms(1);LCD_EN=0;Delay_ms(1);LCD_EN=1;Delay_ms(1); // Read requires Low-to-High sig
             while(CHECK_High_BIT(LCD_DATA,7));
             LCD_DATA_DIRECTION=0x00;   // Data ports output
}

void lcd_Command_write(char value){

                   LCD_RS=0;LCD_RW=0;
                   LCD_DATA=value;
                   Delay_ms(1);LCD_EN=1;delay_ms(1);LCD_EN=0;Delay_ms(1);
}

void lcd_Data_write(char value){
             LCD_DATA_DIRECTION=0x00;
             LCD_RS=1;LCD_RW=0;
             LCD_DATA=value;
             Delay_ms(1);LCD_EN=1;delay_ms(1);LCD_EN=0;Delay_ms(1);
}

void LCD_POWER(bool flag){

                if(flag){
                        Delay_ms(250);           // Power up delay
                        lcd_ready();             // Is LCD BUSY ? wait here
                        lcd_Command_write(0x38); // LCD 2 Lines, 5x7 characters
                        lcd_ready();
                        lcd_Command_write(0x0E); // Display ON, Cursor ON
                        lcd_ready();
                        lcd_Command_write(0x01);  // Clear LCD
                        lcd_ready();
                        lcd_Command_write(0x06);  // Shift Cursor Right
                        lcd_ready();
                        lcd_Command_write(0x80);  // Cursor at line 1 position 1
                        }
                else{
                        lcd_ready(); // Is LCD BUSY ? wait here
                        LCD_RS=0;      // Select Command Register
                        LCD_RW=0;      // Write operation
                        LCD_DATA=0x10; // Cursor and Display off
                        Delay_us(1);LCD_EN=1;Delay_us(1);LCD_EN=0; // Latch
                        }
 }


void main() {


LCD_DATA_DIRECTION=LCD_EN_Direction=LCD_RS_Direction=LCD_RW_Direction=0x00;

            LCD_POWER(1);
            LCD_ready();
            LCD_DATA_write('1');
            LCD_ready();
            LCD_DATA_write('2');
            LCD_ready();
            LCD_DATA_write('3');
            LCD_ready();
            LCD_DATA_write('4');

}

Here is the C Code

NOTE: I am not using delay b/w transfering characters, instead i use D7 pin of LCD to monitor whether the LCD is busy or not.

Best Answer

You have a fundamental problem with how you have coded the LCD controller busy flag check routine.

Referencing the HD44780 character mode LCD data sheet found at Sparkfun there is this timing sequence chart:

enter image description here

You will note that it is necessary to have the E pin high to be able to see the DB7 busy bit. In your code you pulse the E pin but the wait 1msec before even looking at the DB7. By the time you look any valid data is gone. You want to sample DB7 while the E is still high.

The typical way I code an LCD driver is to make low low level routines to support WriteCmd, ReadSts, WriteDat and ReadDat. Then the LCD busy check is a loop that calls the ReadSts inside a loop and checks the readback D7 value each read.

Another thing to be aware of is that the best time to do the LCD busy check is just BEFORE you intend to do a transaction to the LCD. This way you can get a small performance boost because your code can go off to do other things after the last write to LCD controller.

Related Topic