 
#include <avr/io.h>
#include "LCD.h"
#include <util/delay.h>
#include <stdlib.h>

unsigned char Zeichen1[8] = { // ++
	0b00000100,
	0b00001110,
	0b00000100,
	0b00000000,
	0b00000100,
	0b00001110,
	0b00000100,
	0b00000000
};

unsigned char Zeichen2[8] = { // +
	0b00000000,
	0b00000000,
	0b00000100,
	0b00001110,
	0b00000100,
	0b00000000,
	0b00000000,
	0b00000000
};

////////////////////////////////////////////////////////////////////////////////
// Erzeugt einen Enable-Puls
static void lcd_enable( void )
{
    LCD_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
   _delay_us( LCD_ENABLE_US );  // kurze Pause
    LCD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet eine 4-bit Ausgabeoperation an das LCD
static void lcd_out( uint8_t data )
{
    data &= 0xF0;                       // obere 4 Bit maskieren
 
    LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
    LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
    lcd_enable();
}
 
////////////////////////////////////////////////////////////////////////////////
// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
void Init_LCD( void )
{
    // verwendete Pins auf Ausgang schalten
	PORTD &= ~( (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD6) ); 
	DDRD |= (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6);
	
	PORTC &= ~( (1<<LCD_RS) ); // Set RW = 0;
	DDRC |= (1<<LCD_RS);
	
     // warten auf die Bereitschaft des LCD
    _delay_ms( LCD_BOOTUP_MS );
	    
    // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
	lcd_out( LCD_SOFT_RESET );
    _delay_ms( LCD_SOFT_RESET_MS1 );
 
    lcd_enable();
    _delay_ms( LCD_SOFT_RESET_MS2 );
 
    lcd_enable();
    _delay_ms( LCD_SOFT_RESET_MS3 );
 
    // 4-bit Modus aktivieren 
    lcd_out( LCD_SET_FUNCTION |
             LCD_FUNCTION_4BIT );
    _delay_ms( LCD_SET_4BITMODE_MS );

    // 4-bit Modus / 2 Zeilen / 5x7
    lcd_command( LCD_SET_FUNCTION |
                 LCD_FUNCTION_4BIT |
                 LCD_FUNCTION_2LINE |
                 LCD_FUNCTION_5X7 );

	
    // Display ein / Cursor aus / Blinken aus
	lcd_command( LCD_SET_DISPLAY |
                 LCD_DISPLAY_ON |
                 LCD_CURSOR_OFF |
                 LCD_BLINKING_OFF); 

	
    // Cursor inkrement / kein Scrollen
	lcd_command( LCD_SET_ENTRY |
                 LCD_ENTRY_INCREASE |
                 LCD_ENTRY_NOSHIFT );
 
 
    lcd_clear();
//	lcd_generatechar( LCD_GC_CHAR0, Zeichen1 );
//	lcd_generatechar( LCD_GC_CHAR1, Zeichen2 );
}
  
////////////////////////////////////////////////////////////////////////////////
// Sendet ein Datenbyte an das LCD
void lcd_data( uint8_t data )
{
    PORTC |= (1<<LCD_RS);    // RS auf 1 setzen
 
    lcd_out( data );            // zuerst die oberen, 
    lcd_out( data<<4 );         // dann die unteren 4 Bit senden
 
    _delay_us( LCD_WRITEDATA_US );
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet einen Befehl an das LCD
void lcd_command( uint8_t data )
{
    PORTC &= ~(1<<LCD_RS);    // RS auf 0 setzen
 
    lcd_out( data );             // zuerst die oberen, 
    lcd_out( data<<4 );           // dann die unteren 4 Bit senden
 
    _delay_us( LCD_COMMAND_US );
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet den Befehl zur Löschung des Displays
void lcd_clear( void )
{
    lcd_command( LCD_CLEAR_DISPLAY );
    _delay_ms( LCD_CLEAR_DISPLAY_MS );
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet den Befehl: Cursor Home
void lcd_home( void )
{
    lcd_command( LCD_CURSOR_HOME );
    _delay_ms( LCD_CURSOR_HOME_MS );
}
 
////////////////////////////////////////////////////////////////////////////////
// Setzt den Cursor in Spalte x (0..15) Zeile y (1..4) 
 
void lcd_setcursor( uint8_t x, uint8_t y )
{
    uint8_t data;
 
    switch (y)
    {
        case 1:    // 1. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
            break;
 
        case 2:    // 2. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
            break;
 
        case 3:    // 3. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
            break;
 
        case 4:    // 4. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
            break;
 
        default:
            return;                                   // für den Fall einer falschen Zeile
    }
 
    lcd_command( data );
}
 
////////////////////////////////////////////////////////////////////////////////
// Schreibt einen String auf das LCD
 
void lcd_string( const char *data )
{
    while( *data != '\0' )
        lcd_data( *data++ );
}
 
////////////////////////////////////////////////////////////////////////////////
// Schreibt ein Zeichen in den Character Generator RAM
 
void lcd_generatechar( uint8_t code, const uint8_t *data )
{
    // Startposition des Zeichens einstellen
    lcd_command( LCD_SET_CGADR | (code<<3) );
 
    // Bitmuster übertragen
    for ( uint8_t i=0; i<8; i++ )
    {
        lcd_data( data[i] );
    }
}

////////////////////////////////////////////////////////////////////////////////
// Formatierte Ausgabe mit führender Null und Komma
// Zahl 	=> Unformatierter Wert
// Digits 	=> Ziffern vor dem Komma
// Komma	=> Ziffern hinterm Komma
// Digits+Komma muss die Anzahl an Ziffern ergeben, sonst falsche Ausgabe
void lcd_formatierte_zahl(int32_t zahl, uint8_t vor_komma, uint8_t nach_komma)
{
	char s[7];
	uint16_t ganz = 0;
	uint16_t komma;
	
	if (zahl < 0)
	{
		lcd_string("-");
		zahl = zahl * -1;
	}
	
	if (nach_komma == 0)					// eine Nachkommastelle
	{
		ganz = zahl;
		komma = 0;
	}
	
	if (nach_komma == 1)					// eine Nachkommastelle
	{
		ganz = zahl / 10;					// ganzzahligen Anteil berechnen
		komma = zahl - (ganz * 10);		// nachkomma-Anteil berechnen
	}
	
	if (nach_komma == 2)					// zwei Nachkommastellen
	{
		ganz = zahl / 100;					// ganzzahligen Anteil berechnen
		komma = zahl - (ganz * 100);		// nachkomma-Anteil berechnen
	}
	
	if (nach_komma == 3)					// drei Nachkommastellen
	{
		ganz = zahl / 1000;					// ganzzahligen Anteil berechnen
		komma = zahl - (ganz * 1000);		// nachkomma-Anteil berechnen
	}
	
	if (nach_komma == 4)					// vier Nachkommastellen
	{
		ganz = zahl / 10000;				// ganzzahligen Anteil berechnen
		komma = zahl - (ganz * 10000);		// nachkomma-Anteil berechnen
	}
	
	// führende Nullen ausgeben	
	if (vor_komma == 5)
	{
		if (ganz < 10000)	lcd_data(' ');
		if (ganz < 1000)	lcd_data(' ');
		if (ganz < 100)		lcd_data(' ');
		if (ganz < 10)		lcd_data(' ');
	}
	
	if (vor_komma == 4)
	{
		if (ganz < 1000)	lcd_data(' ');
		if (ganz < 100)		lcd_data(' ');
		if (ganz < 10)		lcd_data(' ');
	}
	
	if (vor_komma == 3)
	{
		if (ganz < 100)		lcd_data(' ');
		if (ganz < 10)		lcd_data(' ');
	}
	
	if (vor_komma == 2)
	{
		if (ganz < 10)		lcd_data(' ');
	}
	
	utoa(ganz, s, 10); 					// 10 fuer radix -> Dezimalsystem
	lcd_string(s);							// alle Stellen des ganzzahligen Anteils ausgeben
	
	if (nach_komma)
	{
		lcd_data('.');
		utoa (komma, s, 10); // 10 fuer radix -> Dezimalsystem
		// fehlende Nullen ausgeben
		if (nach_komma == 2)
		{
			if (komma < 10)		lcd_data('0');
		}
		if (nach_komma == 3)
		{
			if (komma < 100)	lcd_data('0');
			if (komma < 10)		lcd_data('0');
		}
		if (nach_komma == 4)
		{
			if (komma < 1000)	lcd_data('0');
			if (komma < 100)	lcd_data('0');
			if (komma < 10)		lcd_data('0');
		}
		if (nach_komma == 5)
		{
			if (komma < 10000)	lcd_data('0');
			if (komma < 1000)	lcd_data('0');
			if (komma < 100)	lcd_data('0');
			if (komma < 10)		lcd_data('0');
		}
		lcd_string(s);
	}	

}

