#include <16F887.h>

#use delay (clock=20000000)
#use fast_io(B)

#FUSES INTRC,NOWDT,NOPUT,NOMCLR,NOPROTECT,NOCPD,NOBROWNOUT,NOIESO,NOFCMEN,NOLVP

#define LCD_DB4   PIN_C4
#define LCD_DB5   PIN_C5
#define LCD_DB6   PIN_C6
#define LCD_DB7   PIN_C7

#define LCD_RW    PIN_C2
#define LCD_E     PIN_C3
#define LCD_RS    PIN_C1

#define lcd_type 2        // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line


int8 const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
 0xc,                    // Display on
 1,                      // Clear display
 6                       // Increment cursor
 };
                             

//-------------------------------------
void lcd_send_nibble(int8 nibble)
{

 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2)); 
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;

#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;
   
output_high(LCD_E);
delay_cycles(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
 
output_low(LCD_E);
   
return(retval);   
}   
#endif


#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif


void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60); 
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);
     
 delay_cycles(1);

#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}


void lcd_init(void)
{
int8 i;

output_low(LCD_RS);

#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif

output_low(LCD_E);

delay_ms(15);

for(i=0 ;i < 3; i++)
   {
    lcd_send_nibble(0x03);
    delay_ms(5);
   }

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
    lcd_send_byte(0, LCD_INIT_STRING[i]);
   

    #ifndef USE_LCD_RW
    delay_ms(5);
    #endif
   }

}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;

if(y != 1)
   address = lcd_line_two;
else
   address=0;

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      delay_ms(2);
      break;
   
    case '\n':
       lcd_gotoxy(1,2);
       break;
   
    case '\b':
       lcd_send_byte(0,0x10);
       break;
   
    default:
       lcd_send_byte(1,c);
       break;
   }
}




void init_io()
{
      SET_TRIS_B(0x01);

      OUTPUT_A(0x00);
      OUTPUT_C(0x00);
      OUTPUT_D(0x00);
}

void lcdbe()
{
      OUTPUT_A(0b10110000); //6 - kontraszt, 7 - hattervilagitas, 0 - lcd0, 1 - lcd1, 2 - lcd2, 3 - lcd3
}

void main()
{
   lcd_init();
   
      int menulepteto = 0;
      int gombnyomas = 0;
      int led = 0x00;
      
      init_io();
      
      while(TRUE)
      {
         if(INPUT_STATE(PIN_B0) == 0)
         {
            delay_ms(100);
            
            gombnyomas++;
            
            if(gombnyomas == 5) //hosszúgombnyomás
            {
                  menulepteto++;
            }
         }
         else
         {
            if (gombnyomas < 4 && gombnyomas > 0) //rövid gombnyomás
            {
                        led++;
                     
                        OUTPUT_D(led);
            }
         
            gombnyomas = 0;
         }            
         
         switch(menulepteto)
         {
            case 1:
            lcdbe();
            OUTPUT_D(0b00000001);
            menulepteto++;
            break;
   
            case 3:
            lcd_putc("\fReady...\n");
            OUTPUT_D(0b00000010);
            menulepteto++;
            break;
            
            case 5:
            lcd_putc("\f");
            OUTPUT_D(0b00000100);
            menulepteto++;
            break;
         }
      }
}
