• We recently switched our forum platform. If you experience any issues please email support@crystalfontz.com

PIC18F45J10 Microprocessor to CFAH1604A-NYG-JP# LCD

vthokie

New member
Hey guys,

I am trying to interface a Microchip PIC18F45J10 to the Crystalfontz CFAH1604ANYGJP# (16x4) LCD. I am having difficulty with the initialization of the screen. When I power the screen on, I obviously get lines 1 and 3 as completely filled in dark (which I believe is normal) so I adjust the contrast POT so that I can just about see the dark lines (which I use to determine whether the screen is initialized or not). I am using the initialization codes from the datasheet for 4-bit mode, and the attachments are as follows (you can see them in the attached .c file as well):

Vss to GND
Vdd to +5V
VO to 10k-ohm POT

LCD DB7 to PIC RD7
LCD DB6 to PIC RD6
LCD DB5 to PIC RD5
LCD DB4 to PIC RD4

LCD EN to PIC RD3
LCD RS to PIC RD2
LCD RW to GND

I have tried everything from double checking time delays and init codes and adjusting the contrast while running to see if the screen has in fact been initialized. However, everytime I run the program, the LCD screen remains in its original state when powered on (lines 1 and 3 black). I think I'm missing something small but I cannot tell what it is. I am using Microchip MPLab C18 compiler to generate the hex file, which I then put onto the PIC18 using the PICkit 2 programmer (just in case someone needs to know that when looking at my c-code). Could someone please take a look at my attached .txt file which contains my c-code and see where I'm going wrong?

Thank you in advance!
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 

Attachments

The proper init sequence is:
0x3 (single nibble),
0x3 (single nibble),
0x3 (single nibble),
0x28 (double nibble)

You are using 0x3, 0x28, 0x28.
 

vthokie

New member
I don't understand how that's the init sequence only becase if you look at the spec (datasheet) for the LCD, the sequence is:

0x3
0x28
0x28

I know that 0x3, 0x3, 0x3, 0x28 is usually the sequence for the Hitatchi controller, but check out the spec sheet I attached. It states something different for this "initialization of LCM".

What are your thoughts after reading the spec sheet I attached? Is the total init sequence as you stated or will it be something different (either way, should the code I posted work the way it is and simply changing around the nibbles to send)?

Thank you!
 

Attachments

Last edited:
I see that the CFAH1604A data sheet has a nonstandard init sequence, compared to all of the other HD44780 compatible displays I've seen. The sequence
0x3
0x3
0x3
0x28
is the standard HD44780 mode set for 4-bit, and I've used it successfully. You should try it, and see if it works for you.

Also, that is only the mode-set part of the init. The other commands in your code look ok (clear, cursor set, disp on, etc).
 

vthokie

New member
Thanks for the input. I tried the 0x3, 0x3, 0x3, 0x28 (followed by the other init commands), but it still has not worked. I'm not sure if I'm strobing the LCD correctly, or if I need to strobe it initially before waiting and then sending commands, etc? I attached an updated version which includes the init sequence you posted along with the rest of my init sequence.

Any other suggestions?
 

Attachments

The code looks like it ought to work. Have you checked that your signals are reaching the display ok? Do you have a scope to see how they look? If not, what kind of test equipment do you have?
 

vthokie

New member
Unfortunately I don't have any test equipment. (poor college student) I did notice one thing though. If I go back to my original code, and add a strobe before the 60ms waiting timeframe, and then continue with the execution of the initialization, the two black lines on my screen turn completely black and the cursor sits and blinks about in the middle of the third line. I know that this is obviously not correct because the first and third lines light up black (even if I turn the contrast mostly down), but does this strike you as odd at all or is it just because the LCD is mad at me for not initializing it correctly?

Again, thanks for all your help! I'm really anxious about getting this to work, but it doesn't seem to be going well.
 
Yes, that does seem odd. When you make a change to your code, and then try it on the display, are you killing the +5v to the display and then turning it on, or do you just leave it on the whole time?

So, you don't have a cheap voltmeter, or a bare LED and a 1K ohm resistor?

I suspect the signals are not correct to the LCD inputs.

Can you single step thru your code with a debugger?
 

vthokie

New member
Yes, every time I re-load my PIC, I unplug and then plug the LCD back in before releasing the PIC from reset. As it is right now, the PIC is running off the PICkit2 programmer for voltage (3.3V) and the LCD is connected to it's own 5V source, but they are sharing the same ground. I even tried switching the ports from port D to port A on the PIC, and still no luck.

I do actually have a voltmeter, but I didn't think that would help me much because the signals would be traveling too fast to measure.
 
I do actually have a voltmeter, but I didn't think that would help me much because the signals would be traveling too fast to measure.
That's why I asked if you could single step. You need to stop the I/O long enough to take a voltage reading on the pins. You could do this by calling a function that waits for an unused port pin to change state before continuing. Then you could put a pushbutton (to ground, with a pullup resistor) on that pin to control your program flow. You could call this wait() function before the delay in your E-high and E-low strobe function.

This would at least tell you whether your signals are what you expect.

Hint: in the wait function, if you are waiting for a 0 input, first wait for a 1 state before accepting a 0 state, so that you don't see the same button push from the last call. I can give you a code sample, if you need one.
 
Last edited:

vthokie

New member
That's a good idea. I haven't got the time to do that this week, so that's why I was wondering if maybe it could have just been a quick fix. (it's always an eye-opener when you have someone else look at your code...amazing how many things can change).

I am going to try and get that done next week, I'll keep you posted on my findings. Again, thanks for all your help!
 

vthokie

New member
Success!

I made some rookie mistakes, the most punishing one of which was to connect the LCD to a low voltage driver port on the PIC. The port I had it hooked up to was only designed (as per the datasheet) to be a detect/signal port, and not a full fledged driver (oops). There were some other minor things in the code (such as the delays and the compiler not recognizing "i++") which killed my code, but overall, displaying a character now works. The only thing left is to figure out why I have to call the initialize function twice before actually successfully initializing the LCD.

I do have one more question. Do you happen to know how to pass a string to the LCD? Here's what I have so far:

void lcd_puts(const char* theString)
{
while(*theString)
{
lcd_putChar(*theString);
theString = theString + 1;
}
}

The idea is that you can do something like "lcd_puts("test_string");" which calls this function and will pass individual bytes into the lcd_putChar function. However, so far, this is both locking up and (with a slight modification) displaying garbage.

Any suggestions?
 
In your init sequence, which mode-set command sequence are you using (3,3,3,0x28 or 3,0x28,0x28)? Have you tried both? Else, I don't know why it would require two passes. AFAIK, the HD44780 type controllers can only be mode-set once per session (i.e. you can't change modes from/to 8-bit/4-bit without killing Vcc to reset the chip), so the 2nd mode-set should have no effect. Or maybe that is not true with this controller chip, considering that it deviates from the old init sequence in the data sheet.

Your string output function looks good, I have used one like that myself. I suspect something in your compiler, especially if it gags on "x++". Does the compiler generate an assembly code listing file that you can inspect? Maybe the code is not being compiled correctly, and you might be able to see why in the listing. Maybe you should get rid of the "const" in "const char * theString", as it may imply that your string is in code space instead of data space.
 

vthokie

New member
Hm, interesting. When I pass this in main:

lcd_writeString("test");

into my function, I found a few different things. First, here is my code:

void lcd_writeString(unsigned char *string)
{
unsigned char temp;

temp = *string;
lcd_write(temp);
//*string++;
}

Notice the commented increment. If I run the code as is (withOUT string++), the code outputs "T" to the LCD. This is close, but it should be outputting "t" (little t).

Now if I add the *string++ to the code, it outputs some garbage character. This doesn't make sense to me because the code is EXACTLY the same (with the exception of *string++, but that's not until after the character is printed).

Crazy things. Any ideas?
 
Yeah. Look at the assembly listing to see what the code is really doing.

If you don't have a debugger w/ single step capability, you have a hard time troubleshooting.

Also, your increment should be "string++;", not "*string++;". You want to increment the pointer, not the data.
 

vthokie

New member
Well, it appears that my code was wrong altogether. Since the PIC processor stores information in both data and program memory (and these two are not compatible), it was erroneous of me to assume that I would be able to pass a regular unsigned char to a function and have it work. After toying around with it for a while and searching the internet, I found the Microchip addendum which explained the difference between the two, and I came up with this:

void lcd_writeString(static const rom char *theString)

This will allow the function to read from the required memory space in orde to display the char* correctly. Because I did not define the string as such, the compiler was reading from the wrong memory space (thus the garbage characters).

Just thought you'd like to know! Thanks again!
 
Top