PIC18 Explorer Board: How To Use The LCD Display

by Miguel on July 8, 2011

in PIC18 Explorer Board

lcd display showing letters and numbers

The PIC18's LCD showing some letters and numbers

As you can see from the image above I managed to get the LCD working, however the code I used was a modified (leaner) version of the original one.

For those who have been trying to use the LCD library please note that it will not work since the LCD is connected to PIC chip through a SPI communication chip, a good choice on Microchip’s part in my opinion. What this chip does is it allows you to use fewer pins of your PIC when working with components that require many like LCDs.

The modified version of the code I used is the following.

#include <p18f8722.h>
#include <delays.h>

#pragma config OSC=HS
#pragma config WDT=OFF

void InitSPI(void);
void InitPORTA_SPI(char);
void InitPORTB_SPI(char);
void WritePortA(char);
void WritePortB(char);
void d_write(char);
void i_write(char);
void LCDLine_1(void);
void LCDLine_2(void);
void LCDInit(void);

void main( void )
{
	unsigned char sentence[]="0123456789ABCDEF";
	unsigned int i=0;
	
	RCONbits.IPEN=0;   // disable priority system. 

	OSCCONbits.IRCF0 = 0;
	OSCCONbits.IRCF1 = 0;
	OSCCONbits.IRCF2 = 1;

  	// Initialize the LCD display.
	LCDInit();
	
	// Switch ti LCD line 1 ( sends a command to the LCD to tell it ).

	LCDLine_1(); // select line 1
	for(i=0;i<=15;i++)
	{
		d_write(sentence[i]);	
		Delay10KTCYx(50);
	}
	
	LCDLine_2(); // select line 2
	d_write('L');
	d_write('I');
	d_write('N');
	d_write('E');
	d_write('2');
	
	while(1)
	{
		
	}
}
//*****************************************************************
// Write to MCP923S17 Port A
//*****************************************************************
void WritePortA(char b)
{
	LATAbits.LATA2 = 0;
	
	SSPBUF = 0x40;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = 0x12;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = b;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	LATAbits.LATA2 = 1;
}
//*****************************************************************
// Write to MCP923S17 Port B
//*****************************************************************
void WritePortB(char b)
{
	LATAbits.LATA2 = 0;
	
	SSPBUF = 0x40;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = 0x13;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = b;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	LATAbits.LATA2 = 1;
}
//*****************************************************************
// Send data to the display
//*****************************************************************
void d_write(char b)
{
	WritePortA(0x80);
	WritePortB(b);
	WritePortA(0xC0);
	WritePortA(0x00);
}
//*****************************************************************
// Send a command to the display
//*****************************************************************
void i_write(char b)
{
	WritePortA(0x00);
	Delay10TCYx(0);

	WritePortB(b);
	Delay10TCYx(0);

	WritePortA(0x40);
	Delay10TCYx(0);

	WritePortA(0x00);
}
//*****************************************************************
// Write to line 1 of the display
//*****************************************************************
void LCDLine_1(void)
{
	i_write(0x80);
}
//*****************************************************************
// Write to line 1 of the display
//*****************************************************************
void LCDLine_2(void)
{
	i_write(0xC0);
}
//******************************************************************
// Function to write to the PORT
//******************************************************************
void InitWrite(char b)
{
	WritePortA(0);
	WritePortB(b);
	Nop();
	Nop();
	Nop();
	WritePortA(0x40);
	Nop();
	Nop();
	Nop();
	Nop();
	Nop();
	Nop();
	Nop();
	Nop();
	Nop();
	WritePortA(0);
}
//*****************************************************************
// Initialize MCP923S17 Port A
//*****************************************************************
void InitPortA_SPI(char b)
{
	LATAbits.LATA2 = 0;
	SSPBUF = 0x40;
	
	/*
	SSP1IF: MSSP1 Interrupt Flag bit 
	1 = The transmission/reception is complete (must be cleared in software)
	0 = Waiting to transmit/receive 
	*/
	
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = 0x00;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = b;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	LATAbits.LATA2 = 1;
}
//*****************************************************************
// Initialize MCP923S17 Port B
//*****************************************************************
void InitPortB_SPI(char b)
{
	LATAbits.LATA2 = 0;

	SSPBUF = 0x40;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = 0x01;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	SSPBUF = b;
	while(!PIR1bits.SSPIF);
	PIR1bits.SSPIF = 0;
	
	LATAbits.LATA2 = 1;
}
//*****************************************************************
// Initialize MCP923S17 SPI
//*****************************************************************
void InitSPI(void)
{
	// RC3 is connected to  SCK: Serial clock input
	TRISCbits.TRISC3 = 0;
	// RC5 is connected to SI: Serial data I/O (MCP23017), Serial data input (MCP23S17) 
	TRISCbits.TRISC5 = 0;
	// SSPxCON1: MSSPx CONTROL REGISTER 1 (I2C™ MODE)
	// SSPEN=1, 1 = Enables the serial port and configures the SDAx and SCLx pins as the serial port pins 
	// SSPM<3:0>=0010, 0010 = SPI Master mode, clock = FOSC/64  
	// CKP=0, 0 = Holds clock low (clock stretch), used to ensure data setup time
	SSP1CON1 = 0x22; // 00100010
	//  CKE: SPI Clock Select bit
	//	1 = Transmit occurs on transition from active to Idle clock state
	//	0 = Transmit occurs on transition from Idle to active clock state
	SSP1STATbits.CKE = 1;
	//	SSP1IF: MSSP1 Interrupt Flag bit 
	//1 = The transmission/reception is complete (must be cleared in software)
	//0 = Waiting to transmit/receive 
	PIR1bits.SSPIF = 0;
	
}



//******************************************************************
// LCD Initialization function
//******************************************************************
void LCDInit(void)
{
	// RA2 connects CS: Chip Select (MCP23S17)
	TRISAbits.TRISA2 = 0;
	LATAbits.LATA2 = 1;	// SPI Sequential Write/Read

	Delay10TCYx(0);
	Delay10TCYx(0);
	Delay10TCYx(0);
	
	// RF6 is connected to RESET of expander: Hardware reset. Must be externally biased.	
	TRISFbits.TRISF6 = 0;
	LATFbits.LATF6 = 0;
	Delay10TCYx(0);
	LATFbits.LATF6 = 1; // RESET expander
	
	InitSPI(); // see above
	
	InitPortA_SPI(0);
	InitPortB_SPI(0);
	
	WritePortA(0);
	
	Delay10TCYx(0);
	InitWrite( 0b00111100 );				//0011NFxx
	
	Delay10TCYx(0);
	InitWrite( 0b00001100 );				//Display Off
	
	Delay10TCYx(0);
	InitWrite( 0b00000001 );				//Display Clear
	
	Delay10TCYx(0);
	InitWrite( 0b00000110 );				//Entry mode
}

Since the LCD used SPI communication we can use the MCC18 SPI library, I will post the code as soon as it’s ready.

Previous post:

Next post: