/**********************************************/
/* Example Program For ET-BASE Z51F6412 V1.0  */
/* MCU      : Zilog MCS51 / Z51F6412          */
/*          : Run Internal RC (8.00 MHz)      */
/* Compiler : Keil C51 (V9.50a)               */
/* Editor   : uVision V4.53.0.6               */
/* Write By : Eakachai Makarn(ETT CO.,LTD.)   */
/* Function : Demo Character LCD Interface    */
/* Update   : 18 August 2012                  */
/**********************************************/
// ET-10PIN CLCD Interface Port P4
// Px0 = Black Light LED
// Px1 = RS
// Px2 = RW
// Px3 = EN
// Px4 = D4
// Px5 = D5
// Px6 = D6
// Px7 = D7

#include <z51f6412.h>																		// Z8051 : Z51F6412

/*************************************/
/* 10PIN CLCD Hardware Interface Pin */
/*************************************/
#define LCD_DIR						P4IO													// Port Direction
#define LCD_PULLUP				P4PU													// Port Pull-Up
#define LCD_PORT					P4														// Port Read/Write Data

#define LCD_BL_PIN        (1 << 0)											// Bit0 = Black Light Control
#define LCD_RS_PIN				(1 << 1)											// Bit1 = RS
#define LCD_RW_PIN        (1 << 2)              				// Bit2 = RW
#define LCD_EN_PIN        (1 << 3)											// Bit3 = EN
#define LCD_D4_PIN				(1 << 4) 											// Bit4 = D4
#define LCD_D5_PIN        (1 << 5)											// Bit5 = D5
#define LCD_D6_PIN        (1 << 6)											// Bit6	= D6
#define LCD_D7_PIN				(1 << 7)											// Bit7 = D7

#define LCD_INIT_PORT()   LCD_DIR     = 0xFF            // Data+Control = Output(11111111)
#define LCD_INIT_WRITE()	LCD_DIR    |= 0xF0						// Data=Output(1111xxxx)
#define LCD_INIT_READ()		LCD_DIR    &= 0x0F						// Data=Input,(0000xxxx)
#define LCD_INIT_PULLUP() LCD_PULLUP |= 0xF0            // Enable Pull-Up Pin[4..7]

#define LCD_BL_OFF()			LCD_PORT   &= ~(LCD_BL_PIN)		// BL = 0(OFF Black Light)
#define LCD_BL_ON()  			LCD_PORT   |=  (LCD_BL_PIN)		// BL = 1(ON Black Light)
#define LCD_RS_LOW()			LCD_PORT   &= ~(LCD_RS_PIN)		// RS = 0(Instruction)
#define LCD_RS_HIGH()  		LCD_PORT   |=  (LCD_RS_PIN)		// RS = 1(Data)
#define LCD_RW_LOW()			LCD_PORT   &= ~(LCD_RW_PIN)		// RW = 0(Write Direction)
#define LCD_RW_HIGH()  		LCD_PORT   |=  (LCD_RW_PIN)		// RW = 1(Read Direction)
#define LCD_EN_LOW()			LCD_PORT   &= ~(LCD_EN_PIN)		// EN = 0
#define LCD_EN_HIGH()  		LCD_PORT   |=  (LCD_EN_PIN)		// EN = 1
#define LCD_D4_LOW()			LCD_PORT   &= ~(LCD_D4_PIN)		// D4 = 0
#define LCD_D4_HIGH()  		LCD_PORT   |=  (LCD_D4_PIN)		// D4 = 1
#define LCD_D5_LOW()			LCD_PORT   &= ~(LCD_D5_PIN)		// D5 = 0
#define LCD_D5_HIGH()  		LCD_PORT   |=  (LCD_D5_PIN)		// D5 = 1
#define LCD_D6_LOW()			LCD_PORT   &= ~(LCD_D6_PIN)		// D6 = 0
#define LCD_D6_HIGH()  		LCD_PORT   |=  (LCD_D6_PIN)		// D6 = 1
#define LCD_D7_LOW()			LCD_PORT   &= ~(LCD_D7_PIN)		// D7 = 0
#define LCD_D7_HIGH()  		LCD_PORT   |=  (LCD_D7_PIN)		// D7 = 1

/***********************
 * Function Prototypes *
 ***********************/
void init_4bit_lcd(void);																// Initial Character LCD(4-Bit Interface)
void set_lcd_cursor(char);															// Set Cursor LCD
void write_lcd_ins(char);      													// Write Instruction LCD
void write_lcd_data(char);															// Write Data LCD
void enable_lcd(void);	 																// Enable Pulse
void wait_busy_lcd(void);																// Read & Wait Busy Status
void print_lcd(char *lcd_buf);													// Display Message LCD
void delay(unsigned long);															// Delay Time Function(1..4294967295)

/********************
 * Function: main() *
 ********************/
void main(void)
{	  
	/* Config System Clock = Internal RC 8.00 MHz */
	//PLLCR = 0,0,0,00,00,0
	// 0xxxxxxx : PLL Output Status
	// x0xxxxxx : PLL Output Bypass
	// xx0xxxxx : Power PLL = Default
	// xxx00xxx : FBDiv = Default
	// xxxxx00x : PLL M = Default
	// xxxxxxx0 : PLL Disable
	PLLCR = 0x00;																					// Disable PLL
	
	// SCCR = 0,01,0,0,1,00
	// 0xxxxxxx : Stop Mode = Mode 2
	// x01xxxxx : INTRC Clock Divide = INTRC(16MHz)/2 = 8MHz
	// xxx0xxxx : Clock Change By Hardware
	// xxxx0xxx : RC Oscillator Enable
	// xxxxx1xx : XTAL Oscillator Disable
	// xxxxxx00 : System Clock Source = INTRC(16MHz)
	SCCR = 0x24;  																				// INT-RC 8MHz	
	/* Now System Clock = 8.00MHz */
 
	// Initial LCD 4Bit Mode */
	init_4bit_lcd();																			// Initial LCD
  
  while(1)
  {
    set_lcd_cursor(0);																	// Set Cursor Line-1
    print_lcd("ET-BASE Z51F6412"); 											// Display Line-1
    set_lcd_cursor(0x40);																// Set Cursor Line-2
    print_lcd("BY..ETT CO.,LTD."); 											// Display Line-2
    delay(150000);																			// Display Delay

    set_lcd_cursor(0);																	// Set Cursor Line-1
    print_lcd("MCS51 High Speed"); 											// Display Line-1  
    set_lcd_cursor(0x40);																// Set Cursor Line-2
    print_lcd("High Performance"); 											// Display Line-2
    delay(150000);																			// Display Delay
  }  
}

/*******************************/
/* Initial LCD 4-Bit Interface */
/*******************************/
void init_4bit_lcd(void)
{
  unsigned long i;																			// Delay Count
	
	LCD_INIT_PORT();																			// LCD Bus = Write 
	LCD_INIT_PULLUP();																		// Enable Pull-Up Data Pin
  LCD_EN_LOW();																					// Start LCD Control (Disable)
  LCD_RS_LOW();																					// Default Instruction
  LCD_RW_LOW();																					// Default = Write Direction
	LCD_D4_HIGH();
  LCD_D5_HIGH();
  LCD_D6_LOW();
  LCD_D7_LOW();		
  for(i=0; i<(400000ul); i++);													// Power-On Delay (50 mS)  
	
  LCD_D4_HIGH();																				// DB5:DB4 = 1:1
  LCD_D5_HIGH();
  LCD_D6_LOW();
  LCD_D7_LOW();	  
  enable_lcd();																					// Enable Pulse
  for(i=0; i<(32800ul); i++);														// Delay 4.1mS
 
	LCD_D4_HIGH();																				// DB5:DB4 = 1:1
  LCD_D5_HIGH();
  LCD_D6_LOW();
  LCD_D7_LOW();	
  enable_lcd();																					// Enable Pulse
  for(i=0; i<(800ul); i++);															// delay 100uS

	LCD_D4_HIGH();																				// DB5:DB4 = 1:1
  LCD_D5_HIGH();
  LCD_D6_LOW();
  LCD_D7_LOW();	
  enable_lcd();																					// Enable Pulse
  wait_busy_lcd();      																// Wait LCD Execute Complete

	LCD_D4_LOW();																					// DB5:DB4 = 1:0
  LCD_D5_HIGH();
  LCD_D6_LOW();
  LCD_D7_LOW();	
  enable_lcd();																					// Enable Pulse
  wait_busy_lcd();      																// Wait LCD Execute Complete
  
  write_lcd_ins(0x28);  																// Function Set (DL=0 4-Bit,N=1 2 Line,F=0 5X7)
  write_lcd_ins(0x0C);  																// Display on/off Control (Entry Display,Cursor off,Cursor not Blink)
  write_lcd_ins(0x06);  																// Entry Mode Set (I/D=1 Increment,S=0 Cursor Shift)
  write_lcd_ins(0x01);  																// Clear Display  (Clear Display,Set DD RAM Address=0)
	LCD_BL_ON();																					// ON Black Light LED
}

/******************/
/* Set LCD Cursor */
/******************/
void set_lcd_cursor(char i)
{
  i |= 0x80;																						// Set DD-RAM Address Command
  write_lcd_ins(i);  
}

/****************************/
/* Write Instruction to LCD */
/****************************/
void write_lcd_ins(char i)
{
  LCD_RS_LOW();			 																		// Instruction Select
  LCD_RW_LOW();																					// Write Select

  LCD_PORT &= 0x0F;       															// Clear old LCD Data (Bit[7..4])
  LCD_PORT |= i & 0xF0;   															// Strobe High Nibble Command
  enable_lcd();																					// Enable Pulse
       
  LCD_PORT &= 0x0F;        															// Clear old LCD Data (Bit[7..4])
  LCD_PORT |= (i << 4) & 0xF0;													// Strobe Low Nibble Command
  enable_lcd();																					// Enable Pulse
    
  wait_busy_lcd();      																// Wait LCD Execute Complete
}

/****************************/
/* Write Data(ASCII) to LCD */
/****************************/
void write_lcd_data(char i)
{
  LCD_RS_HIGH();				  															// Data Select
  LCD_RW_LOW();																					// Write Select

  LCD_PORT &= 0x0F;    																	// Clear old LCD Data (Bit[7..4])
  LCD_PORT |= i & 0xF0;  																// Strobe High Nibble Data
  enable_lcd();																					// Enable Pulse  
    			
  LCD_PORT &= 0x0F;    																	// Clear old LCD Data (Bit[7..4])
  LCD_PORT |= (i << 4) & 0xF0; 													// Strobe Low Nibble Data
  enable_lcd();																					// Enable Pulse
 
  wait_busy_lcd();      																// Wait LCD Execute Complete
}

/***********************/
/* Enable Pulse to LCD */
/***********************/
void enable_lcd(void)	 																	// Enable Pulse
{
  unsigned char t;																			// Delay Count

  LCD_EN_HIGH();   																			// Enable ON
	for(t=0; t<8; t++);																		// Wait 500nS
  LCD_EN_LOW();   																			// Enable OFF 
	for(t=0; t<8; t++);																		// Wait 500nS
}

/******************/
/* Wait LCD Ready */
/******************/
void wait_busy_lcd(void)
{
  unsigned char busy_status;														// Busy Status Read
  unsigned char t;																			// Delay Count

	LCD_INIT_READ();																			// Initial Direction LCD Data Bus = Read
  LCD_RS_LOW();			 																		// Instruction Select
  LCD_RW_HIGH(); 																				// Read Direction	
  for(t=0; t<8; t++);																		// Wait 500nS
 
	do
	{	
    LCD_EN_HIGH();																			// Start Read Busy(MSB)
    for(t=0; t<8; t++);																	// Wait 500nS
    busy_status = LCD_PORT;															// Read LCD Data
    LCD_EN_LOW();       						    								// Disable Read
    for(t=0; t<8; t++);																	// Wait 500nS
    LCD_EN_HIGH();																			// LSB Dummy Read
    for(t=0; t<8; t++);																	// Wait 500nS
    LCD_EN_LOW();
		for(t=0; t<8; t++);																	// Wait 500nS
	}	while((busy_status & 0x80) == 0x80);	  						// Wait until Busy = 0

  LCD_INIT_WRITE();																			// Initial Direction LCD Data Bus = Write
  LCD_RW_LOW();																					// Default = Write Direction	
}

/*
 * Function    : print_lcd
 * Description : print a string to lcd
 */
void print_lcd(char *lcd_buf)
{
	while(*lcd_buf != '\0')
  {
	  write_lcd_data(*lcd_buf++);	
	}	
}

/*******************************************/
/* Long Delay Time Function(1..4294967295) */
/*******************************************/
void delay(unsigned long i)
{
  while(i > 0) {i--;}																		// Loop Decrease Counter	
  return;
}
