0
\$\begingroup\$

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.

asked Feb 15, 2017 at 8:27
\$\endgroup\$
2
  • \$\begingroup\$ @m.Alin : Thanks for the reply. By the way, I am using MicroC Pro so that's not the problem. As per your suggestion, I had placed lcd_ready() AFTER the last LCD_DATA_write('4'), still the same output. \$\endgroup\$ Commented Feb 15, 2017 at 9:07
  • 2
    \$\begingroup\$ You have no while(1) loop (or similar) at the end of your main(). As soon as you've written '4' your code reaches the end of main(), resets and starts over from the beginning. \$\endgroup\$ Commented Feb 15, 2017 at 13:39

2 Answers 2

4
\$\begingroup\$

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.

answered Feb 15, 2017 at 11:41
\$\endgroup\$
1
  • \$\begingroup\$ You are right. I should have read D7 after the EN=HIGH. There was another issue apart from that, and that was "ANSELA Register". I clear that register for Digital I/O and all characters seem to display. Thank you for your helpful suggestion. \$\endgroup\$ Commented Feb 16, 2017 at 7:16
3
\$\begingroup\$

First test if you can display '?' and not '@' then this would show that the problem occurs when you go from 0x3F to 0x40 ('A' is 0x41) so your problem occurs when you want to drive D6 high. Since D6 is connected to RB6/ICSPCLK you need to check both the TRIS state of port B and the config bits for using that pin as an output.

answered Feb 15, 2017 at 9:03
\$\endgroup\$
2
  • \$\begingroup\$ You are right, '?' appears and '@' don't. But I had configured TRISB as output, and whenever program visit write-module, it assign 0x00 to TRISB. I haven't used RB6/ICSPCLK pin for anything other than I/O output. I refer the datasheet and it says that it is Schmitt trigger input when used in "Serial Programming mode". \$\endgroup\$ Commented Feb 15, 2017 at 9:33
  • \$\begingroup\$ The problem of characters was with the "ANSELA Register". Once I clear the ANSELA, All characters are displayed now. \$\endgroup\$ Commented Feb 16, 2017 at 7:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.