24X2 character LCD driver code

That's a standard HD44780 type module.

Have you tried runing the code in MPSIM to verify the delays? Make sure your simulation clock matches the hardware.

Best regards, Spehro Pefhany

--
"it\'s the network..."                          "The Journey is the reward"
speff@interlog.com             Info for manufacturers: http://www.trexon.com
Embedded software/hardware/analog  Info for designers:  http://www.speff.com
Reply to
Spehro Pefhany
Loading thread data ...

Hi, I'm looking for assembly code to allow me to use my 24X2 character LCD module with a PIC 16F873A microcontroller. I've googled on the subject, and spent countless hours looking through webpages with no luck. I thought I had found something, but after trying it in my project the LCD display still does not work. I've checked the contrast, but it might be in the initialization. I bought the module from Crystalfontz.com, and when I contacted them, they were little help. I do have the datasheet on this module, and I modeled my initialization routine off of the recommended routine there. The module is a CFAH2402A-YYB-JP.

If anyone could direct me to other assembly code to control this device, I would appreciate it. Also I'm going to put my code below, so the experts here can pick it apart and tell me what I've done wrong. I tried to just cut/paste the code on here, but it didn't line up right, so I just put it on a website. I'm a novice at this, but I'm willing to work hard to make myself better. -Chris

formatting link

Reply to
Chris Gentry

Chris Gentry wrote: ...

...

...

...

comp.arch.embedded probably is a more-appropriate newsgroup for your query.

You need to provide a link to a circuit diagram so people can check if your values of LCD_D4...7, your notion of contrast setting, etc are correct.

Be a little more precise about "does not work". Do you get black rectangles on line 1 when you crank the contrast? Do randomly moving blobs appear? Does it just stay plain blank?

Looking at the __LCD_INIT routine in

formatting link
it appears that P. Pemberton has not followed the correct sequence of LCD initialization instructions as shown on the second page of section 13 of your reference
formatting link
(ie, the page labeled "4-Bit Ineterface"). The correct sequence is: Wait > 15ms, send 0011, wait > 4.1 ms, send 0011, wait > .1 ms, send 0011, check BF (the busy flag), send 0010, etc. What the routine instead does is: Wait > 15ms, send 0011, send 0011, wait > 4.1 ms, send 0011, send 0011, wait > 1 ms, send 0011, send 0010, etc. It may be that Pemberton's code worked ok with some other LCD, say 16x2, or 24x1, etc, but has problems with your 24x2. Or it may be that the above is not the problem at all; I have used similar (wrong) code ok with at least two different LCD's, but another one wouldn't work until I matched the correct sequence more exactly.

-jiw

Reply to
James Waldby

Also follow the startup sequence exactly as the spec says, otherwise you will get garbage.

Reply to
Martin Riddle

I don't know if it will help, but I wrote some C under Linux to control a similar LCD module on the parallel port. It's not very beautiful - basically it goes step-by-step through the initialization sequences - but this might make it easier to understand. It is appended below.

Matt Roberds

--- /* lcd.c - Matt Roberds snipped-for-privacy@worldnet.att.net - 8/25/99 */ /* control an LCD module over the parallel port */

#include

#include #include #include

#define DATAPORT 0x0378 #define STATUS DATAPORT+1 #define CONTROL DATAPORT+2

void microdelay(int delay); void strobe(int data);

/* LCD module hookup Port addres Module PC DATA[0-7] data0-data7 data0-data7 CONTROL[0] E (enable) strobe (pin 1; inverted logic) CONTROL[2] RS (data/cmd) init (pin 16; standard logic) CONTROL[3] R/W (read/write) select (pin 17; inverted logic) */

#define ENABLE 0xfe #define DATA 0x04 #define WRITE 0xf7

void main(void) { int i; char message[256];

ioperm(DATAPORT,1,1); ioperm(STATUS,1,1); ioperm(CONTROL,1,1);

/* printf("ioperm ok\\n"); */

/* init code - parallel port */

outb(0, DATAPORT); /* zero data lines */

/* strobe low 0x01 write 0x08 command 0x00

*/

outb(0x09, CONTROL); /* disabled (strobe low), write mode, command mode */

microdelay(50);

printf("port setup OK\\n");

/* init code - LCD */

for(i=0;i

Reply to
mroberds

So in your estimation this would be good code to stick with? Someone told me my delays might not be correct, but I'm not sure how to check them in MPSIM. I can simulate it, but I don't know where it would show the correct times.

As for the contrast I get dark rectangles across the first row when I turn it up. I'm posting a little early since I haven't finished modeling the init routine off of what is in the specs, but I'm going to do that tonight, and get back to everyone here. Thanks for your help so far. -Chris

Reply to
Chris Gentry

Chris Gentry wrote:

[snip]
[snip]

Since I'm used to reading AVR assembly and don't know much about pic's I thought it all looked just awful. :) But here's an idea to try anyway - Change: MOVLW B'00110011' ; 2x 8bit resets CALL LCD_SENDINS call Delay20MS MOVLW B'00110011' ; 2x 8bit resets CALL LCD_SENDINS CALL Delay1MS MOVLW B'00110010' ; 8bit reset then 4bit reset CALL LCD_SENDINS to: MOVLW B'0011' ; 8bit reset CALL LCD_SENDIN4 call Delay20MS MOVLW B'0011' ; 8bit reset CALL LCD_SENDIN4 CALL Delay1MS MOVLW B'0011' ; 8bit reset CALL LCD_SENDIN4 CALL Delay1MS MOVLW B'0010' ; 4bit reset CALL LCD_SENDIN4 where LCD_SENDIN4 is: LCD_SENDIN4: MOVWF __LCD_TEMP0 ; Store byte in Temp 0 BCF LCD_RS ; RS low=instruction CALL __LCD_SEND4 ; Send 1 nibble CALL Delay1MS RETURN and __LCD_SEND4 is a label at line 43 in lcd_4bit.inc, ie, just before the second BCF LCD_D7 of __LCD_SEND. Note, see

formatting link
at line 108; the ini0 table corresponds to those first 4 instructions which are sent to the LCD unit via its top 4 data lines; the lower nibbles should not be sent, because the unit is not yet in 4-bit mode. Your current code has no delay between the third 8-bit reset and the 4-bit reset, while spec says to check the busy flag or wait > 39 uS. (The code in

2313s2.null.c works ok for AVR AT90S2313 board like at
formatting link
.)

What is your crystal frequency, anyway? You should check out your delay routines by blinking an LED at 1Hz or an easy-to-time .2Hz etc before trying to get the LCD to work.

That is what you get just by applying power, which gives you 8-bit interface and 1-line display. After software initialization per specs you will have a blinking cursor in first column first row, and turning up the contrast won't show any black rectangles.

-jiw

Reply to
James Waldby

Ok, I've tried that and it didn't seem to work. I worked on the code, and put everything together. I tested my delays at 5seconds worth and they are very close. My revised code is now in one file and is at :

formatting link

I think my initialization is working now, because I no longer get the solid rectangles all the way across the top. Now I am getting solid rectangles where the characters are supposed to be on line 1 and on line 2 I'm getting some weird looking characters. They look like a funny backwards 'e'. I did have the cursor on and blinking in the code, but I took that out. On the LCD the cursor was on and blinking when I had it in code. So I think it might have initialized correctly now, but something is still wrong. -Chris

Reply to
Chris Gentry

Chris Gentry wrote: ...

Did you run a test with LCD_SENDIN4 being called rather than LCD_SENDINS in the first 4 calls of LCD_INIT ?

What is your clock frequency?

Perhaps add another "GOTO $+1" or whatever the PIC code for NOP is, between setting and clearing the LCD_E bit.

-jiw

Reply to
James Waldby

Yes and it didn't seem to work. I could be wrong, but I thought that it needed the full eight bits on the first few calls because it was still in 8 bit mode, and was expecting

8 bits? I'm getting ready to try some other things, so I'll try this again with the different code. When I tried this before my code didn't turn the display back on, so that could be the problem there.

I have a 20MHz xtal.

I will try this. And it is 'NOP' on the PIC too.

Reply to
Chris Gentry

...

The display starts out in 8 bit interface mode. The 8 bit interface mode accepts bits on LCD lines D0...D7. You don't have anything connected to D0-D3 (if you hooked up properly). The low 4 bits of the first 4 commands are irrelevant don't-cares. If the first four calls use LCD_SENDINS (with 2 E strobes per call) then you are feeding the LCD 8 bytes rather than 4.

-jiw

Reply to
James Waldby

Ok, what took days to fix, finally came down to one line that I had forgot to add in LCD_PUTCH. My initialization has to be top notch now, thanks to everyone who replied to this thread. The problem however wasn't with my init routine. It was I had forgot to store the contents of the w register into LCD_TEMP before I called LCD_SENDINS from LCD_PUTCH. My routine didn't use 'w', but instead used 'LCD_TEMP' so when I sent the data it was just garbage.

Thanks to everyone who helped fix this problem. -Chris

Reply to
Chris Gentry

I redid the code to use LCD_SENDIN4 when I changed it last, and everything appears to be working fine. Thanks for your suggestions. -Chris

Reply to
Chris Gentry

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.