- 3D-Druck Einstieg und Tipps         
Ergebnis 11 bis 20 von 29

Thema: Senden und empfangen auf dem UART mit ISR kompatibel zur bisherigen RP6lib

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #19
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    So.. wie versprochen.. ein etwas geänderter LCD Treiber für die M32, zur Verwendung mit stdio geeignet.

    Zunächst: Was ändert sich? Für Programme die auf der M32 alte Write-Funktionen nutzen - nichts! Es gibt die Schreibfunktionen über Umleitungen wie beim UART Treiber.
    Was hat sich geändert? Ich habe die eigentliche Ausgabefunktion zusammen gefasst. Sie nennt sich m32lcd_data() und kann nibbles, Commands und Daten ans Display schicken.
    Will man sich die Lib auf ein anderes Display umschreiben, braucht man nur diese Funktion an die Hardware anzupassen. Hier bin ich insbesondere von den alten Angaben zu CPU-Cycles auf echte Zeiten gegangen wie sie im Datenblatt stehen. Das macht es einfacher bei anderen Taktungen.

    Es sind neue Funktionen hinzu gekommen, unter anderem die Hauptfunktion lcd_putchar(), welche man braucht um sie im Programm mit stdio zu nutzen.
    Code:
    Eingebunden wird sie mit:
    
        FILE *M32lcd;
        static FILE lcdout = FDEV_SETUP_STREAM (lcd_putchar, NULL, _FDEV_SETUP_WRITE);
        M32lcd=&lcdout;
    
    Angesprochen z.B. so:
    
    fprintf ( M32lcd , "L\tCD Test:\v%c=%d foo\a\tbar \x80\n" , lcd_xy(1,4) , i++);
    Die Zeile ist für ein 2x16 Display zu lang aber es wird auf das LCD ausgegeben: mit printf support "L CD" durch \t Tabulatoren (derzeit 4) getrennt, dann wird mit
    \v%c der cursor umgesetzt und auf die position nach "=" Wert i geschrieben, dann "foo" ausgegeben, einmal gebimmelt, mit tabulator bar
    drangehängt und am Schluß noch das erste selbstdefinierte Zeichen aus dem GCRAM (0x80) ausgegeben - abgeschlossen von einem Linefeed,
    was dazu führt das bei der nächsten ausgabe erst das Display gelöscht wird. Macht so alles kein Zusammenhang, zeigt aber ein wenig,
    was man damit anstellen kann. Es gibt dann noch \r für nächste Zeile löschen usw. Und alles in einer Ausgabezeile...

    Das funktioniert alles nur, weil intern u.a. neuerdings ein Cursor mitgeführt wird (wo es zuletzt ein kleines, aber gelöstes Problem mit gab).
    Den kann man auch auslesen (lcd_getCursorPos) und setzen (lcd_setCursorPos), ferner wird mit \v ein kumilierter Cursor verwendet,
    welcher mit lcd_xy(line,pos) berechnet wird. Ansich ist das einfach nur die Position in einem Display welches nicht in lines unterteilt wäre sondern
    alles an einem Stück im Buffer steht. Pos 0 ist erstes Zeichen, Pos 0f das 15te, Pos10 das 16te bzw. 1 in der 2ten Line also line 1.. weil 1 line=0,
    Pos 1f daher auch 16 Zeichen in 2 Line... bzw. (1,15) ... Eigenlich müssten auch 4Zeilige Displays laufen wenn sie in der .h eingestellt sind.
    Es ist ein Line Wrapping mit Übertrag eingebaut so das man nur auf dem sichtbaren Display Ram schreibt und nicht in den Buffer. Im H-File ist das Display auch auf andere Formate (ungetestet) über Defines zu konfigurieren. Es gibt zudem eine Funktion zum einlesen von selbst definierten Grafik chars (8 Zeichen möglich)
    Und zu guter Letzt gibts noch eine Wheel Funktion die ein laufenden Cursor, Sanduhr oder Debug Zähler immitiert. (wirds so ähnlich in der UART Lib auch noch geben da es sich beim debuggen sehr bewährt hat) Ich bin dabei den Code dieser Lib noch zu testen...
    Zudem enthält die Lib wieder die 4 LIB2 Funktionen von Dirk. Für diese muss übrigends das Modul libm eingebunden sein wie ich jetzt gelesen habe.
    In der .h datei gibts noch ein Flag das man ähnlich dem ASCII/BINARY Mode aus dem UART Treiber nutzen bzw. zur compile Zeit, nicht Laufzeit... einstellen kann #define LCDMODE LCD_ASCII // Oder LCD_BINARY
    Im Binary Mode werden die Steuerzeichen nicht verarbeitet, da funktioniert nur das Linewrapping, im ASCII Mode werden die Steuerzeichen: \a \t \r \v%c DEL \b \f und Zeichen 0xFF verarbeitet. Die Funktionen stehen im Code noch mal erläutert. Hinter einem \v MUSS immer sofort danach ein Wert als char %c mit kumulierter Cursorposition folgen, dieser lässt sich mit lcd_xy wie gesagt auch berechnen.

    So.. wie nutzt man das?
    Man sucht sich in der vorher gesicherten RP6ControlLib.c den Abschnitt von // LCD bis // Keypad:
    und wirft alles dazwischen raus. Dann fügt man den Code unten genau dort wieder ein.
    Das ganze ebenso mit der .h Datei unten.

    Was hat man am Ende davon? Naja einen ziemlich flexibel nutzbaren LCD Treiber mit verbessertem Timing für die M32, der Möglichkeit bietet, das Ganze mit stdio einzubinden.

    Was kann der Treiber nicht? Nun er kann nicht mit dem Buffer Mode bzw. moving cursor arbeiten, den die Displays angeblich können. Das bekam ich bei meinen 2 Displays (Nachbauten) nicht zum laufen. Ebenfalls konnte ich den 5x10 Mode und andere Zeilen/Reihengrößen nicht testen.

    Ich überlege, ob ich nicht ein komplettes Lib Paket als ZIP mit allen Änderungen raus geben soll. Ich möchte allerdings die Sachen, die ich da nun geschrieben habe auch erst etwas genauer testen. Die Lib verbraucht übrigends nicht viel mehr Speicher als die alten Funktionen wenn man sie in den Binary Mode schaltet. Im ASCI Mode sinds ein paar Byte mehr aber dafür kann die Lib aber auch wieder vieles was bisher nicht ging oder umständlich und damit ebenfals codefressend umzusetzen war.

    Der Treiber kann auch bei geänderter Ausgabefunktion für andere LCDs verwendet werden, allerdings sollte man bei gleichzeitiger Nutzung von 2 LCDs darauf achten, das man nur die Ausgabefunktion selktierbar macht und nich den ganzen Treiber 2 mal anlegt. Ich habe es noch nicht ausprobiert aber das könnte über den bisher ungenutzten *Stream Parameter der lcd_putchar() gehen. Dann spart man wieder ein Haufen code da wieder ein Sack voll spezial-Write-Funktionen entfallen können. Wer übrigends nur mit stdio arbeiten will.. es gibt da immer noch das define WENEEDRP6IO ... auch in der LCD lib.

    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:
    Hab mal die aktuelle Version von mir eingestellt. Die Geschichte mit dem eeprom ist jetzt hier verbaut und läuft unter dem Aspekt "Deutsche Umlaute auf dem Display" mit automatischem Vorladen in der Init. An den Funktionen selbst hat sich nicht mehr viel geändert, ein paar Bugs sind gefixt. Der Treiber ist wie der UART Treiber über #defines auch wieder konfigurierbar und z.B. die Umlaute/Sonderzeichen oder Steuerzeichen abschaltbar.
    In die RP6CONTROLLIB.H muss auch noch Folgendes eingefügt werden damit es mit dem Speichermanagement klappt. Hinweise zum eeprom auch im entsprechenden Thread oder einfach #define MEMORY suchen und ggf. 0 setzen. Dann landet alles im PGMFLASH.

    Code:
    /*****************************************************************************/
    // Speicherconfig:
    
    #define MEMORY 0 /*0=PROGMEM,1=EEPMEM,2=EEMEM*/
    
    /*****************************************************************************/
    #if MEMORY==0
    #define MEM PROGMEM
    #elif MEMORY==1
    // wenn kein eep import, WEENEEDEEPIMPORT auskommentieren 
    #define WEENEEDEEPIMPORT 1
    #define EEPMEM __attribute__((section(".realeep")))
    #define MEM EEPMEM
    #elif MEMORY==2
    // wenn kein eep import, WEENEEDEEPIMPORT auskommentieren 
    #define WEENEEDEEPIMPORT 1
    #define MEM EEMEM
    #endif
    Den Code für die eep-Ladefunktion findet ihr in dem 1K EEPROM Thread. Bitte auch da den Nachtrag beachten.
    Ich setz mich dann mal an das stdio per TWI. Das kann ein paar Tage dauern. Ich hatte erst vor das über interpretierte Datenströme zu bauen aber da ihr durch Hardware, Remotrol und TWI master/slave Gefummel an die i2c-Registerverwaltung gewöhnt seid, werde ich es wohl erst mal mit virtuellen Registern für die Endgeräte versuchen obwohl die Datenstromvariante schneller, sicherer und leichter umzusetzen wäre.
    Ob Daten an den Motortreiber oder an ein UART durchgereicht werden ist ja vom Ablauf ansich egal... und erstes geht ja schon halbwechs mit der alten lib und den Master/Slave Programmen.

    Für den UART Treiber gibts z.Z. 3 Todos:
    Code:
     * TODO Lesebuffer 16bittig machen um errorcode aus UCSRA und overruns mitzuspeichern? Compatibilität zur fleury-lib?
     *  // -braucht doppelt so viel Ram für Buffer (akt. 2x32 gegen 2x64 byte)
     *  // +Hardwarefehler leichter erkennbar
     * TODO Wheelfunktion als HEX oder Dez Ausgabe
     * TODO hexfilegenerator für export_epp
     * ----
    Ich weis aber noch nicht was ich davon umsetze, mir reicht der Treiber so wie er ist und das Feedback ist mager.

    Gruß
    Geändert von RolfD (22.05.2014 um 01:45 Uhr)
    Sind Sie auch ambivalent?

Ähnliche Themen

  1. IR Senden und Empfangen mit ATtiny
    Von bnitram im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 03.03.2012, 12:32
  2. Problem mit dem senden von Zeichen per UART
    Von KingTobi im Forum C - Programmierung (GCC u.a.)
    Antworten: 14
    Letzter Beitrag: 30.10.2008, 20:29
  3. Atmega32/STK500 -UART senden/empfangen klappt nicht
    Von Leuchtturm im Forum C - Programmierung (GCC u.a.)
    Antworten: 12
    Letzter Beitrag: 16.01.2007, 14:02
  4. Uart senden empfangen Interrups
    Von ronald im Forum AVR Hardwarethemen
    Antworten: 15
    Letzter Beitrag: 06.03.2006, 20:24
  5. UART ermöglicht Senden, aber kann nicht Empfangen
    Von batti112 im Forum C - Programmierung (GCC u.a.)
    Antworten: 3
    Letzter Beitrag: 18.09.2004, 15:05

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress