Interface LCD to PIC (Details inside!)

Thread Starter

jegues

Joined Sep 13, 2010
733
The PIC being used is: PIC16F877A

LCD beind used is:
NHD‐0216XZ‐FSW‐GBW

The objective is to get the LCD to display the following message,

"Bananas $0.49/lb" - for 5 seconds, followed by,

"WOW!" - which is centered on the display and blinking at a rate of once per second for 3 seconds (i.e. 500ms on 500ms off).

I'm having trouble finding information on the correct procedure to use the LCD, and a large portion of the code used in my program has been provided by our instructor.

I have a feeling that before I attempt to, writeString("Hello World!"), to the LCD I must first set the display line and place the cursor accordingly which I don't know how to do. We have been given an incomplete function called setDisplayLine(), but I'm not entirely sure in what sense it is incomplete, nor what the codes being passed to the command function represent.

Then again, I'm not even sure if that is the correct procedure to follow.

Does anyone know?

I've been looking for a data sheet, but all I've been able to find is pinouts which I already have.

See below for my code. (I appologize as the indentation is ruined when I paste it into the forum)

Thanks for the help!

Rich (BB code):
#include <htc.h>
#include <string.h>
#include "ProcessorConfiguration.h"
#include "FunctionPrototypes.h"
#include "Definitions.h"
void main(void){
 portInit();
 LCDInit();
 writeString("Hello World!");
 
}
static void interrupt isr(void){
}
//May be moved to its own .c file later
void LCDInit(void){
 E = 0; 
 delay(15); //Wait >15 msec after power is applied 
 initCommand(0x30); //command 0x30 = Wake up 
 delay(5); //must wait 5ms, busy flag not available 
 initCommand(0x30); //command 0x30 = Wake up #2 
 delay(160); //must wait 160us, busy flag not available 
 initCommand(0x30); //command 0x30 = Wake up #3 
 delay(160); //must wait 160us, busy flag not available 
 command(0x38); //Function set: 8-bit/2-line 
 command(0x10); //Cursor shift mode, S/C to the Left 
 command(0x0C); //1DCB: Display ON; Cursor OFF; Blink OFF 
 command(0x06); //Entry mode: Inc cursor and display shift off 
 clearDisplay(); 
 returnHome(); 
}
void initCommand(char theCommand){ //Cannot Utilize BF
 LCDCOMMAND = theCommand; //put command on PORTD 
 RS = RS_COMMAND; // Select Command Register 
 RWn = WRITE; // Write Mode 
 E = 1; 
 E = 0; //Clock enable: falling edge 
}
void command(char theCommand) { 
 waitForNotBusy(); 
 LCDCOMMAND = theCommand; //put command on PORTD 
 RS = RS_COMMAND; // Select Command Register 
 RWn = WRITE; // Write Mode 
 E = 1; 
 E = 0; //Clock enable: falling edge 
}
void clearDisplay(void) { 
 waitForNotBusy(); 
 command(0x01); //Clear Display 
}
void returnHome(void) { 
 waitForNotBusy(); 
 command(0x02); //Return Home 
}
void waitForNotBusy(void) { 
 unsigned char BF; 
 RS = RS_COMMAND; // Select Command Register 
 RWn = READ; // Read Mode 
 BF = 0b10000000; 
 TRISD = 0b11111111; 
 delay(1); // Wait at least 80 μs before reading BF 
 while(BF==0b10000000){ 
  E = 1; 
  BF = LCDDATA & 0b10000000; 
  E = 0; //Clock enable: falling edge 
 }
 TRISD = 0b00000000; 
}
void delay(unsigned char loops) {
 unsigned char i;
 for(i=0; i<loops;i++){}
}
//End of block pasted from LCDInitialization.c
void setDisplayLine(unsigned char line, unsigned char position) { //This function is incomplete.
 switch(line) { 
  case 1:command(0b01000000); 
  break; 
  case 2:command(0b11000000);
  break; 
 } 
}
void writeChar(char theData) { 
 waitForNotBusy(); 
 LCDDATA = theData; //put data on PORTD 
 RS = RS_DATA; // Select Data Register 
 RWn = WRITE; // Write Mode 
 E = 1; //enable pulse width >= 300ns 
 E = 0; //Clock enable: falling edge 
}
void writeString(char *theString) { 
 unsigned char i; 
 for(i = 0; i < strlen(theString); i++) { 
  waitForNotBusy(); 
  LCDDATA = theString; // Put data on PORTD 
  RS = RS_DATA; // Select Data Register 
  RWn = WRITE; // Write Mode 
  E = 1; // Enable pulse width >= 300ns 
  E = 0; // Clock enable: falling edge 
 } 
}


And the code for portInit(),

Rich (BB code):
#include <htc.h>
void portInit(void){
//Configure for Digital IO
PCFG3 = 0;
PCFG2 = 1;
PCFG1 = 1;
TRISE0 = 0;
TRISE1 = 0;
TRISE2 = 0;
TRISD = 0b00000000; //Configure PORTD for output
INTCON = 0; //Disable interrupts.
}
 
Last edited:

spinnaker

Joined Oct 29, 2009
7,837
Sounds to me like someone wants us to do his / her homework for him or her. :)


Do a search on HD44780. You will find datasheets and plenty of code samples . But you should really work from the datasheet just like your instructor wants you to. :)
 

Thread Starter

jegues

Joined Sep 13, 2010
733
Sounds to me like someone wants us to do his / her homework for him or her. :)


Do a search on HD44780. You will find datasheets and plenty of code samples . But you should really work from the datasheet just like your instructor wants you to. :)
Where in my original post did I ever ask anyone to do my homework for me?

As the description of this section of the forum reads,

"Discussion forum for projects and working with embedded systems and microcontrollers (FPGAs, PICs, AVRs). Get help with hardware issues and embedded programming."

I would like to get some help, not have someone do my homework for me. Just thought I would clarify that for you.

Anyways, I've already looked up the data sheet online,

http://www.newhavendisplay.com/specs/NHD-0216XZ-FSW-GBW.pdf

I feel like I understand the majority of the information being presented, aside from the font table on page 6.

What is CGRAM?

It also shows example intialization programs, but not how to actually display anything on the LCD? Can anyone point me in the right direction?

Thanks again!
 

spinnaker

Joined Oct 29, 2009
7,837
Where in my original post did I ever ask anyone to do my homework for me?

As the description of this section of the forum reads,

"Discussion forum for projects and working with embedded systems and microcontrollers (FPGAs, PICs, AVRs). Get help with hardware issues and embedded programming."

I would like to get some help, not have someone do my homework for me. Just thought I would clarify that for you.

Anyways, I've already looked up the data sheet online,

http://www.newhavendisplay.com/specs/NHD-0216XZ-FSW-GBW.pdf

I feel like I understand the majority of the information being presented, aside from the font table on page 6.

What is CGRAM?

It also shows example intialization programs, but not how to actually display anything on the LCD? Can anyone point me in the right direction?

Thanks again!

Page 6 is just a really complicated looking ASCII table.

http://www.asciitable.com/

CG RAM = Character Generator RAM
DD RAM = Display Data RAM

You are probably going to want to use 4 bit display. It is more complicated but uses less pins. Check page 8. It shows how to display a character using 4 bit.


You will still need to know how to display it on the line you want but that is next.

Remember timing is fairly critical for these displays. It does not need to be exact but you need to pay attention to the delays they recommend.
 

Thread Starter

jegues

Joined Sep 13, 2010
733
OK then page 7 has the code to output a character for 8 bit.
I already have a similiar code within a function called writeChar.

See the code below,

Rich (BB code):
void writeChar(char theData) { 
 waitForNotBusy(); 
 LCDDATA = theData; //put data on PORTD 
 RS = RS_DATA; // Select Data Register 
 RWn = WRITE; // Write Mode 
 E = 1; //enable pulse width >= 300ns 
 E = 0; //Clock enable: falling edge 
}
However, when I call the function in main like so,

writeChar("p");

I don't see any display on the LCD.

Do I have to set the display first somehow?
 

spinnaker

Joined Oct 29, 2009
7,837
Did you run the initialization code?

Post your schematic of how you have the LCD wired.


Do you have a scope, logic probe pr even a multimeter?

Step through your code. When you out put a byte to the port, verify it is appearing at the LCD how you expect it to be. This includes your enable, r/w and select bits.

Sometimes it is easier just to write a little test program to toggle the bits on your LCD and forget about the LCD code till you confirm all of your connections.
 

t06afre

Joined May 11, 2009
5,934
You do know what Hi-Tech C is shipped with examples. And that also include a LCD demo. Look in the the "C:\Program Files\HI-TECH Software\PICC\9.83\samples" folder. It is a four bit LCD demo. But it can with ease be modified to 8 bit. Your code is somewhat untidy. Like Hi-Tech are shipped with good functions for delays. They are named "__delay_ms()" and "__delay_us()" In order to work they need a
Rich (BB code):
#define _XTAL_FREQ 4000000
In the example the system clock is 4 MHz. I also noticed that as far as I can see you do not set the configurations word.
Why not use the HI-Tech C example as your work horse. And take it from there. As a hint make a copy of the example. So you do not overwrite it
 

John P

Joined Oct 14, 2008
1,785
What the???

Rich (BB code):
void LCDInit(void){
 E = 0; 
 delay(15); //Wait >15 msec after power is applied 
 initCommand(0x30); //command 0x30 = Wake up 
 delay(5); //must wait 5ms, busy flag not available 
 initCommand(0x30); //command 0x30 = Wake up #2 
 delay(160); //must wait 160us, busy flag not available
How come delay(5) counts 5 milliseconds but delay(160) counts 160 microseconds?
 

spinnaker

Joined Oct 29, 2009
7,837
Not sure. Check your documentation for delay. Where is it from BTW? Which compiler?

It could be that delay has a maximum count it can handle. Try stringing a bunch together. Say 3 50s and a 10.
 

Thread Starter

jegues

Joined Sep 13, 2010
733
What the???

Rich (BB code):
void LCDInit(void){
 E = 0; 
 delay(15); //Wait >15 msec after power is applied 
 initCommand(0x30); //command 0x30 = Wake up 
 delay(5); //must wait 5ms, busy flag not available 
 initCommand(0x30); //command 0x30 = Wake up #2 
 delay(160); //must wait 160us, busy flag not available
How come delay(5) counts 5 milliseconds but delay(160) counts 160 microseconds?
That is a typo, its actually 160ms which is larger than 160us so it is sufficient.

HI-TECH C compiler.
 
Last edited:

spinnaker

Joined Oct 29, 2009
7,837
Check your datasheet. Is there an on-board current limiting resistor for the back light? If not you should add one.

What is the value of that trim pot?
 

Thread Starter

jegues

Joined Sep 13, 2010
733
Check your datasheet. Is there an on-board current limiting resistor for the back light? If not you should add one.

What is the value of that trim pot?
I'm not sure of its exact value, but isn't that just for adjusting the intensity of the backlight?
 

t06afre

Joined May 11, 2009
5,934
@jegues
You are using HI-Tech C correct? And which version are you using. Any deatils on that. The configuration word(s) are described in the section SPECIAL FEATURES OF THE CPU in the datasheet. I may give you some pointers if I know which version you are using of the C compiler. The configuration word can be set from MPLAB. But it is highly recommended that you put this information in the code.
 

Thread Starter

jegues

Joined Sep 13, 2010
733
@jegues
You are using HI-Tech C correct? And which version are you using. Any deatils on that. The configuration word(s) are described in the section SPECIAL FEATURES OF THE CPU in the datasheet. I may give you some pointers if I know which version you are using of the C compiler. The configuration word can be set from MPLAB. But it is highly recommended that you put this information in the code.
Yes I am using HI-TECH C. The version listed in the readme file is,

"HI-TECH C Compiler for PIC10/12/16 MCUs Version 9.83 ".
 

t06afre

Joined May 11, 2009
5,934
At the top of your PIC header file located in "......\HI-TECH Software\PICC\9.83\include" you will find this section
Rich (BB code):
// Configuration mask definitions
//
 
// Config Register: CONFIG
#define CONFIG               0x2007
// Oscillator Selection bits
// RC oscillator
#define FOSC_EXTRC           0xFFFF
// HS oscillator
#define FOSC_HS              0xFFFE
// XT oscillator
#define FOSC_XT              0xFFFD
// LP oscillator
#define FOSC_LP              0xFFFC
// Watchdog Timer Enable bit
// WDT enabled
#define WDTE_ON              0xFFFF
// WDT disabled
#define WDTE_OFF             0xFFFB
// Power-up Timer Enable bit
// PWRT disabled
#define PWRTE_OFF            0xFFFF
// PWRT enabled
#define PWRTE_ON             0xFFF7
// Brown-out Reset Enable bit
// BOR enabled
#define BOREN_ON             0xFFFF
// BOR disabled
#define BOREN_OFF            0xFFBF
// Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit
// RB3/PGM pin has PGM function; low-voltage programming enabled
#define LVP_ON               0xFFFF
// RB3 is digital I/O, HV on MCLR must be used for programming
#define LVP_OFF              0xFF7F
// Data EEPROM Memory Code Protection bit
// Data EEPROM code protection off
#define CPD_OFF              0xFFFF
// Data EEPROM code-protected
#define CPD_ON               0xFEFF
// Flash Program Memory Write Enable bits
// Write protection off; all program memory may be written to by EECON control
#define WRT_OFF              0xFFFF
// 0000h to 00FFh write-protected; 0100h to 1FFFh may be written to by EECON control
#define WRT_256              0xFDFF
// 0000h to 07FFh write-protected; 0800h to 1FFFh may be written to by EECON control
#define WRT_1FOURTH          0xFBFF
// 0000h to 0FFFh write-protected; 1000h to 1FFFh may be written to by EECON control
#define WRT_HALF             0xF9FF
// In-Circuit Debugger Mode bit
// In-Circuit Debugger disabled, RB6 and RB7 are general purpose I/O pins
#define DEBUG_OFF            0xFFFF
// In-Circuit Debugger enabled, RB6 and RB7 are dedicated to the debugger
#define DEBUG_ON             0xF7FF
// Flash Program Memory Code Protection bit
// Code protection off
#define CP_OFF               0xFFFF
// All program memory code-protected
#define CP_ON                0xDFFF
Then match these options to the figure named "REGISTER 14-1: CONFIGURATION WORD (ADDRESS 2007h)" in the PIC datasheet
At the top of your program after the include section. You add the __CONFIG() macro. You will be using RC OSC, and watchdog timer can be turned off. So to get you started the two first parameters in your __config macro will be like this. You can do the rest. The order of the macro names is unconcerned. For more info see the HI-Tech C manual section 3.3.4 Configuration Bit Access in the docs folder.
Rich (BB code):
__config(FOSC_EXTRC & WDTE_OFF........)
As you see the macro names are bitwise ANDed together to form the configuration value. To avoid any confusion or problems set every options up to the last CP_OFF/CP_ON option. (CP_OFF in your case)
 
Last edited:

ErnieM

Joined Apr 24, 2011
8,011
On the display Pins 15 and 16 are the backlight LED and absolutely need a limit resistor. If you powered on like that you probably killed the LED but the unit should still work in a bright room. The pot connecting to Pin 3 should typically be 10K. If misadjusted nothing will show on the display. Turn it one end to the other to find where it wants to be.

The config word needs to be set. The following may work with your hardware:

Rich (BB code):
// Oscillator Selection bits: RC oscillator
// Watchdog Timer Enable bit: WDT disabled
// Power-up Timer Enable bit: PWRT disabled
// Brown-out Reset Enable bit: BOR disabled
// Low-Voltage (Single-Supply) ICSP Enable bit: RB3 is I/O, HV on MCLR for programming
// Data EEPROM Memory Code Protection bit: Data EEPROM code protection off
// Flash Program Memory Write Enable bits: Write protection off; all program memory may be written to by EECON control
// In-Circuit Debugger Mode bit: In-Circuit Debugger enabled, RB6 and RB7 are dedicated to the debugger
// Flash Program Memory Code Protection bit: Code protection off

__CONFIG(FOSC_EXTRC & WDTE_OFF & PWRTE_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_ON & CP_OFF);
 
Top