-
        

Ergebnis 1 bis 5 von 5

Thema: HD44780 kompatibles LCD im 4-bit-mode, Busy Flag abfragen

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    04.02.2005
    Beiträge
    76

    HD44780 kompatibles LCD im 4-bit-mode, Busy Flag abfragen

    Anzeige

    Hi Leute,
    derzeit hänge ich mal wieder an einem nervigen kleinen Problemchen... Ich versuche mir ne Lib für mein LCD-Board (LCD 204B LED) aufzubauen, vermutlich für den Kontroller KS0073 (Das LCD war Teil eines Lern-Experimentier-Boards und ich habe keine gute Dokumentation, bei der ich mir 100% sicher bin, dass sie passt). Eigentlich funktioniert auch alles gut, bis auf das Auslesen des Speichers. Dies brauche ich eigentlich nur um das Busy Flag auszulesen. Wenn ich auf die BF Abfrage verzichte und stattdessen eine kleine Wartezeit einbauen funktioniert auch alles einwandfrei. Aber ich möchte umbedingt den Fehler finden, alles andere befriedigt mich nicht.

    Jaaa, betrieben wird das LCD im 4-Bit Modus, die unteren Datenleitungen (DB0-DB3) habe ich Offen gelassen, da das LCD wohl interne Pull-Up's verwendet. Ansonsten ist alles direkt mit möglichst kurzen Leitungen auf meinem Experimentierboard mit einem ATmega 8 angeschlossen.

    Also das Problem vermute ich in dieser Funktion
    Code:
    void lcd_busy(void)
    {    uint8_t rep;
        
        P_DD_DDR &= (~(0x0F << DD));        //Data-Port as Input
        SET_DD(0x00);                        //No internal Pull-Up's!
        
        RS_0;                                //Instruction Register
        RW_1;                                //Read-Mode
        _delay_us( t_W_RS_RW );
        
        do
        {    
            #ifdef _4_bit_mode_
                    
                    EN_1;
                    _delay_us( t_H_EN );                //Wait for LCD: 5us
                            
                    rep = ( (P_DD_IN >> DD) << 4 );        //Read high nibble
                    EN_0;
                    _delay_us( t_L_EN );                //Wait for LCD: 5us
                            
                    EN_1;
                    _delay_us( t_H_EN );
                    
                    rep |= ( (P_DD_IN >> DD) & 0x0F);    //Read low nibble
                    EN_0;
                    _delay_us( t_L_EN );
                                    
            #else
                    EN_1;
                    _delay_us( t_H_EN);
                    
                    rep = P_DD_IN;
                    EN_0;
                    _delay_us( t_L_EN );
                    
            #endif
                    
        }while( 0x80 & rep );                    //Check Busy Flag
        
        RW_0;
    }
    Die Konstanten habe ich hier nochmal einzeln
    Code:
    #define F_CPU 8000000L
    #include <avr/io.h>
    #include <util/delay.h>
    #include "uart.h"
    
    /////////////////////////////////////////////////////////////////Mode////////////////////////////////////////////
    #define _4_bit_mode_
    
    /////////////////////////////////////////////////////////////////Port Constants//////////////////////////////////
    #define RS                 7
    #define P_RS            PORTD
    #define P_RS_DDR        DDRD
    
    #define RW                0
    #define P_RW            PORTB
    #define P_RW_DDR        DDRB
    
    #define EN                 6
    #define P_EN            PORTD
    #define P_EN_DDR        DDRD
    
    #define DD                 2
    #define P_DD            PORTD
    #define P_DD_IN            PIND
    #define P_DD_DDR        DDRD
    
    /////////////////////////////////////////////////////////////////Time delays/////////////////////////////////////////////
    
    ///us
    #define t_H_EN 5
    #define t_L_EN 5
    #define t_W_RS_RW 1
    ///ms
    #define t_Init_1 100
    #define t_Init_2 5
            
    /////////////////////////////////////////////////////////////////Commands for Bus/////////////////////////////////////////
    #define RS_1        P_RS |=  _BV(RS)
    #define RS_0        P_RS &= ~_BV(RS)
    
    #define RW_1        P_RW |=  _BV(RW)
    #define RW_0        P_RW &= ~_BV(RW)
    
    #define EN_1        P_EN |=  _BV(EN)
    #define EN_0        P_EN &= ~_BV(EN)
    
    /////////////////////////////////////////////////////////////////Commands and Addresses///////////////////////////////////
    #define CLEAR_SCREEN    0x01
    #define RETURN_HOME     0x02
    #define ENTRY_MODE        0x04
        #define ID            0x02
        #define S            0x01
    #define DISPLAY_CON        0x08
        #define D            0x04
        #define C            0x02
        #define B            0x01
    #define SHIFTING        0x10
        #define SC            0x08
        #define RL            0x04
    #define FUNCTION_SET    0x20
        #define DL            0x10
        #define N            0x08
        #define F            0x04
    #define CG_ADD_SET        0x40
    #define DD_ADD_SET         0x80
        #define Line_1         0x00
        #define Line_2         0x40
        #define Line_3         0x14
        #define Line_4         0x54
    
    #ifdef _4_bit_mode_
        #define SET_DD(x)        P_DD &= ~(0x0F << DD);\
                                P_DD |= ((x) << DD)                        
    #else
        #define SET_DD(x)        P_DD = (x)
    #endif
    Und Sicherheitshalber hier nochmal die ganze Lib, an der ich jetzt arbeite
    Code:
    /////////////////////////////////////////////////////////////////Display Functions////////////////////////////////////////
    void delay_ms(uint16_t ms)
    {
        for(uint16_t t = 0; t <= ms; t++)    _delay_ms(1);
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void Set_P_DD( uint8_t c)
    {    
        EN_1;
            
        #ifdef _4_bit_mode_
                SET_DD( c >> 4 );        //Put high Nibble on Pin's
                _delay_us( t_H_EN );
            
                EN_0;                    //LCD reads
                _delay_us(t_L_EN);
            
                EN_1;
                SET_DD( 0x0F & c );        //Put low nibble on Pin's
        #else
                P_DD = c;
        #endif
        
        _delay_us( t_H_EN );
        
        EN_0;
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_busy(void)
    {    uint8_t rep;
        
        P_DD_DDR &= (~(0x0F << DD));        //Data-Port as Input
        SET_DD(0x00);                        //No internal Pull-Up's!
        
        RS_0;                                //Instruction Register
        RW_1;                                //Read-Mode
        _delay_us( t_W_RS_RW );
        
        do
        {    
            #ifdef _4_bit_mode_
                    
                    EN_1;
                    _delay_us( t_H_EN );                //Wait for LCD: 5us
                            
                    rep = ( (P_DD_IN >> DD) << 4 );        //Read high nibble
                    EN_0;
                    _delay_us( t_L_EN );                //Wait for LCD: 5us
                            
                    EN_1;
                    _delay_us( t_H_EN );
                    
                    rep |= ( (P_DD_IN >> DD) & 0x0F);    //Read low nibble
                    EN_0;
                    _delay_us( t_L_EN );
                                    
            #else
                    EN_1;
                    _delay_us( t_H_EN);
                    
                    rep = P_DD_IN;
                    EN_0;
                    _delay_us( t_L_EN );
                    
            #endif
                    
        }while( 0x80 & rep );                    //Check Busy Flag
        
        RW_0;
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_cmd( uint8_t cmd )
    {    
        delay_ms(1);                            //eigentlich lcd_busy();
        
        RS_0;
        RW_0;
        _delay_us(t_W_RS_RW);
        
        Set_P_DD( cmd );
            
        RS_1;
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_put( uint8_t dd )
    {        
        delay_ms(1);                            //eigentlich lcd_busy();
    
        Set_P_DD( dd );    
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_init( void )
    {    uint8_t i;
        
        P_RS_DDR |= (1 << RS);                    //as Output
        P_RW_DDR |= (1 << RW);
        P_EN_DDR |= (1 << EN);
        
        #ifdef _4_bit_mode_
                    P_DD_DDR |= (0x0F << DD);    //as Output
        #else
                    P_DD_DDR = 0xFF;
        #endif
            
        RS_0;
        RW_0;
        
        delay_ms(t_Init_1);
        
        #ifdef _4_bit_mode_
                    SET_DD( (FUNCTION_SET + DL) >> 4 );
        #else    
                    SET_DD( FUNCTION_SET + DL );
        #endif
        
        for( i=0; i<=2; i++)                    //3x Function setting
        {    
            EN_1;
            _delay_us( t_H_EN );
            EN_0;
            _delay_us( t_L_EN );
            delay_ms(t_Init_2);
        }
            
        lcd_cmd( FUNCTION_SET + N );            //2/4 line display
        lcd_cmd( DISPLAY_CON + D + C + B );        //Display:ON, Cursor:ON, Blink: ON
        lcd_cmd( ENTRY_MODE + ID );                //Increment Cursor
        lcd_cmd( CLEAR_SCREEN );
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_write( const char *dd )
    {
        while( *dd != '\0' )    lcd_put( *dd++ );
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_pos( uint8_t x, uint8_t y )
    {
        uint8_t add;
        
        switch (y)
        {    case 1:        add = DD_ADD_SET + Line_1 + x;
                        break;
            case 2:        add = DD_ADD_SET + Line_2 + x;
                        break;
            case 3:        add = DD_ADD_SET + Line_3 + x;
                        break;
            case 4:        add = DD_ADD_SET + Line_4 + x;
                        break;
            default:    return;
        }
        
        lcd_cmd( add );
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_put_bin( uint8_t c )
    {
        for(uint8_t j=0x80; j>= 0x01; j>>=1 )
        {    
            if( j == 0x08 )        lcd_put( 0x7C );
            if( c & j )            lcd_put( 0xFF );
            else                lcd_put( 0x20 );
        }
    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void lcd_CG ( uint8_t add, uint8_t *c)
    {
        add |= CG_ADD_SET;
        
        lcd_cmd( add );
        
        for (uint8_t i = 0; i<=7; i++)        lcd_cmd( c[i] );
        
    }
    So ich bin für jeden Tipp und jede Anregung sehr dankbar. Außerdem würde mich es mal interessieren wie Ihr die Lesbarkeit des Codes findet.

    Mit freundlichen Grüßen Crowdy
    mfg crowdy

  2. #2
    Benutzer Stammmitglied
    Registriert seit
    04.02.2005
    Beiträge
    76
    Hey,

    hat ne ganze Weile gedauert, aber jetzt ist mir der Fehler aufgefallen. Eigentlich ne ganz einfache Sache und zwar habe ich vergessen das DDR für den Port nach dem Lesemodus wieder auf Output zu stellen. Also die busys Funktion sieht nun so aus:
    Code:
    void lcd_busy(void)
    {    uint8_t rep;
        
        #ifdef _4_bit_mode_
            P_DD_DDR &= (~(0x0F << DD));        //Data-Port as Input
        #else
            P_DD_DDR = 0x00;                    
        #endif        
            
        SET_DD(0x0F);                            //internal Pull-Up's!
        
        RS_0;                                    //Instruction Register
        RW_1;                                    //Read-Mode
        
        _delay_us( t_W_RS_RW );
        
        do
        {    
            #ifdef _4_bit_mode_
                    
                    EN_1;
                    _delay_us( t_H_EN );                //Wait for LCD: 5us
                            
                    rep = ( (P_DD_IN >> DD) << 4 );        //Read high nibble
                    EN_0;
                    _delay_us( t_L_EN );                //Wait for LCD: 5us
                            
                    EN_1;
                    _delay_us( t_H_EN );
                    
                    rep |= ( (P_DD_IN >> DD) & 0x0F);    //Read low nibble
                    EN_0;
                    _delay_us( t_L_EN );
                                    
            #else
                    EN_1;
                    _delay_us( t_H_EN);
                    
                    rep = P_DD_IN;
                    EN_0;
                    _delay_us( t_L_EN );
                    
            #endif
                    
        }while( 0x80 & rep );                    //Check Busy Flag
        
        #ifdef _4_bit_mode_
            P_DD_DDR |= (0x0F << DD);            //Data-Port as Input
        #else
            P_DD_DDR = 0xFF;
        #endif
        
        RW_0;
        RS_1;
    }
    Leider habe ich seit dem das Problem gelöst ist, wohl ein Neues dazubekommen. Irgendwie führt der µC nicht mehr so zuverlässig das Programm aus, manchamal schreibt er gar nichts aufs Display ( der Cursor fehlt dann auch), manchmal funktioniert alles einwandfrei und manchmal vertut er sich mit den Adressen des DDRAM und schreibt die Buchstaben an falsche Stellen. Ich habe im Moment keine Ahnung woran das liegen könnte. Hat jemand ein Idee? Könnte ich einen Fehler im C-Programm ausschließen, denn manchmal funktioniert der Mist ja??

    Hier nochmal der Testcode, der sich auf die schon gepostete Lib bezieht:

    Code:
    #include <avr/io.h>
    #include "HD44780.h"
    #include "uart.h"
    
    int main(void)
    {    
        
        DDRC |= 0x3F;
        PORTC &= ~0x3F;
        
        lcd_init();
        
        lcd_write("LCD-Testing");
        
        lcd_pos(3,2);
        lcd_write("Welche Zeile?");
        
        lcd_pos(0,4);
        lcd_write("Zeile 4?");
        
        delay_ms(1000);
        PORTC |= 0x3F;
        while(1)
        {        
        }
    }
    Also ich bin schon wieder ratlos und deshalb um jede Hilfe oder Denkanstoß dankbar!
    mfg crowdy

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    938
    Fremden Source verstehend zu lesen macht mir offengestanden zu viel Mühe (andere hier sind diesbezüglich begabter). Daher die stumpfe Frage:
    Hast du eventuell die busy-Flag-Abfrage auch schon bei den Schreibvorgängen zur Initialisierung verwendet?
    Dort sind i.d.R. Mindestwartezeiten einzuhalten.

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    04.02.2005
    Beiträge
    76
    Hi RoboHolIC,
    danke für deine offene Antwort, hab ne weile gebraucht um das zu testen. Tatsächlich habe ich das BF zu früh abgefragt, aber da war das LCD noch recht tolerant. Es lag dann am Timing für das Enable-Signal, es war viel zu konservativ 15µs (ich wollte auf der sicheren Seite sein) nun habe ich es auf 3µs begrenzt und es funktioniert so weit einwandfrei.
    mfg crowdy

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    938
    Zitat Zitat von crowdy Beitrag anzeigen
    . . . Timing für das Enable-Signal . . viel zu konservativ 15µs . . auf 3µs begrenzt und es funktioniert so weit einwandfrei.
    Hmm, hmm .... komisch!
    Ich habe das Datenblatt zum HD44780 studiert: Dort ist nur eine minimale High-Zeit für das Enable angegeben. D.h., es kann eigentlich gar nicht zu lang sein. Die Bus-Kompatibilität der sog. kompatiblen Matrixcontrollerchips ("KS<irgendwas>") setze ich jetzt einfach mal mutig voraus.

Ähnliche Themen

  1. LCD HD44780 im 4-bit Mode mit Busy-Abfrage
    Von crowdy im Forum C - Programmierung (GCC u.a.)
    Antworten: 1
    Letzter Beitrag: 26.05.2011, 20:12
  2. LCD-Display 8bit mit busy-flag-Abfrage
    Von BoGe-Ro im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 25.08.2010, 14:49
  3. 20x4Display: Abfrage "Busy-Flag" reagiert nicht
    Von Dolfo im Forum Assembler-Programmierung
    Antworten: 0
    Letzter Beitrag: 17.10.2007, 22:56
  4. Alle HD44780-LCDs mit 4 Bit ansteuerbar?
    Von Jaecko im Forum Elektronik
    Antworten: 4
    Letzter Beitrag: 23.11.2006, 08:23
  5. LCD-Display 16*2: Auf welchem Pin ist das Busy-Flag??
    Von Minifriese im Forum Elektronik
    Antworten: 6
    Letzter Beitrag: 07.05.2005, 23:48

Berechtigungen

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