//*******************************************************************
//
//  Program Type  : Sample Program
//  Part No.      : C162-1/2/3/4/5/6/7/8/9/A/B/C/E
//  Dot Matrix    : 16 Characters x 2 Lines
//  LCD Controller: SPLC780D1/ST7066U/S6A0069
//  Interface     : 8-bit 6800 Parallel
//  MCU Type      : AT89S52
//  OSC Frequency : 12 MHz
//  Revision      : REV1.0
//  Date          : 2011/08/10
//  Editor        : LYJ 
//
//*******************************************************************

//*******************************************************************
//  The displayed message should read:
//	Line 1: "16X2 LCD"
//	Line 2: 8 CGRAM characters
//********************************************************************

#include <AT89X52.H> 
#include <intrins.h>
#include <string.h>

#define uchar unsigned char
#define uint unsigned int

//*******************************************************************
//  Pin Definition
//*******************************************************************

#define LCD_BUS  P0		//Data Bus P0 should be pulled up by 10K resistors
#define LCD_RS   P1_0	//Data/Command Selection
#define LCD_RW   P1_1	//Read/Write Selection
#define LCD_E    P1_2	//Enable Signal


//*******************************************************************
//  Delay t ms for 12 MHz crystal
//*******************************************************************

void Delay_ms(uint t)
{  
	uint i,j;
	for(i=0;i<t;i++)
	for(j=0;j<125;j++)  //Delay 125x8us=1ms
    {;}
}

//*******************************************************************
//  Check LCD busy flag
//*******************************************************************

void LCD_BusyCheck(void)
{
	LCD_BUS = 0xFF;  		   	//Set data port to input mode
	LCD_RS = 0;             //Select status register
	LCD_RW = 1;             //Read 
	LCD_E  = 1;             //Enable LCD 
	while (LCD_BUS & 0x80);	//Wait until LCD busy flag clears
	LCD_E = 0;              //Disable LCD
	LCD_RW = 1;
	LCD_RS = 1;
}

//*******************************************************************
//  Write command without LCD busy checking
//*******************************************************************

void LCD_WriteCommand_NBC(uchar cmd)
{	
	LCD_RS = 0;
	LCD_RW = 0;
	LCD_BUS = cmd;
	LCD_E = 1;
	_nop_();      //Delay
	LCD_E = 0;
	LCD_RW=1;
	LCD_RS=1;
}

//*******************************************************************
//  Write command with LCD busy checking
//*******************************************************************

void LCD_WriteCommand(uchar cmd)
{	
	LCD_BusyCheck();  //Check LCD busy flag
	LCD_RS = 0;
	LCD_RW = 0;
	LCD_BUS = cmd;
	LCD_E = 1;
	_nop_();       //Delay
	LCD_E = 0;
	LCD_RW=1;
	LCD_RS=1;
}

//*******************************************************************
//  Write display data with LCD busy checking
//*******************************************************************

void LCD_WriteData(uchar dat)
{	
	LCD_BusyCheck();  //Check LCD busy flag
	LCD_RS = 1;
	LCD_RW = 0;
	LCD_BUS = dat;
	LCD_E  = 1;
	_nop_();     //Delay
	LCD_E  = 0;
	LCD_RW=1;
	LCD_RS=1;
}

//*******************************************************************
//  Set DDRAM Address
//*******************************************************************

void Set_DDRAM_Address(uchar add)
{
	LCD_WriteCommand(0x80|add);	// Set DDRAM Address
}

//*******************************************************************
//  Set CGRAM Address
//*******************************************************************

void Set_CGRAM_Address(uchar add)
{
	LCD_WriteCommand(0x40|add);	// Set CGRAM Address
}

//*******************************************************************
//  Write a character string
//*******************************************************************

void ShowString(uchar *str)
{ 	
	while(*str)
	{
	LCD_WriteData(*str);
	str++;
	}
}

//*******************************************************************
//  CGRAM Data (Character Patterns)
//*******************************************************************

uchar code CGRAM_Data[]={
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,	//  "Solid Block"
	0x1F,0x11,0x11,0x11,0x11,0x11,0x11,0x1F,	//  "Square"
	0x1F,0x00,0x1F,0x00,0x1F,0x00,0x1F,0x00,	//  "4 Rows 1"
	0x00,0x1F,0x00,0x1F,0x00,0x1F,0x00,0x1F,	//  "4 Rows 2"
	0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,	//  "3 ColumnS"
	0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,	//  "2 ColumnS"
	0x15,0x0A,0x15,0x0A,0x15,0x0A,0x15,0x0A,	//  "Checkerboard 1"
	0x0A,0x15,0x0A,0x15,0x0A,0x15,0x0A,0x15,	//  "Checkerboard 2"
};

//*******************************************************************
//  Write CGRAM Data (Character Patterns)
//*******************************************************************

void Write_CGRAM_Data(void)
{	
	uchar i;

	Set_CGRAM_Address(0x00);      //Set CGRAM address 
	for (i=0;i<64;i++)            //Write 64 bytes of CGRAM character pattern data
	LCD_WriteData(CGRAM_Data[i]);
}

//*******************************************************************
//  LCD Initilization
//*******************************************************************

void LCD_Init(void)	
{		
	Delay_ms(30);		            //Delay 30ms
	LCD_WriteCommand_NBC(0x38);	//Function set: 8-bit, 2-line mode, 5x8 font
	Delay_ms(1);                //Delay 1ms
	LCD_WriteCommand_NBC(0x38);	//Function set: 8-bit, 2-line mode, 5x8 font
	Delay_ms(1);                //Delay 1ms
	LCD_WriteCommand_NBC(0x38);	//Send function set instruction 3 times to make sure lcd is initialized  
														  //Busy flag can not be checked before this instruction               
	Delay_ms(1);  	            //Delay 1ms
	LCD_WriteCommand(0x08);     //Display off, cursor off, blink off. 
														  //Busy flag should be checked from this instruction
	LCD_WriteCommand(0x01);     //Clear display
	LCD_WriteCommand(0x06);	    //Entry mode set: increament by 1, no shift
	LCD_WriteCommand(0x0C);     //Display on, cursor off, blink off                 		          	           	
}

//*******************************************************************
//  Main program
//*******************************************************************

void main()
{	
	uchar i;
	
	LCD_BUS = 0xFF;
	P1 = 0xFF;

	LCD_Init();
	Write_CGRAM_Data();       //Write CGRAM data (character patterns)
			
	LCD_WriteCommand(0x01);  	//Clear display
	Set_DDRAM_Address(0x00);	//Set DDRAM address to 00H(1st position of LCD line 1)
	ShowString("16X2 LCD");	  //Write 8 characters
	Set_DDRAM_Address(0x40);  //Set DDRAM address to 40H(1st position of LCD line 2)
	for (i=0;i<8;i++)
	  LCD_WriteData(i);       //Write 8 bytes of CGRAM code (0x00 to 0x07) to DDRAM
	while(1)
 	{};
}

//*******************************************************************
//  End
//*******************************************************************
