Code:
	// LCD
//Einstellung für vorgeladene ASCII Zeichen im Display
#define PRELOADLCDCHARS 1
#if PRELOADLCDCHARS==1
const uint8_t chrdata[64] MEM = {
// LCD_GC_CHAR0 124=|
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000000,
// LCD_GC_CHAR1 252=ü
    0b00001010,
    0b00000000,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00010011,
    0b00001101,
    0b00000000,
// LCD_GC_CHAR2 228=ä
    0b00001010,
    0b00000000,
    0b00001110,
    0b00000001,
    0b00001111,
    0b00010001,
    0b00001111,
    0b00000000,
// LCD_GC_CHAR3 246=ö
    0b00001010,
    0b00000000,
    0b00001110,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00001110,
    0b00000000,
// LCD_GC_CHAR4 220=Ü
    0b00001010,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00001110,
    0b00000000,
// LCD_GC_CHAR5 196=Ä
    0b00001010,
    0b00001110,
    0b00010001,
    0b00010001,
    0b00011111,
    0b00010001,
    0b00010001,
    0b00000000,
// LCD_GC_CHAR6 214=Ö
    0b00001010,
    0b00001110,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00001110,
    0b00000000,
// LCD_GC_CHAR7 223=ß
    0b00001100,
    0b00001010,
    0b00001110,
    0b00001001,
    0b00001001,
    0b00001010,
    0b00001000,
    0b00000000
};
#endif
const char lcd_wheelchar[] MEM = ".,oO0*0Oo,. "; // sinnvoll wäre auch noch const char wheel[] = "0123456789ABCDEF";
const uint8_t LCDLineAdr[] = {LCD_START_LINE1, LCD_START_LINE2, LCD_START_LINE3, LCD_START_LINE4};
#define LCDwheelsize (sizeof(lcd_wheelchar)-1)
static uint8_t lcd_cpos; // nächste Schreibadresse bzw. Cursorposition im Display
static uint8_t lcd_line;
/**
 * Sendet Daten an das M32LCD, für andere LCD Anschlüsse muss nur die Ausgabe per writeSPI angepasst werden
 */
void m32lcd_data( uint8_t data, uint8_t mode )
{
    if (mode!=LCD_SINGLE) {
        if (mode==LCD_DATA) PORTB |= LCD_RS;// RS setzen / data
        else PORTB &= ~LCD_RS; // RS löschen  / byte cmd
        externalPort.LCDD = data >> 4;
        writeSPI(externalPort.byte);
        PORTD |= STR;
        PORTB |= LCD_EN;
        PORTD &= ~STR;
        _delay_us(LCD_ENABLE_US);
        PORTB &= ~LCD_EN;
    } else PORTB &= ~LCD_RS; // RS löschen / nibble cmd
    externalPort.LCDD = data & 0x0f;
    writeSPI(externalPort.byte);
    PORTD |= STR;
    PORTB |= LCD_EN;
    PORTD &= ~STR;    
    _delay_us(LCD_ENABLE_US);
    PORTB &= ~LCD_EN;
    _delay_us(LCD_ENABLE_US);
    if (mode==LCD_DATA){
        _delay_us( LCD_WRITEDATA_US );
        lcd_cpos++; // Cursor increment
    }
    else _delay_ms( LCD_WRITECMD_MS );
}
/**
 * Initialize the LCD. Always call this before using the LCD! 
 */
void initLCD(void)
{
    uint8_t i;
//    _delay_ms(LCD_BOOTUP_MS , LCD_SINGLE); No need for Power ON delay as usually the
// Bootloader should have been executed before...
    PORTB &= ~LCD_EN;
    PORTB &= ~LCD_RS;
    _delay_ms(15);
    for(i=0;i<2;++i) {
        m32lcd_data(0x3 , LCD_SINGLE);
        _delay_ms(2);
    } //Reset
// 4-bit Modus aktivieren
    m32lcd_data(0x2 , LCD_SINGLE);
    _delay_ms(2);
// 4-bit Modus / 2 Zeilen / 5x7
    m32lcd_data( LCD_SET_FUNCTION | LCD_FUNCTION_4BIT | LCD_FUNCTION_2LINE | LCD_FUNCTION_5X7 , LCD_CMD);
// Display ein / Cursor aus / Blinken aus
    m32lcd_data( LCD_SET_DISPLAY | LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINKING_OFF , LCD_CMD);
// Cursor inkrement / kein Scrollen
#if LCD_WRAP_LINES==1
    m32lcd_data( LCD_SET_ENTRY | LCD_ENTRY_INCREASE | LCD_ENTRY_NOSHIFT , LCD_CMD);
#else
    m32lcd_data( LCD_SET_ENTRY | LCD_ENTRY_INCREASE | LCD_ENTRY_SHIFT , LCD_CMD);
#endif
// vordefinieren der 8 Sonderzeichen
#if PRELOADLCDCHARS==1
    uint8_t eeval;    
    m32lcd_data( LCD_SET_CGADR , LCD_CMD );
    for (i=0; i<64; i++ ) {
#if MEMORY==0        
        eeval = pgm_read_byte(&chrdata[i]);
#else
        eeval = eeprom_read_byte(&chrdata[i]);
#endif        
        m32lcd_data( eeval , LCD_DATA);
    }
#endif
// Clear
    lcd_cpos=0;
    lcd_line=0;
    m32lcd_data(LCD_CLEAR_DISPLAY, LCD_CMD);
}
#ifdef WENEEDRP6IO
/**
 * Clears the whole LCD!
 */
void clearLCD(void)
{
    lcd_cpos=0;
    lcd_line=0;
    m32lcd_data(LCD_CLEAR_DISPLAY , LCD_CMD);
}
/**
 * Write a single character to the LCD.
 */
void writeCharLCD(uint8_t ch)
{
    m32lcd_data(ch , LCD_DATA);
}
/**
 * Writes a null terminated string from flash program memory to the LCD.
 * You can use the macro writeStringLCD_P(STRING); instead, this macro
 * ensures that the String is stored in program memory only!
 * Example:
 *            writeNStringLCD_P(PSTR("RP6 Control"));
 *            // There is also a Macro that makes life easier and
 *            // you can simply write:
 *            writeStringLCD_P("RP6 Control");
 */
void writeNStringLCD_P(const char *pstring)
{
    uint8_t c;
    for (;(c = pgm_read_byte_near(pstring++));m32lcd_data(c , LCD_DATA));
}
/**
 * Writes a String from SRAM to the LCD.
 */
void writeStringLCD(char *string)
{
    while(*string)
        m32lcd_data(*string++ , LCD_DATA);
}
/**
 * Writes a string with specified length and offset from SRAM to the LCD.
 * If it is a null terminated string, output will be stopped at the
 * end. It does not need to be null terminated, but it is recommended
 * to use only null terminated strings/buffers, otherwise the function could
 * output any SRAM memory data stored after the string until it reaches a 0
 * or the specified length!
 * Example:
 *            writeStringLength("RP6 Robot Sytem",16,0);
 *            // would output: "RP6 Robot Sytem\n"
 *            writeStringLength("RP6 Robot Sytem",11,4);
 *            // would output: "Robot System"
 *             writeStringLength("RP6 Robot Sytem",40,4);
 *            // would output: "Robot System"
 *            // No matter if the specified length is 40 characters!
 */
void writeStringLengthLCD(char *string, uint8_t length, uint8_t offset)
{
    for(string = &string[offset]; *string && length; length--)
        m32lcd_data(*string++ , LCD_DATA);
}
/**
 * Write a number (with specified base) to the LCD.
 * Example:
 *            // Write a hexadecimal number to the LCD:
 *            writeInteger(0xAACC,16);
 *            // Instead of 16 you can also write "HEX" as this is defined in the
 *            // RP6RobotBaseLib.h :
 *            writeInteger(0xAACC, HEX);
 *            // Other Formats:
 *            writeInteger(1024,DEC);      // Decimal
 *            writeInteger(511,OCT);        // Ocal
 *            writeInteger(0b11010111,BIN); // Binary
 */
void writeIntegerLCD(int16_t number, uint8_t base)
{
    char buffer[17];
    itoa(number, &buffer[0], base);
    writeStringLCD(&buffer[0]);
}
/**
 * Same as writeInteger, but with defined length.
 * This means this routine will add leading zeros to the number if length is
 * larger than the actual value or cut the upper digits if length is smaller
 * than the actual value.
 * Example:
 *            // Write a hexadecimal number to the LCD:
 *            writeIntegerLength(0xAACC, 16, 8);
 *            // Instead of 16 you can also write "HEX" as this is defined in the
 *            // RP6ControlLib.h :
 *            writeIntegerLength(0xAACC, HEX, 8);
 *            // Other Formats:
 *            writeIntegerLength(1024,DEC,6);      // Decimal
 *            writeIntegerLength(511,OCT,4);        // Ocal
 *            writeIntegerLength(0b11010111,BIN,8); // Binary
 */
 
void writeIntegerLengthLCD(int16_t number, uint8_t base, uint8_t length)
{
    char buffer[17];
    itoa(number, &buffer[0], base);
    int8_t cnt = length - strlen(buffer);
    if(cnt > 0) {
        for(; cnt > 0; cnt--, writeCharLCD('0'));
        writeStringLCD(&buffer[0]);
    }
    else 
        writeStringLengthLCD(&buffer[0],length,-cnt);
}
/**
 * This function is useful for displaying text screens on the LCD.
 * It clears the whole LCD and writes the two Strings to line 1 and
 * line 2.
 */
void _showScreenLCD_P(const char *line1, const char *line2)
{
    clearLCD();
    writeNStringLCD_P(line1);
    lcd_line=1;
    m32lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
    writeNStringLCD_P(line2);
}
/**
 * Sets the cursor position on LCD.
 */
void setCursorPosLCD(uint8_t line, uint8_t pos)
{
    if (line < LCD_LINES) {
        lcd_line=line;
        lcd_cpos=pos;
        m32lcd_data(LCD_SET_DDADR + LCDLineAdr[line] + pos, LCD_CMD);
    }
}
/**
 * Clears some characters after the given position.
 */
void clearPosLCD(uint8_t line, uint8_t pos, uint8_t length)
{
    lcd_line=0;
    lcd_cpos=0;
    m32lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
    while(length--)
        m32lcd_data(' ' , LCD_DATA);
}
/*****************************************************************************/
// die uart_2 lib für LCD
/*****************************************************************************/
void writeLongLCD(int32_t number, uint8_t base) {
    char buffer[33];
    ltoa(number, buffer, base); //->stdio
    writeStringLCD(&buffer[0]);
}
void writeLongLengthLCD(int32_t number, uint8_t base, uint8_t length) {
    char buffer[33];
    ltoa(number, &buffer[0], base);
    int8_t cnt = length - strlen(buffer);
    if(cnt > 0) {
        for(; cnt > 0; cnt--, writeCharLCD('0'));
        writeStringLCD(&buffer[0]);
    } else writeStringLengthLCD(&buffer[0], length, -cnt);
}
void writeDoubleLCD(double number, uint8_t width, uint8_t prec) {
    char buffer[width + 1];
    dtostrf(number, width, prec, buffer);
    writeStringLCD(&buffer[0]);
}
void writeDoubleExpLCD(double number, uint8_t prec, uint8_t flags) {
    char buffer[prec + 8];
    dtostre(number, buffer, prec, flags);
    writeStringLCD(&buffer[0]);
}
#endif
// die neuen LCD Funktionen
void lcd_CalcCursorUP(uint8_t setcursor){ //Boundary check upward
    if ( lcd_cpos >= LCD_LINE_LENGTH ) { //linewrap prüfen und nächste Zeile setzen
        lcd_cpos=0;
        if (lcd_line >= LCD_LINES) lcd_line=0; else lcd_line++;
        setcursor=true;
    }
    if (setcursor==true) m32lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
}
void lcd_CalcCursorDOWN(void){ //Boundary check downward
    if (lcd_cpos > 0 ) lcd_cpos--;
    else {
        if (lcd_line > 0) lcd_line--;
        else lcd_line=LCD_LINES-1;
        lcd_cpos=LCD_LINE_LENGTH-1;        
    }
    m32lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
}
/*****************************************************************************/
void lcd_putxy(char c, uint8_t line, uint8_t pos) //gibt Zeichen an xy aus
{
    lcd_line=line;
    lcd_cpos=pos;
    lcd_CalcCursorUP(true);
    m32lcd_data(c , LCD_DATA);
    lcd_CalcCursorUP(false);
}
int16_t lcd_putchar(char c, __attribute__((unused)) FILE *stream)
{
//*********    
#if LCDMODE==LCD_ASCII
    static bool nl_seen;
    static bool cursor_seen;
    uint8_t i;
    
    if (cursor_seen) { // erstes Zeichen nach \v, Cursorposition also \v%c
        lcd_cpos = c % LCD_LINE_LENGTH; 
        lcd_line = (c / LCD_LINE_LENGTH) % LCD_LINES;
        lcd_CalcCursorUP(true);
        cursor_seen = false; //ok es geht weiter im String
        return 1; // darf nicht zur weiteren Auswertung gelangen.
    } else { // wenn keine Cursorposition, dann normales Zeichen
        switch (c) { // Steuerzeichen nach ISO/IEC 6429
            case '\a': // BELL Zeichen
                sound(230,25,25);
            break;
            case '\t': // nächsten Tabulator ansteuern
                lcd_cpos=lcd_cpos+LCD_TAB_SIZE-(lcd_cpos % LCD_TAB_SIZE);
                lcd_CalcCursorUP(true);
            break;
            case '\r': // wagenrücklauf, nächste Zeile löschen
                lcd_line++;
                lcd_cpos=0;
                lcd_CalcCursorUP(true);
                for(i=0;i<LCD_LINE_LENGTH;i++) m32lcd_data(' ' , LCD_DATA);
                lcd_cpos-=LCD_LINE_LENGTH;
                lcd_CalcCursorUP(true);
            break;
            case '\v': //set cursor line, nächstes "char" ist der kumulierte cursorwert
                cursor_seen = true;
            break;
            case '\x7f': // ist zwar ein Zeichen im Displayzeichensatz, aber laut ASCII das DEL char!
                lcd_CalcCursorDOWN();
                m32lcd_data(' ' , LCD_DATA);
            case '\b': // 1 Zeichen zurück gehen, nicht löschen entspricht <- [cursor].
                lcd_CalcCursorDOWN();
            break;
            case '\xff': // steht für signed -1, EOF, ALTSPACE, hier als "jumpover" bzw. SPACE ohne löschen / [cursor] ->
                lcd_cpos++;
                lcd_CalcCursorUP(true);
            break;
            case '\n': // indirekter löschbefehl
                nl_seen = true;
            break;
            case '\f': // direkter löschbefehl
                lcd_cpos=0;
                lcd_line=0;
                m32lcd_data(LCD_CLEAR_DISPLAY , LCD_CMD);
            break;
            default:
                if (nl_seen && c != '\n') { // First character after newline, clear display and home cursor.
                    lcd_cpos=0;
                    lcd_line=0;
                    m32lcd_data(LCD_CLEAR_DISPLAY , LCD_CMD);
                    nl_seen = false;
                }
#if PRELOADLCDCHARS==1                
                switch (c) { // Umsetzungstabelle für Sonderzeichen laut ISO/IEC 8859-1/15
                    case 124: // LCD_GC_CHAR0 124=|
                        c=0x80+LCD_GC_CHAR0;
                    break;
                    case 252: // LCD_GC_CHAR1 252=ü
                        c=0x80+LCD_GC_CHAR1;
                    break;
                    case 228: // LCD_GC_CHAR2 228=ä
                        c=0x80+LCD_GC_CHAR2;
                    break;
                    case 246: // LCD_GC_CHAR3 246=ö
                        c=0x80+LCD_GC_CHAR3;
                    break;
                    case 220: // LCD_GC_CHAR4 220=Ü
                        c=0x80+LCD_GC_CHAR4;
                    break;
                    case 196: // LCD_GC_CHAR5 196=Ä
                        c=0x80+LCD_GC_CHAR5;
                    break;
                    case 214: // LCD_GC_CHAR6 214=Ö
                        c=0x80+LCD_GC_CHAR6;
                    break;
                    case 223: // LCD_GC_CHAR7 223=ß
                        c=0x80+LCD_GC_CHAR7;
                    break;
                }
#endif
                if ((c >= ' ' && c <= '\x87')) { // ist das ein verwertbares Zeichen incl. CGCHAR?
                    m32lcd_data(c & 0x7f , LCD_DATA); // ggf. das "Steuerzeichenvehikel" für CGCHAR (0x80+CGCHAR) ausmaskieren
                    lcd_CalcCursorUP(false); //Linewrap berechen... 
                } else printf ("%c %x. ",c,c);
            break;
        }
    }
//*********    
#elif LCDMODE==LCD_BINARY
    m32lcd_data(c , LCD_DATA); //nur ausgeben und cursor boundary berechnen/setzen
    lcd_CalcCursorUP(false); //cursor boundary berechnen/setzen
#endif
    return 0;
}
void lcd_wheel(uint8_t line, uint8_t pos) //sowas wie Sanduhr/Kringel oder rotierender Cursor, gut zum debuggen
{
    static uint8_t i=0;
    m32lcd_data(LCD_SET_DDADR + LCDLineAdr[line] + pos, LCD_CMD);
#if MEMORY==0
    m32lcd_data(pgm_read_byte(&lcd_wheelchar[i++]), LCD_DATA);
#else
    m32lcd_data(eeprom_read_byte(&lcd_wheelchar[i++]), LCD_DATA);
#endif
    lcd_cpos-=1; // Cursor korrigieren, war ja kein reguläres char im Display
    if (i==LCDwheelsize) i=0;
    m32lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
}
uint8_t lcd_getCursorPos(void) // gibt aktuelle cursorposition als kumulierten Wert zurück
{
    return ((lcd_line*LCD_LINE_LENGTH) + lcd_cpos);
}
void lcd_setCursorPos(uint8_t data) // setzt aktuelle cursorposition als kumulierten Wert
{
    lcd_cpos = data % LCD_LINE_LENGTH;
    lcd_line = (data / LCD_LINE_LENGTH) % LCD_LINES;
    lcd_CalcCursorUP(true);
}
uint8_t lcd_xy(uint8_t line, uint8_t pos) // gibt x/y cursorposition als kumulierten Wert zurück
{
    return ((line*LCD_LINE_LENGTH) + pos);
}
/*
* Erzeugt selbst definierte Zeichen im CGRAM, Beisp.:
*  const uint8_t chrdata0[8] EEPMEM = {
*     0b00000000,
*     0b00000000,
*     0b00001010,     //   X X
*     0b00011111,     //  XXXXX
*     0b00001110,     //   XXX
*     0b00000100,     //    X
*     0b00000000,
*     0b00000000};
*
* lcd_generatechar(LCD_GC_CHAR0, chrdata0); //erzeugt 5x7 oder 5x10 char (+cursorline)
* Die Funktion erkennt selbst wie viel Byte einzulesen sind 
* für 5x10 Zeichen muss das bitarray 11 lines haben und man kann nur jedes 2.te GCCHAR nutzen.
* Also LCD_GC_CHAR0, LCD_GC_CHAR2, LCD_GC_CHAR4 und LCD_GC_CHAR6
*/
void lcd_generatechar( uint8_t code, const uint8_t *data)
{
    uint8_t i;
    m32lcd_data( LCD_SET_CGADR | (code<<3) , LCD_CMD ); // Startposition des Zeichens einstellen
    for (i=0; i<sizeof(data); i++ ) 
        m32lcd_data( data[i] , LCD_DATA); // Zeichendaten byteweise hoch laden
    lcd_cpos-=i; // Cursor korrigieren, war ja kein char im Display    
    m32lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD); // Zurück setzen auf alte cursor Position
}
/*****************************************************************************/
// Keypad:
 Das gleiche macht man sinngemäß mit der RP6ControlLib.h und folgendem Code.
	Code:
	// LCD:
// zur Compile Zeit einstellbar:
#define LCD_ASCII 0 // wie ASCII Terminal, Steuerungszeichen werden verarbeitet
#define LCD_BINARY 1 // RAW Binärübertragung ohne Beeinflussung des Datenstroms
// Modus für putchar, wirkt sich auf die Codesize aus.
#define LCDMODE LCD_ASCII // Oder LCD_BINARY
// das Display selbt hat Eigenschaften:
#define LCD_LINES                0x02     //Anzahl Zeilen
#define LCD_DISP_LENGTH            0x10    //sichtbare Anzahl Zeichen pro Zeile IN HEX !!! 16Z=0x10,20Z=0x14,24Z=0x18
#define LCD_WRAP_LINES            1     // 0 buffer wrap?, 1 (default) wrap auf sichtbaren Zeilengrenzen*
#define LCD_TAB_SIZE            0x04     // Tabulator Position */
//*Die Einstellungen für Bufferwrap konnten noch nicht getestet werden
//Timings
#define LCD_BOOTUP_MS           0x28 //40ms
#define LCD_ENABLE_US           0x01 //1us
#define LCD_WRITEDATA_US        0x32 //50us
#define LCD_WRITECMD_MS            0x03 //3ms
//LCD Befehle
// Clear Display -------------- 0b00000001
#define LCD_CLEAR_DISPLAY       0x01
// Cursor Home ---------------- 0b0000001x
#define LCD_CURSOR_HOME         0x02
// Set Entry Mode ------------- 0b000001xx
#define LCD_SET_ENTRY           0x04
#define LCD_ENTRY_DECREASE      0x00
#define LCD_ENTRY_INCREASE      0x02
#define LCD_ENTRY_NOSHIFT       0x00
#define LCD_ENTRY_SHIFT         0x01
// Set Display ---------------- 0b00001xxx
#define LCD_SET_DISPLAY         0x08
#define LCD_DISPLAY_OFF         0x00
#define LCD_DISPLAY_ON          0x04
#define LCD_CURSOR_OFF          0x00
#define LCD_CURSOR_ON           0x02
#define LCD_BLINKING_OFF        0x00
#define LCD_BLINKING_ON         0x01
// Set Shift ------------------ 0b0001xxxx
#define LCD_SET_SHIFT           0x10
#define LCD_CURSOR_MOVE         0x00
#define LCD_DISPLAY_SHIFT       0x08
#define LCD_SHIFT_LEFT          0x00
#define LCD_SHIFT_RIGHT         0x04
// Set Function --------------- 0b001xxxxx
#define LCD_SOFT_RESET          0x30
#define LCD_SET_FUNCTION        0x20
#define LCD_FUNCTION_4BIT       0x00
#define LCD_FUNCTION_8BIT       0x10
#define LCD_FUNCTION_1LINE      0x00
#define LCD_FUNCTION_2LINE      0x08
#define LCD_FUNCTION_5X7        0x00
#define LCD_FUNCTION_5X10       0x04
// Set CG RAM Address --------- 0b01xxxxxx  (Character Generator RAM)
#define LCD_SET_CGADR           0x40
#define LCD_GC_CHAR0            0
#define LCD_GC_CHAR1            1
#define LCD_GC_CHAR2            2
#define LCD_GC_CHAR3            3
#define LCD_GC_CHAR4            4
#define LCD_GC_CHAR5            5
#define LCD_GC_CHAR6            6
#define LCD_GC_CHAR7            7
// Set DD RAM Address --------- 0b1xxxxxxx  (Display Data RAM)
#define LCD_SET_DDADR           0x80
// Modus für LCD-schreibfunktion (RP6 Spezifisch)
#define LCD_DATA                0 // 8 bit Daten mit RS1
#define LCD_CMD                    1 // 8 bit Befehl mit RS0
#define LCD_SINGLE                2 // 4 bit init
#if LCD_WRAP_LINES==1
#define LCD_LINE_LENGTH LCD_DISP_LENGTH // wrap auf Display Sichtgrenzen
#else
#define LCD_LINE_LENGTH 0x40            // wrap auf Buffer Grenzen, Wert=Buffergröße
#endif
//Dispay Daten Adressen für 2x16, 4x16
#define LCD_START_LINE1         0x00
#define LCD_START_LINE2         0x40
#if LCD_DISP_LENGTH==16            // 16er Displays haben wohl andere Adressen für Line 3&4 als 20er
#define LCD_START_LINE3         0x10
#define LCD_START_LINE4         0x50
#else                            // 20 zeichen/line
#define LCD_START_LINE3         0x14
#define LCD_START_LINE4         0x54
#endif
// neue stdio Ausgabefunktion, alles andere würd über printf und Steuerzeichen gemacht.
int16_t lcd_putchar(char c, __attribute__((unused)) FILE *stream); // Ausgabe mit Steuerzeichen
// neue LCD Funktion
void lcd_wheel(uint8_t line, uint8_t ); // gibt eine Folge von chars als "Wheel" auf x/y aus
uint8_t lcd_getCursorPos(void); // gibt aktuelle cursorposition als kumulierten Wert zurück
void lcd_setCursorPos(uint8_t data); // setzt aktuelle cursorposition als kumulierten Wert
uint8_t lcd_xy(uint8_t line, uint8_t pos); // gibt x/y cursorposition als kumulierten Wert zurück
void lcd_generatechar( uint8_t code, const uint8_t *data); //schreibt Zeichen in CGRAM
// internal use
void m32lcd_data( uint8_t data, uint8_t mode ); // zentrale Schreibfunktion, Mode LCD_DATA/LCD_CMD/LCD_SINGLE
void lcd_CalcCursorUP(uint8_t setcursor); //Boundary check upward
void lcd_CalcCursorDOWN(void); //Boundary check downward
/*
Benutzung von lcd_generatechar()
    const uint8_t chrdata0[8] = {
        0b00000000,
        0b00000000,
        0b00001010,     //   X X
        0b00011111,     //  XXXXX
        0b00001110,     //   XXX
        0b00000100,     //    X
        0b00000000,
        0b00000000
    };
    lcd_generatechar(LCD_GC_CHAR0, chrdata0);
    m32lcd_data(LCD_GC_CHAR0,LCD_DATA); // als direkte Ausgabe im Display-Zeichensatz 0-7
//oder
    fprintf(M32lcd,"LCD char: \x80"); // die 8 CGCHARS liegen also ab 0x80 bis 0x87 im ASCII Zeichensatz
*/
// alte und geänderte Funktionen
void initLCD(void);
#ifdef WENEEDRP6IO
void clearLCD(void);
void clearPosLCD(uint8_t line, uint8_t pos, uint8_t length);
void writeCharLCD(uint8_t ch);
#define writeStringLCD_P(__pstr) writeNStringLCD_P((PSTR(__pstr)))
void writeStringLengthLCD(char *string, uint8_t length, uint8_t offset);
void writeStringLCD(char *string);
void writeNStringLCD_P(const char *pstring);
void _showScreenLCD_P(const char *line1, const char *line2);
#define showScreenLCD(__line1,__line2); ({_showScreenLCD_P((PSTR(__line1)),(PSTR(__line2)));})
void writeIntegerLCD(int16_t number, uint8_t base);
void writeIntegerLengthLCD(int16_t number, uint8_t base, uint8_t length);
void setCursorPosLCD(uint8_t line, uint8_t pos);
/*****************************************************************************/
// die uart_2 lib
/*****************************************************************************/
#define PRECISION 6
#define DTOSTR_ALWAYS_SIGN 0x01
#define DTOSTR_PLUS_SIGN 0x02
#define DTOSTR_UPPERCASE 0x04
void writeLongLCD(int32_t number, uint8_t base);
void writeLongLengthLCD(int32_t number, uint8_t base, uint8_t length);
void writeDoubleLCD(double number, uint8_t width, uint8_t prec);
void writeDoubleExpLCD(double number, uint8_t prec, uint8_t flags);
/*****************************************************************************/
#endif
#ifndef HEX
    #define HEX 16
#endif
#ifndef DEC 
    #define DEC 10
#endif
#ifndef OCT
    #define OCT 8
#endif
#ifndef BIN
    #define BIN 2
#endif
/*****************************************************************************/
// Keys:
 NACHTRAG:
Lesezeichen