//LCD Display Module Interfacing Example in Hi-Tech PICCLITE C
//Number of PIC pins used: 6 (RB5 - RB0)
//This example works for any LCD Module made by Optrex, Hitachi, etc.
//Two 4-bit nybbles are sent one after the other from the PIC16F877 to the LCD interface,
//as explained in Microchip Application Note AN587 (DS00587B - page 3-205)
//Chip Type: PIC16F877
//Clock Frequency: 13.5 MHz
//Written by KEH on 11/01/2003
//LCD Display Type: 20 char X 2 line
//***********************************************************************
//LCD Display Module connections to the PIC 
//   	LCD Pin  LCD Pin #   PIC Sig  PIC Pin #
//      	1		GND			---		---
//       	2   	Vcc			---		---
//		 	3		Vee (Gnded for full contrast)
//			4		RS			RB5		P38
//			5		R/W* (Gnded, since we will only write to LCD module)
//			6		E			RB4		P37
//			7-10 	DB0-DB3 (Not used)	---
//			11		DB4			RB0		P33
//			12		DB5			RB1		P34
//			13		DB6			RB2		P35
//			14		DB7			RB3		P36
//***********************************************************************
	#include <pic.h>
	#define RS 			RB5
	#define RSCMD		0
	#define RSDTA		1
	#define E			RB4

	void initialize_lcd(void);
	void delayms(unsigned char);
	void sendnyb(unsigned char);
	void sendbyte(unsigned char);

	void main(void)
{	
	unsigned char j;
	PORTB = 0;
	TRISB = 0xC0;	// Make RB5-0 all outputs
	initialize_lcd();
	RS=RSDTA;
	for(j=0;j<20;j++)
  			sendbyte(j+0x41);
	RS=RSCMD;
	sendbyte(0b10101000);	//Set DDRAM address command
							//Format (1 a a a a a a a )
							//Set DDRAM address to 0x28 = 40
							//This is the starting address
							//of the 2nd row.
	RS=RSDTA;
	for(j=0;j<20;j++)
  			sendbyte(j+0x61);
	for(;;)
	  continue;
}


void initialize_lcd(void)
{
//initializes LCD Display
	delayms(20);	
	RS=RSCMD;		
	E=0;
	sendnyb(0x3);	// Function Set Command, Gen'l format: 0 0 1 DL N F * *
	delayms(0x5);	// Note that DL = 1 => 8-bit interface mode (Display must be started in 8-bit mode)
					// Note that the N F * * (low order 4 bits) are not connected, and may be any value.
	sendnyb(0x3); 	// Repeat a second time.
	delayms(0x1);
	sendnyb(0x3);	// Repeat a 3rd time
	sendnyb(0x2); 	// Function Set Command - Now we can set interface to 4-bit (nybble) mode

					// Now that we are in nybble mode, we can send all 8 bits of each command via
					// two back-to-back calls to sendnyb( ).
	sendbyte(0x28); // Function Set Command Format: 0 0 1 DL N F * *
								// We just sent:                0 0 1 0  1 0 0 0 
								//  DL=0 => 4-bit mode,
								//	N=1 => 1/8 duty cycle
								//  F=0 => 5 X 7 dot font
	sendbyte(0x08); // Display OFF command
	sendbyte(0x01); // Clear Display command
	sendbyte(0x06);	// Entry mode set command format: 0 0 0 0 0 1 I/D S
							// I/D = 1 => Increment display addr ptr.
							// S = 0 => Do not shift (scroll) display
	sendbyte(0x0C);	// Display ON command
}


void delayms(unsigned char nrms)
{
// Uses Timer #2 to delay the nr of ms specified assuming clock freq = 13.5 MHz
	unsigned char i;
	T2CON=0b0000111;	//Timer 2 tick time = (4/13.5 Mhz)*16 = 210.93
	for (i = 0; i < nrms; i++)
		{
			TMR2=256-211;		//Schedule TMR2IF flag to be set in 1 ms
			TMR2IF = 0;			//Clear TMR2IF timeout flag
			while(TMR2IF == 0)
				continue;		//Wait here for 1 ms, until TMR2IF flag is set
		}
}

void sendnyb(unsigned char sendval)
{
	unsigned char portbval;
	portbval = PORTB;
	PORTB = (portbval & 0xF0) + (sendval & 0x0F);
								//Send out most sig 4 bits of sendval on RB3:0
	delayms(1);
	E=1;
	delayms(1);
	E=0;
	delayms(1);
}

void sendbyte(unsigned char sendval)
{
	sendnyb(sendval >> 4);
	sendnyb(sendval & 0x0f);
}