Programing an LCD

Have you got the greatest 48 bit multiplier ever conceived? Prove it - post your code here.

Moderator: phalanx

Post Reply
nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Programing an LCD

Post by nate27502 » Mon Jun 21, 2010 11:06 am

I bought the 20x4 LCD panel http://www.sparkfun.com/commerce/produc ... cts_id=256 and have been trying to get it to work.
I am trying to get 8-bit going and it seems to be hanging up. The screen shows two solid lines on lines 1 and 3 and no text. My program waits for a button push, then sends the commands to initialize and display some text, the problem is that nothing happens.
Thanks in advance.

waltr
Support Volunteer
Posts: 2823
Joined: Tue Sep 08, 2009 12:07 pm
Location: Philadelphia, USA

Re: Programing an LCD

Post by waltr » Mon Jun 21, 2010 12:02 pm

Which PIC are you using?
What does your code look like?
What experience do you have writing code for PICs?
What are the connections? Schematic?
Are you using code from one of the many posted on the Web?

nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Re: Programing an LCD

Post by nate27502 » Mon Jun 21, 2010 12:35 pm

I'm using a pic16f690 and the pickit2
I have written some code but nothing major. I know java pretty well but I'm using C to program the chip. The interface seemed like it would be pretty easy. Seemed like it could be as simple as setting the diffrent pins, then activating the enable pin. That didn't work.
As far as the connections, I wired up the pickit2's low pin count board to a breadboard and stuck the LCD in.
I added names for all the connections in the program but if you need more info please let me know.
Sorry for the code, it is a little crude and probably confusing.
I found many sites that basically said the same thing, to set the control pins and run through a list of commands.
I didnt find any that said 'here is the code to run your chip in c'.

//LCD control program......... maybe

#include <pic.h> // Include HITECH CC header file

__CONFIG (INTIO & WDTDIS & PWRTDIS & MCLRDIS & BORDIS
& UNPROTECT & IESODIS & FCMDIS ); //Internal clock, Watchdog off, MCLR off, Code Unprotected

#define LCD_RS RC1
#define LCD_RW RC0
#define LCD_EN RA0 //ENABLE //CH1-RA0
#define LCD_DB7 RA4 //BUSY FLAG //CH3-RA4
#define LCD_DB6 RA5
#define LCD_DB5 RA3
#define LCD_DB4 RC5
#define LCD_DB3 RC4
#define LCD_DB2 RC3
#define LCD_DB1 RA1 //CH2-RA1
#define LCD_DB0 RA2
#define LED RC2
#define Button RA3

//thinking that the pic could be going too fast for the lcd to recognize, I decided to slow it down.
//this should run the chip at 250kHz
#define IRCF0 0
#define IRCF1 1
#define IRCF2 0

void LCD_wait(void); //Establish pause routine function
void LCD_write(unsigned char);
void LCD_command(unsigned char);
bit testbit(unsigned char, int);

void LCD_wait(void)
{
LED = 1;
TRISA4 = 1; //make A4 (the DB7 pin or busy flag on the lcd) an imput
LCD_EN=0;
LCD_RS=0;
LCD_RW=1;
/*
//failed attempt at a recursive wait script
LCD_EN=1;
static bit busynflag = 0;
busynflag = RA5;
LCD_EN=0;
if(busynflag == 1)
{
LCD_wait();
}
*/
static bit busyflags = 0;
LCD_EN=1;
LCD_EN=0;
while(RA5==1)
{
LCD_EN=1;
LCD_EN=0;
}
LCD_EN=0;
TRISA4 = 0;
LED = 0;
}

//writes a letter the the LCD
void LCD_write(unsigned char letter)
{
LCD_wait();
LCD_RS = 1;
LCD_RW = 0;
LCD_DB0 = testbit(letter, 0);
LCD_DB1 = testbit(letter, 1);
LCD_DB2 = testbit(letter, 2);
LCD_DB3 = testbit(letter, 3);
LCD_DB4 = testbit(letter, 4);
LCD_DB5 = testbit(letter, 5);
LCD_DB6 = testbit(letter, 6);
LCD_DB7 = testbit(letter, 7);
LCD_EN=1;
LCD_EN=0;
}

//sends a command to the LCD
void LCD_command(unsigned char letter)
{
LCD_wait();
LCD_RS = 0;
LCD_RW = 0;
LCD_DB0 = testbit(letter, 0);
LCD_DB1 = testbit(letter, 1);
LCD_DB2 = testbit(letter, 2);
LCD_DB3 = testbit(letter, 3);
LCD_DB4 = testbit(letter, 4);
LCD_DB5 = testbit(letter, 5);
LCD_DB6 = testbit(letter, 6);
LCD_DB7 = testbit(letter, 7);
LCD_EN=1;
LCD_EN=0;
}

//this method will return the bit at a specific location, splitting up a char into bits.
//sorry for the useless variable names but I didnt know what to call them.
bit testbit(unsigned char f, int loc)
{
static int tp, wb;
static bit r;
tp = 0b10^loc;
wb = f % tp;
r = wb/tp;
return (r==1);
}

void main(void)
{
ANSEL = 0; // Intialize A/D ports off
CM1CON0 = 0; // Initialize Comparator 1 off
CM2CON0 = 0; // Initialize Comparator 2 off

PORTC = 0x00; //Clear PortC port
TRISC = 0x00; //All PortC I/O outputs

PORTA = 0x00; //Clear PortA port
TRISA = 0x00; //All PortA I/O outputs

/*
//SET OF INSTRUCTIONS BY THE WEBSITE http://www.8052.com/tutlcd
LCD_command(0x38); //function set, 8 bits, 2 lines
LCD_command(0x0E); //0x08 and turn on
LCD_command(0x06); //move to the right
//LCD_command(0x01); //clear the screen
LCD_write(0x48); //H
LCD_write(0x49); //I
*/

//INSTRUCTIONS GIVEN BY MFGR http://www.sparkfun.com/datasheets/LCD/GDM2004D.pdf
/*LCD_wait();
LCD_command(0x01); //function set, 8 bits, 2 lines
LCD_command(0x38); //0x08 and turn on
LCD_command(0x03); //move to the right
LCD_command(0x10); //clear the screen
LCD_command(0x38); //
*/


/*
//I tried to just spam the screen with text but nothing showed up.
LCD_write(0x48); //H
LCD_command(0xC6); //move to 40
LCD_write(0x48); //H
LCD_command(0x9A); //move to 14
LCD_write(0x48); //H
LCD_command(0xDA); //move to 54
LCD_write(0x48); //H
LCD_command(0x87); //move to 01
*/

LED = 1;
TRISA3 = 1; //make RA3 an imput
//this section lets the LCD initialize and waits for a button push a few times.
while(Button == 0)
{
}
while(Button == 1)
{
}
LED = 0;
while(Button==0)
{
}
while(Button == 1)
{
}
LED = 1;
while(Button == 0)
{
}
while(Button == 1)
{
}
LED = 0;
while(Button==0)
{
}
while(Button == 1)
{
}
LED = 1;
TRISA3 = 0; //makes RA3 an output again

LCD_RS = 0;
LCD_RW = 0;
LCD_DB7 = 0;
LCD_DB6 = 0;
LCD_DB5 = 1;
LCD_DB4 = 1;
LCD_DB3 = 1; //8 BIT, 2 LINES, 5X8 DISPLAY
LCD_DB2 = 0;
LCD_DB1 = 0;
LCD_DB0 = 0;
LCD_EN = 1;
LCD_EN = 0;

LCD_RS = 0;
LCD_RW = 0;
LCD_DB7 = 0;
LCD_DB6 = 0;
LCD_DB5 = 0;
LCD_DB4 = 0;
LCD_DB3 = 1; //TURNS ON DISPLAY
LCD_DB2 = 1;
LCD_DB1 = 1;
LCD_DB0 = 0;
LCD_EN = 1;
LCD_EN = 0;

LCD_RS = 0;
LCD_RW = 0;
LCD_DB7 = 0;
LCD_DB6 = 0;
LCD_DB5 = 0;
LCD_DB4 = 0;
LCD_DB3 = 0; //INCREMENT THE ADDRESS
LCD_DB2 = 1;
LCD_DB1 = 1;
LCD_DB0 = 0;
LCD_EN = 1;
LCD_EN = 0;

LCD_RS = 1;
LCD_RW = 0;
LCD_DB7 = 0;
LCD_DB6 = 1;
LCD_DB5 = 0;
LCD_DB4 = 0;
LCD_DB3 = 1; //H
LCD_DB2 = 0;
LCD_DB1 = 0;
LCD_DB0 = 0;
LCD_EN = 1;
LCD_EN = 0;

LCD_RS = 1;
LCD_RW = 0;
LCD_DB7 = 0;
LCD_DB6 = 1;
LCD_DB5 = 0;
LCD_DB4 = 0;
LCD_DB3 = 1; //I
LCD_DB2 = 0;
LCD_DB1 = 0;
LCD_DB0 = 1;
LCD_EN = 1;
LCD_EN = 0;


while(1==1)
{
//dont screw up
//stay here in the program
}
} //end main

waltr
Support Volunteer
Posts: 2823
Joined: Tue Sep 08, 2009 12:07 pm
Location: Philadelphia, USA

Re: Programing an LCD

Post by waltr » Mon Jun 21, 2010 5:36 pm

The one thing I see is the port outputs:

#define LCD_DB6 RA5

LCD_DB6 = 0;

In assembler code this is really:
temp = portB;
bcf temp, 6;
portB = temp;

So it reads all the bits in port B clears bit 6 and write out to all port B pins. This is known as RMW (read-modify-write) and if a pin is loaded it may not read as the value as what is output. So if a pin output was set to a 0 and there is a pull-up it may read as a 1 which is then written back out. This is a common problem when using the base-line and mid-range PICs. Section 15.1 in the data sheet give a short explanation and one example. A better explanation of this problem is in the Mid-range Reference Manual, Chapter 9, sections 9.1 and 9.10.1. And a much, much better discussion here: http://www.microchip.com/forums/tm.aspx ... e=1#478014

Ok, some more basic questions:
Have you gotten a simple LED blink program to work with this board and processor?
Have you stepped through each line of code in the MPLAB SIMulator and verified the code is doing what you want?
Have you checked that the output pins are doing what they should? The PICKit2's stand alone tool has a Logic Analyzer feature that works very well. It can measure the logic levels and timing of outputs.
What other troubleshooting/debugging steps have you taken?

I also suggest learning enough PIC assembler so that you can look at code examples and get an understanding of what they do and then to write them in C.
Good luck and keep plugging at this.

nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Re: Programing an LCD

Post by nate27502 » Tue Jun 22, 2010 8:26 am

I ran the simulator but couldnt tell much. It ran thru the program as expected.
However when I ran the logic tool and compared it with the commands, LCD_DB5 aka RA3 wasnt going low. I attached the screen in case it helps. Nearly all of the commands needs that line low so that might be the problem. Is this the pull up error you were talking about?
thanks again.
Attachments
Logic.jpg
Logic output from the simulator
Logic.jpg (46.72 KiB) Viewed 5493 times

waltr
Support Volunteer
Posts: 2823
Joined: Tue Sep 08, 2009 12:07 pm
Location: Philadelphia, USA

Re: Programing an LCD

Post by waltr » Tue Jun 22, 2010 8:38 am

That is a good start in determining what is wrong. This is not showing RMW issue as the simulator does actually read a real pin and has no idea that there may be a pull-up on the pin so I think its a code problem. Go back to the Simulator and step through the lines of code that write to PortA and check that your code does set RA3 low (View the SFR's and look at PORTA).

To see a real RMW issue you need to look at the real PIC's pin. Which is why it is hard to troubleshoot as it only happens in real hardware.

But I see that RA3 is also used for the button which I guess has a pull-up. If you set the PORT Stimulus to set RA3 high then yes, this is a RMW issue you are seeing in the MPLAB simulator. Can you use a different pin for the button? Maybe one in port B?
If not then use a shadow register for PortA. Set the bits to high or low in the shadow register then write the shadow register out to port A. This eliminates the reading of the port pins.

I did find this project that use a similar PIC and an 8-bit interface for an HD44780 controller. There may be some help in the schematic and code.
http://www.piclist.com/techref/microchi ... oll-tr.htm

Edit:

I missed this at first but when I stepped through your code the TRISA3 did not clear to a 0 (line 187).
Look at Note 1 on page 59 under REGISTER 4-2 of the data sheet.
Port RA3 is ALWAYS an input and NEVER an output. This is due to this pin can also be /MCLR.
You need to use a different pin to output to the LCD. Its perfect to use for the button since it can only be an input.

nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Re: Programing an LCD

Post by nate27502 » Tue Jun 22, 2010 9:19 am

I disabled the button in the code and the error persists. Its a button that comes on the PicKit2's demo board and it does have a hardware pullup resistor. Referring to the earlier post in the past I have gotten the same board to light up LED's. Most of the experience I have though is from a book I bought a while ago. I dont have access to a logic analizer and I think a voltmeter wouldnt register.

waltr
Support Volunteer
Posts: 2823
Joined: Tue Sep 08, 2009 12:07 pm
Location: Philadelphia, USA

Re: Programing an LCD

Post by waltr » Tue Jun 22, 2010 9:22 am

I think you missed my post above. Maybe I was editing while you where posting.

The problem is port RA3 as explained in section 4.1 of the data sheet.
I dont have access to a logic analizer
Yes you do. You have a PICKit2.
Download and install the Stand alone PICKit2 programming utility from Microchip. It has a Logic Analyzer feature that works very well for three inputs.

nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Re: Programing an LCD

Post by nate27502 » Tue Jun 22, 2010 10:45 am

Ok well new development, this whole time my screen has been displaying two solid black lines across lines 1 and 3. With the button press section commented out I noticed that the screen did print out HI right before it was covered with the black line. When I uncommented the button section the screen shows the lines before the HI gets printed and doesnt go back. When I recommented the section the whole screen is a dim solid black. Any idea whats causing that?

As far as the logic analyzer on the PicKit2 I am powering the board via the usb and the program doesnt allow any change to the vcc after it starts, which is when the whole rutine starts. I got around that using the button press. I have the screen and demo board from the PicKit hooked up to a breadboard and the wires get confusing when moving them around to try to get the right pin on the analyzer channel. If it helps I'll connect the PicKit2 to it's own header and do it that way.

nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Re: Programing an LCD

Post by nate27502 » Tue Jun 22, 2010 10:56 am

Aaaaahhhhh I found the problem with the whole screen going dim solid black. I mixed up the wire for DB5 with DB6.
So now I can see HI displayed right before two lines cover it up.

waltr
Support Volunteer
Posts: 2823
Joined: Tue Sep 08, 2009 12:07 pm
Location: Philadelphia, USA

Re: Programing an LCD

Post by waltr » Tue Jun 22, 2010 11:55 am

Woohoo...progress.
This is typical of development so keep going.

nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Re: Programing an LCD

Post by nate27502 » Tue Jun 22, 2010 12:56 pm

Do you know what is causing the lines to appear? Or nothing to work after they do?

waltr
Support Volunteer
Posts: 2823
Joined: Tue Sep 08, 2009 12:07 pm
Location: Philadelphia, USA

Re: Programing an LCD

Post by waltr » Tue Jun 22, 2010 1:21 pm

Not off-hand but a first guess is either timing or a glitch on on output (LCD input).

Go over the Data sheet for the LCD again and check against what your code does.

nate27502
Posts: 13
Joined: Mon Jun 21, 2010 11:02 am

Re: Programing an LCD

Post by nate27502 » Tue Jun 22, 2010 1:39 pm

I got it to work. I thought I called the function LCD_wait() before starting anything. Nope.
But now I'm working on the function LCD_write() and probably the command function too.
Thanks

millwood
Posts: 115
Joined: Thu Jul 02, 2009 2:09 pm

Re: Programing an LCD

Post by millwood » Mon Jul 05, 2010 7:17 am

your code looks disorganized and hard to be reused later.

In general, a lcd driver involves a few functional blocks:

1) lcd initialization: where you set up the pins and build a logic layer for all future lcd-related functions. this is where most people got stuck, because of timing issues, or incorrect handling of mode choices.

2) send a byte to the lcd, either a command or data: this is the basic building block of communicating with the lcd.

4) send a string to the lcd: essentially a repetition of 2), but sending a series of data bytes.

Once you have that laid out, your programming / debugging would be much easier and the code generated should be quite re-usable and portable.

Code: Select all

//this method will return the bit at a specific location, splitting up a char into bits.
//sorry for the useless variable names but I didnt know what to call them.
bit testbit(unsigned char f, int loc)
{
static int tp, wb;
static bit r;
tp = 0b10^loc;
wb = f % tp;
r = wb/tp;
return (r==1);
}
a simpler piece of code, faster too, might be:

Code: Select all

//this method will return the bit at a specific location, splitting up a char into bits.
//sorry for the useless variable names but I didnt know what to call them.
#define testbit(f, loc) (((f) & (1<<(loc)))? 1: 0)
I would actually use a mask (=1<<loc), instead of loc.

Post Reply