//Подключение к микроконтроллеру PIC16F628A, с кварцем 4 МГц (20 МГц), 
//LCD дисплея на микроконтроллере HD44780 (применялся дисплей WH1602A 2x16). 
//Линия RS к RA1, E к RA0, DB4 к RB4, DB5 к RB5, DB6 к RB6, DB7 к RB7.

#include <pic16f62xa.h>

void low_init()
{
	CMCON=0x07;		//	отключение компаратора
	TRISA=0x00;
	TRISB=0x00;
}

#define RS_1 RA1 = 1	//	RA1
#define E_1  RA0 = 1	//	RA0
#define RS_0 RA1 = 0	//	RA1
#define E_0  RA0 = 0	//	RA0

const unsigned char addLUT[4] = {0x80, 0xC0, 0x94, 0xD4};
unsigned char LCD_Address, LCD_Line;
unsigned int PreviousTime;
char buffer[15];
  
void delay(unsigned int p)
{
  unsigned int i;
  for(i=0;i<p;i++){asm("NOP");}
}

void WriteNibble(unsigned char data)
{
  E_1;
  PORTB = (data & 0x0F)*16;
  E_0;
  delay(300);
}

void WriteByte(unsigned char data)
{
  E_1;
  PORTB = (data >> 4)*16;
  E_0;
  E_1;
  PORTB = (data & 0xF)*16;
  E_0;
  delay(300);
}

void GoToLine(char LineNum)
{
  RS_0;
  LCD_Address = addLUT[LineNum-1];
  WriteByte(LCD_Address);
  RS_1;
  LCD_Address = 0;
  LCD_Line = LineNum;
}

void ClearLCD(void)
{
  RS_0;
  WriteByte(0x01);
  delay(1000);
  RS_1;
  GoToLine(1);
}

void SetLCDPosition(char row, char col)
{
  RS_0;
  LCD_Address = addLUT[row-1] + col;
  WriteByte(LCD_Address);
  RS_1;
  LCD_Line = row;
}

void ShowChar(unsigned char c)
{
  RS_1;
  WriteByte(c);
  LCD_Address++;
  if(LCD_Address>15)		//	указывается размер строки, в данном случае для 16 символьного индикатора
  {
    switch (LCD_Line)		//	здесь указываются переход с одной строки на другую, в данном случае адрес указан на 2-х строчный индикатор
    {
      case 1: GoToLine(2); break;
      case 2: GoToLine(1); break;
//      case 3: GoToLine(4); break;
//      case 4: GoToLine(1); break;
    }
  }
}

void ShowStr(unsigned char *s)
{
  while (*s != 0) ShowChar(*s++);
}

void InitLCD(void)
{
  int i;
  E_0;
  RS_0;
  delay(5000);
  WriteNibble(0x33);
  WriteNibble(0x33);
  WriteNibble(0x33);
  WriteNibble(0x22);
  WriteByte(0x28);
  WriteByte(0x01);
  WriteByte(0x10);
  WriteByte(0x06);
  WriteByte(0x0C);
  for(i=0x40; i<0x5F; i++)
  {
    delay(1000);
    RS_0;
    WriteByte(i);
    delay(1000);
    ShowChar(0);
  }
  RS_1;
  SetLCDPosition(1, 0);
  buffer[0] = 'O';
  buffer[1] = 'k';
  buffer[2] = '\0';
  ShowStr(buffer);
}

void main()
{
  low_init();
  delay(10000);
  InitLCD();
  delay(100000);
  ClearLCD();
  
  SetLCDPosition(1, 0);
  buffer[0] = 'A';
  buffer[1] = 'l';
  buffer[2] = 'e';
  buffer[3] = 'x';
  buffer[4] = '\0';
  ShowStr(buffer);
}
