/****************************************************************************
*	lcd.c 
*	LCD-Funktionen
*	Version: 2.0
*	11.05.2005
*	Gaston K
*
* CPU: ATmega8515
* LCD: 2x16 Zeichen, HD44780 kompatibel
* Ansteuerung im 4-Bit Modus
****************************************************************************/

#include <stdio.h>		// Bibliothek der Standardfunktionen von C
#include <io.h>			// I/O's des Controllers
#include <stdint.h>	// Datentypen Definition:
								//	int8_t (für Variablen von -128...127) 
								//	uint8_t (für Variablen von 0...255)
								//	int16_t (für Variablen von -32768...32767)
								//		...
								//	uint64_t (für Variablen von 0...2^64(-1))
#include <delay.h>	// Zeitverzögerungsfunktionen
/****************************************************************************/
#define		function			0b00101000 		// LCD Functionset
#define 		entry				0b00000110		// LCD Eingabemodus
#define		on				0b00001110		// LCD ein, Cursor ein, Blinken aus
#define 		off					0b00001000		// LCD Aus
#define 		cur_on			0b00001110		// LCD Cursor ein
#define 		cur_off			0b00001100		// LCD Cursor aus
#define 		cur_blink_on	0b00001101		// LCD Cursor blink
#define 		cur_blink_off	0b00001110		// LCD Cursor blink aus
#define 		shift_left		0b00000110		// LCD Scrollen (Links)
#define 		shift_right		0b00000100		// LCD Scrollen (Rechts)
#define 		clr 				0b00000001		// LCD Löschen
#define 		home 			0x02		// LCD Home
#define 		line1				0x00		// LCD Linie 1
#define 		line2				0x40		// LCD Linie 2

#define RS_MASK			0x10
#define EN_MASK			0x20

#define LCD_PORT		PORTC
#define LCD_DDR			DDRC

/****************************************************************************
*  lcd_command(<8bit befehl>) 
*  Instruktionsübertragung an LCD im 4-Bit Modus
****************************************************************************/
void lcd_command(uint8_t x){
	uint8_t	y;					// Temporäre Hilfsvarible initialisieren
	y = x;						// Kommandobefehl kopieren
	x >>= 4;					// High-Nibble in Low-Nibble verschieben
	x &= 0x0f;					// Maske über Low-Nibble setzen
	LCD_PORT = x;		// erster Teil des Kommandos an das LCD ausgeben
	LCD_PORT |= EN_MASK;  // Enable bit setzen
	_delay_ms(1);			
	LCD_PORT &= ~EN_MASK; // Enable bit wieder löschen
		
	y &= 0x0f;				// Das untere Nibble des Kommandos freistellen
	LCD_PORT = y;	// zweiter Teil des Kommandos an das LCD ausgeben
	LCD_PORT |= EN_MASK;  // Enable bit setzen
	_delay_ms(1);		// Enable Signal liegt 1 ms t[w] am Port. Das Kommando
	LCD_PORT &= ~EN_MASK;  // Enable bit wieder löschen
	_delay_ms(2);
}

/****************************************************************************
*  lcd_init() 
*  Initialisierung des LCD's
****************************************************************************/
void lcd_init(void)
{
	_delay_ms(100);		//100ms warten
	lcd_command(function);	// function set: 4bit, 2line, 5x8dots
	lcd_command(on);		//lcd ein
	lcd_command(clr);		//lcd löschen
	_delay_ms(4);
	lcd_command(entry);	//entry mode: increment mode, entrie shift off
	_delay_ms(100);
}

/****************************************************************************
*  lcd_ram(<DDRAM Adresse>) 
*  DDRAM Adresse bestimmen
****************************************************************************/
void lcd_ram(uint8_t position)
{
	position |= 0b10000000;	// Maske für DDRAM-Adresse
	lcd_command(position);
}

/****************************************************************************
*  lcd_char(<ASCII-Zeichen>) 
*  ASCII Zeichen auf das LCD ausgeben
****************************************************************************/
void lcd_char(uint8_t zeichen)
{
	uint8_t zeichen2;		// Temporäre Hilfsvarible initialisieren
	zeichen2 = zeichen; 	// Charakter kopieren
	zeichen >>= 4;			// High-Nibble in Low-Nibble verschieben
	zeichen &= 0xff;
	zeichen |= RS_MASK;  // Maske über Low-Nibble setzen
	LCD_PORT = zeichen;  // erster Teil des Zeichens an das LCD ausgeben
	LCD_PORT |= EN_MASK;  // Enable bit setzen
	_delay_ms(1);
	LCD_PORT &= ~EN_MASK; // Enable bit wieder löschen
	
	zeichen2 &= 0x0f;  // Low-Nibble freistellen
	zeichen2 |= RS_MASK; // Maske über Low-Nibble setzen
	LCD_PORT = zeichen2; // zweiter Teil des Zeichens an das LCD ausgeben
	LCD_PORT |= EN_MASK;  // Enable bit setzen
	_delay_ms(1);
	LCD_PORT &= ~EN_MASK;  // Enable bit wieder löschen
}

/****************************************************************************
*  lcd_str(<Pointer auf ein Array>) 
*  Strin auf LCD ausgeben
****************************************************************************/
void lcd_print(uint8_t *string)
{
	uint8_t count =	0;			// Zähler löschen
	lcd_ram(line1);				// Cursor auf Anfang setzen 
	
	while(*string != '\0')		// bis String-Abschlusszeichen \0
	{
		count++ ;					// Zähler inkrementieren
		lcd_char(*string);		// Zeichen übergeben
		string++;					// Pointer auf nächstes Zeichen
		_delay_ms(1);
		if(count == 16)			// Wenn der Strin länger als 16 Zeichen
			{							// ist, wird der Text auf Zeile2 fortgesetzt.
			lcd_ram(line2);		// DDRAM Adresse Zeile2
			}
	}
}

/********************* Hauptprogramm **********************************
*  Demonstration der LCD Funktion
****************************************************************************/
int main (void)
{
	LCD_DDR = 0xff;		// Port für LCD
	
	uint8_t text1[] = {"-> Hallo Welt <-"}; 
	uint8_t text2[] = {"Hier spricht das LCD!"};
	uint8_t i;
	
	_delay_ms(50);
	
	lcd_init();
	lcd_command(cur_off);
	
	for(;;)
	{
		lcd_command(clr);
		lcd_print(text1);
		for(i = 0; i <100; i++)  // 3 sek warten
		{
			_delay_ms(30);
		}	
		
		lcd_command(clr);
		lcd_print(text2);
		for(i = 0; i <100; i++)  // 3 sek warten
		{
			_delay_ms(30);
		}
	}
}


