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.

Interfacing LCD to PIC32

Status
Not open for further replies.

neelamgpg

Newbie level 2
Joined
Jan 22, 2012
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,339
I am trying to interface an LCD to a PIC32 microcontroller without any success until now. I am using MPLABX as the platform. Initially some random characters used to get displayed. Basic instructions like cursor blink used to work but when I tried strings nothing worked and even the previous outputs are not coming.
Now nothing seems to work. Only a line of boxes is displayed. I tried changing the delays, changing the enable pin value, sending different sequences but nothing has worked till now. I checked the outputs for the enable pin on an oscilloscope. It toggles after a period of 500ms. I am using the LCD in the 4-bit mode. The LCD is being used at 5V. I have connected it to the 5V tolerant pins on the PIC32 and tried as well.
Kindly advise where I might be going wrong. I can post my code over here as well.
 

It is likely an issue of improper initialization.

The single row of black boxes usually indicates the LCD has powered up correctly and is waiting for proper initialization.

Post you code using CODE tags and a schematic of your design, so that we may examine it.

BigDog
 

Also check you have pullups to 5V on the 5V signal lines and check they are actually going to 5V. Make sure you have sufficient delay between sending commands to the display - some can take 2ms depending on the display.

I am not sure about MPLAB X - I have ditched it for now - but that is a separate issue.

Keith
 

I connected pull up resistors at the 5v pins but surprisingly my LCD was not drawing more than 3.3V(which is the voltage at which the PIC is operating.)I don't know why this happened.
I decided to use the lcd at 3.3V then. The code is as shown below. (Many sections have been commented out.)
The LCD has been connected on PORTA(from A0-A3)
The connections for RS, EN and RW are on PORTB.
RS is connected to B5, EN to B6 and RW to B7.
I think the delays are for a sufficient duration. Kindly check if my initialization sequence is correct.
Also, I have made the circuit on a breadboard. So I could post that picture if required.


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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <p32xxxx.h>
#include <plib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// DEVCFG3:
#pragma config IOL1WAY  = OFF       // Peripheral Pin Select Configuration, allow mult reconfig
#pragma config PMDL1WAY = OFF     // Peripheral Module Disable Config, allow mult reconfig
// DEVCFG2:
#pragma config FPLLODIV = DIV_2     // PLL Output Divider
#pragma config FPLLMUL  = MUL_20    // PLL Multiplier
#pragma config FPLLIDIV = DIV_2     // PLL Input Divider
// 8MHz / 2 * 20 / 2 = 40MHz
// DEVCFG1:
#pragma config FWDTEN   = OFF       // Watchdog Timer
#pragma config WDTPS    = PS1       // Watchdog Timer Postscale
#pragma config FCKSM    = CSDCMD    // Clock Switching & Fail Safe Clock Monitor
#pragma config FPBDIV   = DIV_1     // Peripheral Clock divisor
#pragma config OSCIOFNC = OFF       // CLKO Enable
#pragma config POSCMOD  = OFF       // Primary Oscillator
#pragma config IESO     = OFF       // Internal/External Switch-over
#pragma config FSOSCEN  = OFF       // Secondary Oscillator Enable (KLO was off)
#pragma config FNOSC    = FRCPLL    // Oscillator Selection
// DEVCFG0:
#pragma config CP       = OFF       // Code Protect
#pragma config BWP      = ON        // Boot Flash Write Protect
#pragma config PWP      = OFF       // Program Flash Write Protect
#pragma config ICESEL   = ICS_PGx2  // ICE/ICD Comm Channel Select
#pragma config JTAGEN   = OFF       // JTAG Enable
#pragma config DEBUG    = OFF       // Background Debugger Enable
 
#define SYS_FREQ 40000000uL
#define RS LATBbits.LATB5
#define EN LATBbits.LATB6
#define RW LATBbits.LATB7
#define CHECKBIT(x,b) x&(1<<b)      //Checks bit status
#define SETBIT(x,b) x|=(1<<b)       //Sets the particular bit
#define CLEARBIT(x,b) x&=~(1<<b)    //Sets the particular bit
#define TOGGLEBIT(x,b) x^=(1<<b)    //Toggles the particular bit
#define Line1 0x80
#define Line2 0xC0
int t1=0;
unsigned int i=0,j=0;
void delay(void);
void initbinary(void);
void delay1(unsigned int num)
{
    for(i=0;i<num;i++)
    {for(j=0;j<10000000;j++)
        {Nop();}}
 
}
void toggle(void)
{  
     EN=1;
     delay();
     EN=0;
     delay();
}
void go2line1(int position) // Function to go to a particular position
{
    RS=0;
    RW=0;
    EN=0;
    PORTA=(Line1 | position)>>4;
    toggle();
    PORTA=(Line1 | position);
    toggle();
    
}
void lcd_putchar(unsigned char str) // Function to display a string on the lcd
{   RW=0;
    EN=0;
    PORTA=(str&0xF0);
    RS=1;//To enable data mode
    toggle();
    delay();
    PORTA=(str&0x0F);
    toggle();
    delay();
    delay();
}
 
void check_busy(void)
{//checks if lcd is busy. If D7 is high the LCD is in the busy state
    TRISA=0xFFFF;//setting port a as input port
    RW=1;//Enabling Read Mode
    RS=0;//Enabling register select for command mode
}
void init(void);
 
int main()
{
    ANSELA=0b00000;//Enabling PORTA as digital
    ANSELB=0x0000;//Enabling PORTB as digital
   SYSTEMConfigPerformance(SYS_FREQ);
    INTEnableSystemMultiVectoredInt();
 
   mPORTASetPinsDigitalOut(BIT_0 | BIT_1 | BIT_2 | BIT_3 );
    mPORTBSetPinsDigitalOut( BIT_5 | BIT_6 | BIT_7 | BIT_9);
     OpenCoreTimer(40000000);
while(1)
{
    EN=0;
    RW=0;//enabling write mode
    RS=0;//enabling command mode for register select
   // PORTA=(0x28 & 0xF0);
   // PORTA=0b11111;
   j=0;
   toggle();
   initbinary();
   // PORTA=0x0E;
   // init();
    // toggle();
    //init();
//    RW=0;EN=0;
//    RS=0;
//    //Initalizing CGRAM address
//    PORTA=(0x80 & 0xF0)>> 4;
//    toggle();
//    delay();
//    PORTA=(0x80 & 0x0F);
//    toggle();
//    delay();
//     go2line1(3);
//     lcd_putchar('a');
 
//    RS=1;//To enable the data mode
 
////Sending character A
//    PORTA=(0x45 & 0xF0);
//    toggle();
//    delay();
//PORTA=(0x45 & 0x0F);
//toggle();
//delay();
}
 while(1)
        {
            Nop();
        }
 
    return;
 
}
 
//Coretimer works at frequency of 20MHz, So current delay function is set to 0.5ms
void delay(void)
{
    WriteCoreTimer(0);
        j=ReadCoreTimer();
        while(j<10000000) j=ReadCoreTimer();
 
}
 
void init(void)
{
//    TRISA=0x0000;//setting porta as an output port
//    TRISB=0x0000;//setting portb as an output port
    EN=0;
    RW=0;//enabling read mode
    RS=0;//enabling command mode for register select
    PORTA=(0x28 & 0xF0);
    toggle();
    //delay();
    PORTA=(0x28 & 0x0F);
    toggle();
   // delay();
    PORTA=0x0E;//writing value for cursor blink on data lines
    toggle();
//Enabling the LCD - Will work only when there is a H-L transition
 
}
 
void initbinary(void)
{
    EN=0;
    RW=0;
    RS=0;
    //Initializing four bit mode of operation
//Passing command 0x28 for 4 bit mode of operation
    PORTA=0b00010; 
    toggle();
    PORTA=0b01000;
    toggle();
//Passing 0x0E for cursor blink
    PORTA=0b01110;
    toggle();
}

 
Last edited by a moderator:

LCD are very slow devices (compared to the speed of modern processors) and require delays between each write (if too fast one gets random characters on the display), e.g. I use 1mSec

I would tend to use a timer rather than a delay loop as in your code

this works driving the LCD of a Microchip Explorer 16 dev board
Code:
// lcd.c -  Explorer 16 - functions for the PC1602-J lcd display 8-bit mode
//
// see http://www.repairfaq.org/filipg/LINK/F_LCD_progr.html

#include "hardware.h"
#include "timer.h"
#include "lcd.h"

// LCD display ports etc
#define LCDdata LATE					// data port
#define LCDdataEnable	TRISE
#define RS LATBbits.LATB15				// RS bit in LCDstatus
#define RW LATDbits.LATD5				// read/write bit in LCDstatus
#define E  LATDbits.LATD4   			// enable bit in LCDstatus
#define Eenable TRISDbits.TRISD4
#define ERSenable TRISDbits.TRISD5
#define RWenable TRISBbits.TRISB15

void lcd_delay() { mSecDelay(1); }  // if LCD does not work make this longer

// Write a nibble to the LCD
// may have to adjust delays to suit the processor and clock
void lcdNibble(int n)
{
	lcd_delay();
    LCDdata=n;
	lcd_delay();
    E=1;					// take clock E high 
	lcd_delay();
    E=0;
	lcd_delay();
 }

// Write a Control Command to the LCD
// This is written as two nibbles
void lcdCmd(int c)
{
 	RS=0;			        // Take RS pin low for command
	lcdNibble(c);			        // Makeup Lower Nibble
}

// write a data byte to LCD
int lcdPutchar(int d)
{
//    printf("%c", d);
	RS=1; 				// Take RS pin high for data
	lcdNibble(d);		            // Makeup Lower Nibble
    return 1;
}

// Initialise the LCD in 4bit Mode
void lcdInit()
{
	E=0;				// take E low
 	RS=0;				// Take RS pin low for command
 	RW=0;				// Take RS pin low for command
    // set RS, RW and E bits as output
	Eenable =0;
	ERSenable =0;
	RWenable =0;
    LCDdataEnable &= 0x0;          // set bits 0-3 output for data
	lcdNibble(0x3);		// This put the LCD into Soft Reset 
	lcdNibble(0x3);
	lcdNibble(0x3);
	lcdNibble(0x2);
	lcd_delay();
//	lcdCmd(0x28);			// 2 line, 4 bit mode 
	lcdCmd(0x38);			// 2 line, 8 bit mode 
	lcd_delay();
    lcdCmd(0x6);			// increment cursor after each write
	lcd_delay();
    lcdCmd(0x1);			// clear display
	lcd_delay();
    lcdCmd(0x2);			// home
	lcd_delay();
    lcdCmd(0xF);			// turn disply on
	lcd_delay();
}
 

You need to find out if your display needs to be powered from 5V - if so it is no use using 3.3V.

The reason your I/O lines only go to 3.3V is you haven't set the open drain register using mPORTAOpenDrainOpen(0x00ff) for example.

Your code doesn't seem to do much - it gets stuck in a while(1) loop calling initbinary()

You need to carefully check the datasheet for the LCD - they can be quite ambiguous and contradictory. I was programming a 2x8 one recently (with a PIC32) and while some commands seem to say they take 38us, elsewhere it says they take up to 4ms. Also, for some reason the initialisation of the mode must be done twice on my display - again this is mentioned in the data sheet in one place but not in others.

Keith.
 

I connected pull up resistors at the 5v pins but surprisingly my LCD was not drawing more than 3.3V(which is the voltage at which the PIC is operating.)I don't know why this happened.
I decided to use the lcd at 3.3V then. The code is as shown below. (Many sections have been commented out.)
The LCD has been connected on PORTA(from A0-A3)
The connections for RS, EN and RW are on PORTB.
RS is connected to B5, EN to B6 and RW to B7.
I think the delays are for a sufficient duration. Kindly check if my initialization sequence is correct.
Also, I have made the circuit on a breadboard. So I could post that picture if required.


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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <p32xxxx.h>
#include <plib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// DEVCFG3:
#pragma config IOL1WAY  = OFF       // Peripheral Pin Select Configuration, allow mult reconfig
#pragma config PMDL1WAY = OFF     // Peripheral Module Disable Config, allow mult reconfig
// DEVCFG2:
#pragma config FPLLODIV = DIV_2     // PLL Output Divider
#pragma config FPLLMUL  = MUL_20    // PLL Multiplier
#pragma config FPLLIDIV = DIV_2     // PLL Input Divider
// 8MHz / 2 * 20 / 2 = 40MHz
// DEVCFG1:
#pragma config FWDTEN   = OFF       // Watchdog Timer
#pragma config WDTPS    = PS1       // Watchdog Timer Postscale
#pragma config FCKSM    = CSDCMD    // Clock Switching & Fail Safe Clock Monitor
#pragma config FPBDIV   = DIV_1     // Peripheral Clock divisor
#pragma config OSCIOFNC = OFF       // CLKO Enable
#pragma config POSCMOD  = OFF       // Primary Oscillator
#pragma config IESO     = OFF       // Internal/External Switch-over
#pragma config FSOSCEN  = OFF       // Secondary Oscillator Enable (KLO was off)
#pragma config FNOSC    = FRCPLL    // Oscillator Selection
// DEVCFG0:
#pragma config CP       = OFF       // Code Protect
#pragma config BWP      = ON        // Boot Flash Write Protect
#pragma config PWP      = OFF       // Program Flash Write Protect
#pragma config ICESEL   = ICS_PGx2  // ICE/ICD Comm Channel Select
#pragma config JTAGEN   = OFF       // JTAG Enable
#pragma config DEBUG    = OFF       // Background Debugger Enable
 
#define SYS_FREQ 40000000uL
#define RS LATBbits.LATB5
#define EN LATBbits.LATB6
#define RW LATBbits.LATB7
#define CHECKBIT(x,b) x&(1<<b)      //Checks bit status
#define SETBIT(x,b) x|=(1<<b)       //Sets the particular bit
#define CLEARBIT(x,b) x&=~(1<<b)    //Sets the particular bit
#define TOGGLEBIT(x,b) x^=(1<<b)    //Toggles the particular bit
#define Line1 0x80
#define Line2 0xC0
int t1=0;
unsigned int i=0,j=0;
void delay(void);
void initbinary(void);
void delay1(unsigned int num)
{
    for(i=0;i<num;i++)
    {for(j=0;j<10000000;j++)
        {Nop();}}
 
}
void toggle(void)
{  
     EN=1;
     delay();
     EN=0;
     delay();
}
void go2line1(int position) // Function to go to a particular position
{
    RS=0;
    RW=0;
    EN=0;
    PORTA=(Line1 | position)>>4;
    toggle();
    PORTA=(Line1 | position);
    toggle();
    
}
void lcd_putchar(unsigned char str) // Function to display a string on the lcd
{   RW=0;
    EN=0;
    PORTA=(str&0xF0);
    RS=1;//To enable data mode
    toggle();
    delay();
    PORTA=(str&0x0F);
    toggle();
    delay();
    delay();
}
 
void check_busy(void)
{//checks if lcd is busy. If D7 is high the LCD is in the busy state
    TRISA=0xFFFF;//setting port a as input port
    RW=1;//Enabling Read Mode
    RS=0;//Enabling register select for command mode
}
void init(void);
 
int main()
{
    ANSELA=0b00000;//Enabling PORTA as digital
    ANSELB=0x0000;//Enabling PORTB as digital
   SYSTEMConfigPerformance(SYS_FREQ);
    INTEnableSystemMultiVectoredInt();
 
   mPORTASetPinsDigitalOut(BIT_0 | BIT_1 | BIT_2 | BIT_3 );
    mPORTBSetPinsDigitalOut( BIT_5 | BIT_6 | BIT_7 | BIT_9);
     OpenCoreTimer(40000000);
while(1)
{
    EN=0;
    RW=0;//enabling write mode
    RS=0;//enabling command mode for register select
   // PORTA=(0x28 & 0xF0);
   // PORTA=0b11111;
   j=0;
   toggle();
   initbinary();
   // PORTA=0x0E;
   // init();
    // toggle();
    //init();
//    RW=0;EN=0;
//    RS=0;
//    //Initalizing CGRAM address
//    PORTA=(0x80 & 0xF0)>> 4;
//    toggle();
//    delay();
//    PORTA=(0x80 & 0x0F);
//    toggle();
//    delay();
//     go2line1(3);
//     lcd_putchar('a');
 
//    RS=1;//To enable the data mode
 
////Sending character A
//    PORTA=(0x45 & 0xF0);
//    toggle();
//    delay();
//PORTA=(0x45 & 0x0F);
//toggle();
//delay();
}
 while(1)
        {
            Nop();
        }
 
    return;
 
}
 
//Coretimer works at frequency of 20MHz, So current delay function is set to 0.5ms
void delay(void)
{
    WriteCoreTimer(0);
        j=ReadCoreTimer();
        while(j<10000000) j=ReadCoreTimer();
 
}
 
void init(void)
{
//    TRISA=0x0000;//setting porta as an output port
//    TRISB=0x0000;//setting portb as an output port
    EN=0;
    RW=0;//enabling read mode
    RS=0;//enabling command mode for register select
    PORTA=(0x28 & 0xF0);
    toggle();
    //delay();
    PORTA=(0x28 & 0x0F);
    toggle();
   // delay();
    PORTA=0x0E;//writing value for cursor blink on data lines
    toggle();
//Enabling the LCD - Will work only when there is a H-L transition
 
}
 
void initbinary(void)
{
    EN=0;
    RW=0;
    RS=0;
    //Initializing four bit mode of operation
//Passing command 0x28 for 4 bit mode of operation
    PORTA=0b00010; 
    toggle();
    PORTA=0b01000;
    toggle();
//Passing 0x0E for cursor blink
    PORTA=0b01110;
    toggle();
}



the problem with lcd initialization. plse add the LCD commands like cursor ON,cursor shifting, and line selection......
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top