/************************************************/
/* Demo Program For ET-BASE PIC40/1939(ICSP)    */
/* MCU Control : PIC16F1939                     */
/*             : Run 32MHz(Internal 8MHz + PLL) */
/* Compiler    : PIC-CCS Version 4.120          */
/* Function    : Demo CLCD 4-Bit Interface      */
/************************************************/
// CLCD Used 4-Bit Mode Interface       
// Pin1(GND)    = GND
// Pin2(VDD)    = +5V
// Pin3(VO)     = Contrast Brightness
// Pin4(RS)     = RB1(RS)
// Pin5(R/W#)   = RB2(R/W#)
// Pin6(E)      = RB3(E)
// Pin7(DB0)    = GND(DB0)
// Pin8(DB1)    = GND(DB1)
// Pin9(DB2)    = GND(DB2)
// Pin10(DB3)   = GND(DB3)
// Pin11(DB4)   = RB4(DB4)
// Pin12(DB5)   = RB5(DB5)
// Pin13(DB6)   = RB6(DB6)
// Pin14(DB7)   = RB7(DB7)

#include <16F1939.h>
#include <stdlib.h>

// Fuses: PIC16F1939(CCS Compiler)
// Fuses: LP,XT,HS,RC,INTRC_IO,ECL,ECM,ECH,NOWDT,WDT_SW,WDT_NOSL,WDT
// Fuses: PUT,NOPUT,NOMCLR,MCLR,PROTECT,NOPROTECT,CPD,NOCPD,NOBROWNOUT
// Fuses: BROWNOUT_SW,BROWNOUT_NOSL,BROWNOUT,CLKOUT,NOCLKOUT,NOIESO
// Fuses: IESO,NOFCMEN,FCMEN,WRT,WRT_EECON2000,WRT_EECON200,NOWRT
// Fuses: VCAP_A0,VCAP_A5,VCAP_A6,NOVCAP,PLL_SW,PLL,NOSTVREN,STVREN
// Fuses: BORV25,BORV19,DEBUG,NODEBUG,NOLVP,LVP

//Select Jumper RA6,RA7(XTAL/GPIO) = XTAL
//#fuses   HS,PLL,NOWDT,NOPROTECT,NOLVP                                       // X-TAL 8MHz + PLL(x4)
//#use     delay(clock=32000000)                                              // 32.00 MHz

//Select Jumper RA6,RA7(XTAL/GPIO) = GPIO
#fuses   INTRC_IO,PLL,NOWDT,NOPROTECT,NOLVP                                   // Internal RC Clock 8MHz + PLL(4)
#use     delay(clock=32000000)                                                // 32.00 MHz

//LCD Interface                        
#define LCD_BL_PIN               PIN_B0                                       // Blacklight LED
#define LCD_RS_PIN               PIN_B1   
#define LCD_RW_PIN               PIN_B2      
#define LCD_ENABLE_PIN           PIN_B3   
#define LCD_DATA4_PIN            PIN_B4 
#define LCD_DATA5_PIN            PIN_B5  
#define LCD_DATA6_PIN            PIN_B6   
#define LCD_DATA7_PIN            PIN_B7  

#define lcd_output_dir_bl()      output_drive(LCD_BL_PIN)
#define lcd_output_bl(x)         output_bit(LCD_BL_PIN,x)

#define lcd_output_dir_enable()  output_drive(LCD_ENABLE_PIN)
#define lcd_output_enable(x)     output_bit(LCD_ENABLE_PIN,x)

#define lcd_output_dir_rs()      output_drive(LCD_RS_PIN)
#define lcd_output_rs(x)         output_bit(LCD_RS_PIN,x)

#define lcd_output_dir_rw()      output_drive(LCD_RW_PIN)
#define lcd_output_rw(x)         output_bit(LCD_RW_PIN,x)

#define lcd_output_dir_data4()   output_drive(LCD_DATA4_PIN)
#define lcd_input_dir_data4()    output_float(LCD_DATA4_PIN)
#define lcd_output_data4(x)      output_bit(LCD_DATA4_PIN,x)
#define lcd_input_data4()        input_state(LCD_DATA4_PIN)

#define lcd_output_dir_data5()   output_drive(LCD_DATA5_PIN)
#define lcd_input_dir_data5()    output_float(LCD_DATA5_PIN)
#define lcd_output_data5(x)      output_bit(LCD_DATA5_PIN,x)
#define lcd_input_data5()        input_state(LCD_DATA5_PIN)

#define lcd_output_dir_data6()   output_drive(LCD_DATA6_PIN)
#define lcd_input_dir_data6()    output_float(LCD_DATA6_PIN)
#define lcd_output_data6(x)      output_bit(LCD_DATA6_PIN,x)
#define lcd_input_data6()        input_state(LCD_DATA6_PIN)

#define lcd_output_dir_data7()   output_drive(LCD_DATA7_PIN)
#define lcd_input_dir_data7()    output_float(LCD_DATA7_PIN)
#define lcd_output_data7(x)      output_bit(LCD_DATA7_PIN,x)
#define lcd_input_data7()        input_state(LCD_DATA7_PIN)

void lcd_send_data(BYTE lcd_dat);
void lcd_send_command(BYTE lcd_cmd);
BYTE lcd_read_data(void);
BYTE lcd_read_command(void);
void lcd_init(void);
void lcd_set_cursor(BYTE cursor);
void lcd_putc(char c);
char lcd_getc(BYTE cursor);

/****************/
/* Main Program */
/****************/
void main() 
{
  setup_oscillator(OSC_8MHZ|OSC_PLL_ON);                                      // Sets the Internal Oscillator to 32MHz (PLL Enabled)
  lcd_init();                                                                 // Initial CLCD 4 Bit Mode
  
  while(true)
  {     
    lcd_set_cursor(0x00);                                                     // Start Line(1)           
    printf(lcd_putc,"(ET-BASE PIC16F)");
    lcd_set_cursor(0x40);                                                     // Start Line(2)
    printf(lcd_putc,">>ETT CO.,LTD.<<");    
    delay_ms(2000);
    
    lcd_set_cursor(0x00);                                                     // Start Line(1)
    printf(lcd_putc,"(WWW.ETTEAM.COM)");    
    lcd_set_cursor(0x40);                                                     // Start Line(2)
    printf(lcd_putc,"MCU : PIC16F1939");    
    delay_ms(2000);
  }  
}

/******************************/
/* Write CLCD Data 4 Bit Mode */
/******************************/
void lcd_send_data(BYTE lcd_dat) 
{ 
  while((lcd_read_command() & 0x80) == 0x80);                                 // Wait Busy(D7) = 0
  
  lcd_output_rs(1);                                                           // Select Data 
  lcd_output_rw(0);                                                           // Write Bus
  lcd_output_data7(((lcd_dat & 0x80)>>7));                                    // High Nibble Data            
  lcd_output_data6(((lcd_dat & 0x40)>>6));
  lcd_output_data5(((lcd_dat & 0x20)>>5));
  lcd_output_data4(((lcd_dat & 0x10)>>4));
  delay_cycles(1);
  lcd_output_enable(1);                                                       // Start of Strobe Write
  delay_us(2);                                                                // Enable Pulse Delay
  lcd_output_enable(0);                                                       // End of Strobe    
  delay_us(150);                                                              // Wait Nibble Delay 100uS++  
  lcd_output_data7(((lcd_dat & 0x08)>>3));                                    // Low Nibble Data
  lcd_output_data6(((lcd_dat & 0x04)>>2));
  lcd_output_data5(((lcd_dat & 0x02)>>1));
  lcd_output_data4((lcd_dat & 0x01));
  delay_cycles(1);
  lcd_output_enable(1);                                                       // Start of Strobe Write
  delay_us(2);                                                                // Enable Pulse Delay
  lcd_output_enable(0);                                                       // End of Strobe  
}

/*************************************/
/* Write CLCD Instruction 4 Bit Mode */
/*************************************/
void lcd_send_command(BYTE lcd_cmd) 
{
  while((lcd_read_command() & 0x80) == 0x80);                                 // Wait Busy(D7) = 0
 
  lcd_output_rs(0);                                                           // Select Instruction 
  lcd_output_rw(0);                                                           // Write Bus
  lcd_output_data7(((lcd_cmd & 0x80)>>7));                                    // High Nibble Data
  lcd_output_data6(((lcd_cmd & 0x40)>>6));
  lcd_output_data5(((lcd_cmd & 0x20)>>5));
  lcd_output_data4(((lcd_cmd & 0x10)>>4));
  delay_cycles(1);
  lcd_output_enable(1);                                                       // Start of Strobe Write
  delay_us(2);                                                                // Enable Pulse Delay
  lcd_output_enable(0);                                                       // End of Strobe  
  delay_us(150);                                                              // Wait Nibble Delay 100uS++    
  lcd_output_data7(((lcd_cmd & 0x08)>>3));                                    // Low Nibble Data
  lcd_output_data6(((lcd_cmd & 0x04)>>2));
  lcd_output_data5(((lcd_cmd & 0x02)>>1));
  lcd_output_data4((lcd_cmd & 0x01));
  delay_cycles(1);
  lcd_output_enable(1);                                                       // Start of Strobe Write
  delay_us(2);                                                                // Enable Pulse Delay
  lcd_output_enable(0);                                                       // End of Strobe
}

/*****************************/
/* Read CLCD Data 4 Bit Mode */
/*****************************/
BYTE lcd_read_data(void) 
{
  BYTE dat_read = 0x00;
  
  lcd_input_dir_data4();                                                      // Data = Input(Read Bus)
  lcd_input_dir_data5();
  lcd_input_dir_data6();
  lcd_input_dir_data7();    
  lcd_output_rs(1);                                                           // Select Data 
  lcd_output_rw(1);                                                           // Read Bus  
  delay_cycles(1);   
  
  lcd_output_enable(1);                                                       // Start of Strobe Read
  delay_us(1);    
  dat_read |= input(LCD_DATA7_PIN) << 7;                                      // Data D7
  dat_read |= input(LCD_DATA6_PIN) << 6;                                      // Data D6
  dat_read |= input(LCD_DATA5_PIN) << 5;                                      // Data D5
  dat_read |= input(LCD_DATA4_PIN) << 4;                                      // Data D4  
  delay_us(1);
  lcd_output_enable(0);                                                       // End of Strobe    
  delay_us(150);                                                              // Wait Nibble Delay 100uS++  
  lcd_output_enable(1);                                                       // Start of Strobe Read
  delay_us(1);  
  dat_read |= input(LCD_DATA7_PIN) << 3;                                      // Data D3
  dat_read |= input(LCD_DATA6_PIN) << 2;                                      // Data D2
  dat_read |= input(LCD_DATA5_PIN) << 1;                                      // Data D1
  dat_read |= input(LCD_DATA4_PIN);                                           // Data D0  
  delay_us(1);  
  lcd_output_enable(0);                                                       // End of Strobe
  
  lcd_output_dir_data4();                                                     // Data = Output(Write Bus)
  lcd_output_dir_data5();
  lcd_output_dir_data6();
  lcd_output_dir_data7();
     
  return(dat_read);
}

/***********************************/
/* Read CLCD Instruction 4Bit Mode */
/***********************************/
BYTE lcd_read_command(void) 
{  
  BYTE cmd_read = 0x00;
  
  lcd_input_dir_data4();                                                      // Data = Input(Read Bus)
  lcd_input_dir_data5();
  lcd_input_dir_data6();
  lcd_input_dir_data7();    
  lcd_output_rs(0);                                                           // Select Instruction 
  lcd_output_rw(1);                                                           // Read Bus  
  delay_cycles(1);   
  
  lcd_output_enable(1);                                                       // Start of Strobe Read
  delay_us(1);    
  cmd_read |= input(LCD_DATA7_PIN) << 7;                                      // Data D7
  cmd_read |= input(LCD_DATA6_PIN) << 6;                                      // Data D6
  cmd_read |= input(LCD_DATA5_PIN) << 5;                                      // Data D5
  cmd_read |= input(LCD_DATA4_PIN) << 4;                                      // Data D4  
  delay_us(1);
  lcd_output_enable(0);                                                       // End of Strobe    
  delay_us(150);                                                              // Wait Nibble Delay 100uS++  
  lcd_output_enable(1);                                                       // Start of Strobe Read
  delay_us(1);  
  cmd_read |= input(LCD_DATA7_PIN) << 3;                                      // Data D3
  cmd_read |= input(LCD_DATA6_PIN) << 2;                                      // Data D2
  cmd_read |= input(LCD_DATA5_PIN) << 1;                                      // Data D1
  cmd_read |= input(LCD_DATA4_PIN);                                           // Data D0  
  delay_us(1);  
  lcd_output_enable(0);                                                       // End of Strobe
  
  lcd_output_dir_data4();                                                     // Data = Output(Write Bus)
  lcd_output_dir_data5();
  lcd_output_dir_data6();
  lcd_output_dir_data7();
     
  return(cmd_read);
}

/*******************************/
/* Initial LCD 4 Bit Interface */
/*******************************/
void lcd_init(void) 
{
  lcd_output_dir_bl();                                                        // Blacklight = Output
  lcd_output_bl(1);                                                           // ON Blcaklight LED
  
  lcd_output_dir_data4();                                                     // Data = Output
  lcd_output_dir_data5();
  lcd_output_dir_data6();
  lcd_output_dir_data7();
  lcd_output_dir_rs();
  lcd_output_dir_rw();
  lcd_output_dir_enable();
  
  lcd_output_rs(0);
  lcd_output_rw(0);
  lcd_output_enable(0);
  lcd_output_data4(0);
  lcd_output_data5(0);
  lcd_output_data6(0);
  lcd_output_data7(0);
  delay_ms(15);                                                               // Power-ON Delay (minimum of 15ms) 
  
  lcd_output_data4(1);
  lcd_output_data5(1);
  lcd_output_data6(0);
  lcd_output_data7(0);
  delay_cycles(1);
  lcd_output_enable(1);                                                       // Enable Strobe
  delay_us(2);                                                                // Enable Pulse Delay
  lcd_output_enable(0);                                                       // Disable Strobe
  delay_ms(5);                                                                // 4.1mS++  
  lcd_output_data4(1);
  lcd_output_data5(1);
  lcd_output_data6(0);
  lcd_output_data7(0);
  delay_cycles(1);
  lcd_output_enable(1);                                                       // Enable Strobe
  delay_us(2);                                                                // Enable Pulse Delay
  lcd_output_enable(0);                                                       // Disable Strobe
  delay_us(150);                                                              // 100uS++
  
  lcd_send_command(0x32);                                                     // Initial 4 Bit Interface Format  
  lcd_send_command(0x28);                                                     // Function Set (DL=0 4-Bit,N=1 2 Line,F=0 5X7)                     
  lcd_send_command(0x0C);                                                     // Display on/off Control (Entry Display,Cursor off,Cursor not Blink)
  lcd_send_command(0x06);                                                     // Entry Mode Set (I/D=1 Increment,S=0 Cursor Shift)     
  lcd_send_command(0x01);                                                     // Clear Display  (Clear Display,Set DD RAM Address=0) 
  delay_ms(2);                                                                // 1.64mS++  
  lcd_set_cursor(0x00);                                                       // Start Line(1)
}

/******************************/
/* Set CLCD Cursor 4 Bit Mode */
/******************************/
void lcd_set_cursor(BYTE cursor) 
{
  lcd_send_command(cursor|0x80);                                              // Set Cursor(DD RAM Address)    
}

/******************************/
/* Write CLCD Data 4 Bit Mode */
/******************************/
void lcd_putc(char c) 
{
  switch (c) 
  {
    case '\f'  : lcd_send_command(0x01);    
                 delay_ms(2);                                                 // 1.64mS++  
                 break;
                 
    case '\n'  : lcd_set_cursor(0x00);        
                 break;
                 
    case '\b'  : lcd_send_command(0x10);  
                 break;
                 
    default    : lcd_send_data(c);     
                 break;
  }
}

/*****************************/
/* Read CLCD Data 4 Bit Mode */
/*****************************/
char lcd_getc(BYTE cursor) 
{
  char value;

  lcd_set_cursor(cursor);
  value = lcd_read_data();
 
  return(value);
}

