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] Interfacing LCD with PIC MCU

Status
Not open for further replies.

tajiknomi

Member level 4
Member level 4
Joined
Nov 2, 2015
Messages
79
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
754
Okay, so i tried to interface PIC16f722A with LM016L LCD. i had wrote the C-code for initializing (LCD) and displaying characters on LCD. Somehow i got stuck when i simulated the program in Proteus. 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) The proteus shows that "Controller(LM016L) was busy while recieving the character".

I didn't used delay in the program,instead, i used one bit (D7) to monitor whether the LCD is busy or not. Here is the screenshot.
Capture.PNG
Note: I have transfered 4 characters and it displayed only "3"
Here is the C code



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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#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_BIT(var,pos) (((var)>>(pos)) & 1)
 
 
// =========================    LCD FUNCTIONS =========================
 
//           LCD Busy-Check function
 
void lcd_ready(){
 
             LCD_DATA_DIRECTION=0xff;    // Data ports input
             LCD_RS=0; // Command register
             LCD_RW=1; // Read from LCD
             LCD_EN=0;Delay_ms(1);LCD_EN=1;                 // Low-to-High signal for latching
             //while(LCD_DATA && 0x08 == 0x08);            // Checking the MSB (B7) for busy indication
             while(CHECK_BIT(LCD_DATA,7));                 // Stay here if the d7 bit is high (i.e. LCD is busy)
}
 
//  LCD Command write function
 
void lcd_Command_write(char value){
                   LCD_DATA_DIRECTION=0x00;
                   LCD_RS=0;LCD_RW=0;
                   LCD_DATA=value;
                   LCD_EN=1; delay_ms(1); LCD_EN=0;      // High to Low signal for latching
}
 
 
//  LCD Display function
 
void lcd_Data_write(char value){
             LCD_DATA_DIRECTION=0x00;
             LCD_RS=1;LCD_RW=0;
             LCD_DATA=value;
             LCD_EN=1;delay_ms(1);LCD_EN=0;          // High to Low signal for latching
}
 
 
//          LCD_POWER(ON/OFF) | ON=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_EN_Direction=LCD_RS_Direction=LCD_RW_Direction=0x00;
            LCD_DATA_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');                     // Last character doens't shows up!
}



I tried and tried to solve what's wrong with the code, still couldn't find the bug that is causing the above 2 issues i have stated.

So i tried to use "built-in Library" provided by the MicroCpro for the LCD, And guess what, i got the same "Controller(LM016L) was busy while recieving the character".

Any help would be appreciated. Thank you.
 
Last edited by a moderator:

Code written pretty dirty, but just guessing, may be strobe have to be delayed simmetrically?
Code:
void lcd_Data_write(char value){
             LCD_DATA_DIRECTION=0x00;
             LCD_RS=1;LCD_RW=0;
             LCD_DATA=value;
             LCD_EN=1;delay_ms(1);LCD_EN=0;[COLOR="#FF0000"]delay_ms(1);[/COLOR]          // High to Low signal for latching
}
 

Code written pretty dirty, but just guessing, may be strobe have to be delayed simmetrically?
Code:
void lcd_Data_write(char value){
             LCD_DATA_DIRECTION=0x00;
             LCD_RS=1;LCD_RW=0;
             LCD_DATA=value;
             LCD_EN=1;delay_ms(1);LCD_EN=0;[COLOR="#FF0000"]delay_ms(1);[/COLOR]          // High to Low signal for latching
}

I didn't understand "may be strobe have to be delayed simmetrically". Can you eloborate it a little. Excuse my english.
 
Last edited:

When you cycle execution of lcd_Data_write LCD_EN=1 will be executed right after LCD_EN=0. So there will not be any delay needed to latch the data by LCD.
 
Strobe means sending a clock to EN pin. 500us delay is enough for the strobe if your delay function gives proper delay. From your sbit defines it seems you are using mikroC PRO PIC. Is it correct ? If yes, then it has a LCD Library.
 
Thank's Easyrider83, I had just read the timing diagram of LATCH cycle and its shows 140ns delay b/w LCD R/W.
Capture.PNG
I had put 1ms delay and it solved my 2nd problem, i.e Controller isn't busy now :)
But the 1st problem still remains i.e. The last character doesn't show up on the LCD. Any idea's about that ?

- - - Updated - - -

@Okada : Yes, i am using mikroC PRO PIC, but i don't want to use the "built-in" library for the LCD, therefore i tried to make my own module for that. And yes you are right about the 500us delay, the timing diagram shows about 450us delay (minimum). Somehow i had used 1ms delay (because MicroC pro hasn't builtin function for nano-seconds delay) and it worked.
 

... I had just read the timing diagram of LATCH cycle and its shows 140ns delay b/w LCD R/W. the timing diagram shows about 450us delay (minimum). Somehow i had used 1ms delay (because MicroC pro hasn't builtin function for nano-seconds delay)
Do not mix the time-units, mikroC really does not have nanosecond (ns) delay libraries but it has microsecond (us) delays so use Delay_us(1) instead of every Delay_ms(1) which is unnecessarily long.

Your initialization sequence is wrong, see the HD44780 datasheet. Busy Flag can be checked only after the first three instructions.

Please zip and post (attach) the whole project folder (also the DSN) if it still does not work.
 

@zuisti
This file contains the proteus design and MicroC Pro file.
 

Attachments

  • LCD.rar
    77.7 KB · Views: 143

I don't see where you are printing out a string

I haven't used that module yet. I am just using lcd_ready(), lcd_Command_write(), lcd_Data_write() and LCD_POWER(). Once i am finished with single characters display, i will switch to supply characters(string) at the same time. For a time being, i am stuck with the 1st problem,
 

... the 1st problem still remains i.e. The last character doesn't show up on the LCD. Any idea's about that ?
My idea (not tried yet, sorry):
Simply put a "LCD_EN = 0;" instruction to the end of your lcd_ready() function.
Without the above it leaves the EN pin at HIGH level so the subsequent (the last !) lcd_Data_write does not make any raising EN transition and does not work.
 

Hi tajiknomi;
I was looking for more than a hour the mistake. Finally I found it: the main problem was the missing ANSELA = 0; instruction :roll:. Without this the PORTA is malfunctioning (see the datasheet).

Here is my modified (and a bit simplified) source:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//8-bit LCD with BF, written by zuisti
 
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)
 
char sfr LCD_DATA at PORTB;
char sfr LCD_DATA_DIRECTION at TRISB;
 
sbit LCD_EN_Direction at TRISA0_bit;
sbit LCD_RS_Direction at TRISA1_bit;
sbit LCD_RW_Direction at TRISA2_bit;
 
// =========================    LCD FUNCTIONS =========================
 
void lcd_ready(){
 
   LCD_DATA_DIRECTION=0xFF;    // Data ports input
   LCD_RS=0; // Command register         
   LCD_RW=1; // Read from LCD
   while (1) {
     Delay_us(1);
     LCD_EN=1;
     Delay_us(1);
     if (!LCD_DATA.B7) // Busy Flag
        break;
     LCD_EN=0;
   }
   LCD_EN=0;
   LCD_DATA_DIRECTION=0;   // Data ports output
}
 
void lcd_Command_write(char value){
   
   lcd_ready();
   LCD_RS=0;LCD_RW=0;
   LCD_DATA=value;
   Delay_us(1);LCD_EN=1;Delay_us(1);LCD_EN=0;
}
 
void lcd_Data_write(char value){
 
   lcd_ready();
   LCD_RS=1;LCD_RW=0;
   LCD_DATA=value;
   Delay_us(1);LCD_EN=1;Delay_us(1);LCD_EN=0;
}
 
void LCD_POWER(void){
 
    Delay_ms(250);           // Power up delay
    lcd_Command_write(0x38); // LCD 2 Lines, 5x7 characters
    lcd_Command_write(0x0E); // Display ON, Cursor ON
    lcd_Command_write(0x01); // Clear LCD
    lcd_Command_write(0x06); // Shift Cursor Right
    lcd_Command_write(0x80); // Cursor home
}
 
//-------
 
void main() {
 
    ANSELA = 0;   // !!! this was the main problem
    ANSELB = 0;   // this does not necessarily need
 
//    PORTA = 0;
//    TRISA = 0;
//    PORTB = 0;
//    TRISB =0;
    // or:
    LCD_DATA_DIRECTION=0;
    LCD_EN_Direction=0;
    LCD_RS_Direction=0;
    LCD_RW_Direction=0;
 
  // but DO NOT use this form in mikroC (much larger code):
//LCD_DATA_DIRECTION=LCD_EN_Direction=LCD_RS_Direction=LCD_RW_Direction=0x00;
 
    LCD_POWER();
    lcd_Data_write('1');
    lcd_Data_write('2');
    lcd_Data_write('3');
    lcd_Data_write('4'); // not '?'
}



Tested only in Proteus, here is the result:
LCDbusy.gif

Hope this will be a good starting point for you.
Good luck.
zuisti
 
@zuisti: Thank you soo much :)
I wasn't aware of ANSELA=0
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top