//**************************************
// Функции работы с ЖКИ для Победителя
// Версия 1.0
//
// Arsen: для колмпилятора WinAVR 20060125
//**************************************

#include <avr/io.h>
#include <util/delay.h>

#define D7        PB3
#define D6        PB2
#define D5        PB1
#define D4        PB0
#define E         PB4
#define RW        PB5
#define RS        PB6


// определяем светодиод
#define LED_OFF (PORTD |= (1<<6))
#define LED_ON (PORTD &= ~(1<<6))


#define SET_D7        (PORTB |= (1<<3))
#define SET_D6        (PORTB |= (1<<2))
#define SET_D5        (PORTB |= (1<<1))
#define SET_D4        (PORTB |= (1<<0))

//#define SET_RW (PORTB |= (1<<5))
//#define CLR_RW (PORTB &= ~(1<<5))
#define SET_RS (PORTB |= (1<<6))
#define CLR_RS (PORTB &= ~(1<<6))
#define SET_E  (PORTB |= (1<<4))
#define CLR_E  (PORTB &= ~(1<<4))

// ЖКИ подключен младшему полубайту порта PB!
#define WRITE_HIGH_NIBBLE(x)  ( PORTB = (PORTB & 0xF0) | ((x) >> 4) )
#define WRITE_LOW_NIBBLE(x) ( PORTB = (PORTB & 0xF0) | ((x) & 0x0F) )

#define MKS_PBYT 2 /* время на передачу полубайта на дисплей */
#define MKS_BYTE 40 /* время после передачи байта на дисплей */

#define PAGE0 0x28 // Первая кодовая страница
#define PAGE1 0x2A // Вторая кодовая страница

//**************************************
//          P R O T O T Y P E
//**************************************
void LINE_LETTER_LCD(void);
void RUN_LETTER_LCD(unsigned char ch);
void LIST_LETTER_LCD(unsigned char ch);
void CLR_ALL(void);
void BLINK_LED (void);
void PRINT_LCD(char);
void WRITE_LCD(char);
void _E (void);
void _Epb (void);
void _RS (void);
void INIT_LCD(void);
void CLR_LCD(void);
void GOTO_XY_LCD(unsigned char,unsigned char);
void PR_STR_LCD(char *);
void Delay_50ms(int t);

//**************************************
//            M A I N
//**************************************
int main(void)
{

  DDRB  = 0xff;  // назначаем все линии порта B на выход
  PORTB = 0x00;  // и устанавливаем на них низкий уровень
  DDRD  = 0xff;  // назначаем все линии порта D на вывход
  PORTD = 0x00;  // и устанавливаем на них низкий уровень
  LED_OFF;

	BLINK_LED ();
	INIT_LCD();

// вывод знакогенераторов
	GOTO_XY_LCD(1,1); PR_STR_LCD("Code Page 0\0");
	BLINK_LED (); 
	WRITE_LCD(PAGE0); // кодовая страница 0

	CLR_LCD();
	LINE_LETTER_LCD();

// Выводим первые знаки алфавитов первой кодовой страницы
	CLR_LCD();
	LIST_LETTER_LCD(0x40);
	BLINK_LED (); 
	RUN_LETTER_LCD(0x40);
	CLR_LCD();
	LIST_LETTER_LCD(0x60);
	BLINK_LED (); BLINK_LED ();
	RUN_LETTER_LCD(0x60);
// значки и цифры
	CLR_LCD();
	LIST_LETTER_LCD(0x00);
	BLINK_LED (); 
	RUN_LETTER_LCD(0x00);
	CLR_LCD();
	LIST_LETTER_LCD(0x20);
	BLINK_LED (); BLINK_LED ();
	RUN_LETTER_LCD(0x20);


	CLR_LCD();
	GOTO_XY_LCD(1,2); PR_STR_LCD("Code Page 1\0");
	BLINK_LED ();
	WRITE_LCD(PAGE1); // кодовая страница 1
	CLR_LCD();
	LINE_LETTER_LCD();

	// Выводим первые  знаки алфавитов второй кодовой страницы
	// если она есть, клнечно. Иначе будет копия первой страницы.
	CLR_LCD();
	LIST_LETTER_LCD(0x40);
	BLINK_LED ();
	RUN_LETTER_LCD(0x40);
	CLR_LCD();
	LIST_LETTER_LCD(0x60);
	BLINK_LED (); BLINK_LED ();
	RUN_LETTER_LCD(0x60);

// значки и цифры
	CLR_LCD();
	LIST_LETTER_LCD(0x00);
	BLINK_LED (); 
	RUN_LETTER_LCD(0x00);
	CLR_LCD();
	LIST_LETTER_LCD(0x20);
	BLINK_LED (); BLINK_LED ();
	RUN_LETTER_LCD(0x20);

// Выводим адрес сайта "Железный фелкс"
	CLR_LCD();
	GOTO_XY_LCD(3,1); PR_STR_LCD("ironfelix.ru\0");
	BLINK_LED ();


// проверяем способность выводить русско-нурусский текст.
// Этот текст правильно отображают не все ЖКИ.
// некоторым требуется перекодировка русских букв.
	CLR_LCD();
	GOTO_XY_LCD(1,1); PR_STR_LCD("Проект Conqeror,\0");
	GOTO_XY_LCD(3,2); PR_STR_LCD("\"Победитель\"\0");


while(1);
}

//*********************************************************
// Функции для ЖКИ
//*********************************************************

/**********************************************************
Имя функции:    void LINE_LETTER_LCD(void)
Описание:       Вывод двух первых строк текущей кодовой страницы ЖКИ
Вход:           нет
Выход:          нет
Примечание:     Arsen, редакция от 27.05.2006
**********************************************************/

void LINE_LETTER_LCD(void) {

	unsigned char ch, i;
	ch = 0;
	for (i=0;i<16;i++) {
		GOTO_XY_LCD(i+1,1);
		PRINT_LCD(ch); 
		GOTO_XY_LCD(i+1,2);
		PRINT_LCD(ch + 0x01); 
		ch= ch + 0x10;
	}
	BLINK_LED ();
}

/**********************************************************
Имя функции:    void RUN_LETTER_LCD(unsigned char ch)
Описание:       Вывод бегущей строкой двух колонок знакогенератора ЖКИ
Вход:           ch -> код первого выводимого симпола
Выход:          нет
Примечание:     Arsen, редакция от 27.05.2006
**********************************************************/

void RUN_LETTER_LCD(unsigned char ch) {

	unsigned char ch1, n, k;
	// БЕгущая строка
	ch1 = ch;
	k = 0;
	for (n=0;n<17;n++) {
		LED_ON;
		LIST_LETTER_LCD(ch);
		k = k + 0x01;
		ch = ch1 + k;
		Delay_50ms(5);  // пауза 250 ms
		LED_OFF;
		Delay_50ms(5);  // пауза 250 ms
	}
	BLINK_LED ();
	BLINK_LED ();
}

/**********************************************************
Имя функции:    void LIST_LETTER_LCD(unsigned char ch)
Описание:       вывод 16 знаков текущей кодовой страницы ЖКИ
Вход:           ch -> код первого выводимого симпола
Выход:          нет
Примечание:     Arsen, редакция от 17.05.2006
**********************************************************/

void LIST_LETTER_LCD(unsigned char ch) {

	unsigned char i;
	for (i=0;i<16;i++) {
		GOTO_XY_LCD(i+1,1);
		PRINT_LCD(ch); 
		GOTO_XY_LCD(i+1,2);
		PRINT_LCD(ch + 0x80); 
		ch = ch + 0x01;
	}
}



/**********************************************************
Имя функции:    void CLR_LCD(void)
Описание:       Очистка экрана ЖКИ
Вход:           нет
Выход:          нет
Примечание:     Arsen, редакция от 17.05.2006
**********************************************************/

void CLR_LCD()
{
WRITE_LCD (0x01);
_delay_ms(3);
}


/**********************************************************
Имя:        Goto_XY_LCDXY(unsigned char x, unsigned char y)
Описание:   Установка курсора в желаемую позицию на экране ЖКИ
Вход:       X -> X позиция в строке на экране ЖКИ
            Y -> Y номер Строки на экране ЖКИ
Выход:      нет
Misc:	   Arsen, редакция от 17.04.2006
**********************************************************/

void GOTO_XY_LCD(unsigned char x,unsigned char y)
{
unsigned char address;

x--;
if (y > 1) {address = 64 + x;}
else {address = x;}
  WRITE_LCD(address | 0x80); 
}


/**********************************************************
Name:          PR_STR_LCD(char *ptr)
Description:   Вывод текстовой строки на ЖКИ-дисплей 
Input:         Укзатель на строку
Output:        Нет
Misc:         Arsen, редакция от 17.05.2006       
**********************************************************/
void PR_STR_LCD(char *ptr)
{
unsigned char i;

for (i=1;i<41;i++)
   {
   if (*ptr == 0x00) break;
   PRINT_LCD(*ptr);
   *ptr++ = 0x00;
   }
}



/**********************************************************
Имя функции:    void Delay_50ms(int t)
Описание:       Задержка, кратная 50 ms
Вход:           t -> Число повторов цикла 
Выход:          нет
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

void Delay_50ms(int t) {
  unsigned int i;
  for(i=0;i<t; i++) {
  _delay_ms(50);
  }
}

//**************************************************************************************

/**********************************************************
Имя функции:    void _E(void)
Описание:       выдача сигнала "Е" на ЖКИ с полным временем
                ожидания (после выдачи всей команды) 
Вход:           нет
Выход:          нет
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

void _E (void)
{
	_delay_us(MKS_PBYT); 
	SET_E;
	_delay_us(MKS_PBYT);
	CLR_E;
	_delay_us(MKS_BYTE);		//пауза между командами
}	
/**********************************************************
Имя функции:    void _Epb(void)
Описание:       выдача сигнала "Е" на ЖКИ с укороченным временем
                ожидания (между вводом полубайтов) 
Вход:           нет
Выход:          нет
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

void _Epb (void)
{
	_delay_us(MKS_PBYT); 
	SET_E;
	_delay_us(MKS_PBYT);
	CLR_E;
	_delay_us(MKS_PBYT);		// пауза между полубайтами
}	

/**********************************************************
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

// Дернуть "RS"  перед передачей старшего полубайта, по рекомендации МЭЛТ
void _RS (void)
{
	_delay_us(MKS_PBYT); 
	SET_RS;
	_delay_us(MKS_PBYT);
	CLR_RS;
	_delay_us(MKS_PBYT);
}	

/**********************************************************
Имя функции:    void WRITE_LCD(unsigned char ch)
Описание:       Запись байта команды в ЖКИ 
Вход:           ch -> байт для записи
Выход:          нет
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

void WRITE_LCD(char value) {
	_delay_us(MKS_PBYT);
	WRITE_HIGH_NIBBLE(value);
	_Epb();
	WRITE_LOW_NIBBLE(value);
	_E();
  _delay_us(MKS_BYTE);
}

/**********************************************************
Имя функции:    void PRINT_LCD(unsigned char ch)
Описание:       Вывод символа на экран ЖКИ 
Вход:           ch -> Символ (код символа) для вывода
Выход:          нет
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

void PRINT_LCD(char value) {
	SET_RS;
	WRITE_LCD (value);
	CLR_RS;
	_delay_us(MKS_BYTE);
}
/**********************************************************
Имя функции:    void BLINK_LED(void)
Описание:       Вспышка светодиода на порту PD6 
Вход:           нет
Выход:          нет
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

void BLINK_LED (void)
{
	Delay_50ms(50);
    LED_ON; // Зажигаем LED
	Delay_50ms(5);  // пауза 250 ms
    LED_OFF; // гасим LED
	Delay_50ms(15);  // Всего 500 ms
//	Delay_50ms(50);  // с этой строкой 1 сек.
}

/**********************************************************
Имя функции:    void CLR_ALL(void)
Описание:       Очистка порта вывода на ЖКИ 
Вход:           нет
Выход:          нет
Примечание:     Arsen, редакция от 17.04.2006
**********************************************************/

void CLR_ALL(){
 
 PORTB = 0x00;  // устанавливаем на PB низкий уровень

}
//**************************************************************************************
//**************************************************************************************

/**********************************************************
Имя функции:    void INIT_LCD(void)
Описание:       Начальная инициализация ЖКИ 
Вход:           нет
Выход:          нет
Примечание:     Arsen, редакция от 17.05.2006
**********************************************************/

void INIT_LCD(void)
{
CLR_ALL();
_delay_ms(MKS_BYTE); // ждем более 30 мс

// Трижды устанавливаем 8-битный режим - начальная инициализация 
	SET_D5; SET_D4;    // команда "8-битный режим"
    _E();
    _E();
    _E();

/***/

	CLR_ALL();
	SET_D5;           // Переводим в 4-битный режим
    _E();

/***************************************************/

WRITE_LCD(0x2A);
WRITE_LCD(0x0C);
CLR_LCD();
WRITE_LCD(0x06);


}



