Forum: Mikrocontroller und Digitale Elektronik Betrieb eines LCD (HD44780) an Port2


von Mikrocontroller Rookie (Gast)


Lesenswert?

Hallo zusammen,

ich würde gerne einen LCD (HD44780) an Port2 des MSP430G2553 betreiben.

Die Beschaltung soll folgendermaßen sein:

DB7 -> P2.5
DB6 -> P2.4
DB5 -> P2.3
DB4 -> P2.2

RS -> P2.0
RW -> GND
E -> P2.1


Beim Googlen fand ich einen Lösungsvorschlag (allerdings für Port 1 mit 
P1.7 bis P1.4 für die Datenleitungen DB7 bis DB4) der auch funktioniert.

Allerdings zeigt mir das Display bei Portierung von Port1 auf Port2 
wieder nur die Balken an.

Angepasst wurden nur die Defines (siehe Code)




#include  "msp430.h"

#define     LCM_DIR               P2DIR
#define     LCM_OUT               P2OUT

//

#define     LCM_PIN_RS            BIT0          // P2.0
#define     LCM_PIN_EN            BIT1          // P2.1
#define     LCM_PIN_D7            BIT5          // P2.5
#define     LCM_PIN_D6            BIT4          // P2.4
#define     LCM_PIN_D5            BIT3          // P2.3
#define     LCM_PIN_D4            BIT2          // P2.2



#define     LCM_PIN_MASK  ((LCM_PIN_RS | LCM_PIN_EN | LCM_PIN_D7 | 
LCM_PIN_D6 | LCM_PIN_D5 | LCM_PIN_D4))

#define     FALSE                 0
#define     TRUE                  1

//
// Routine Desc:
//
// This is the function that must be called
// whenever the LCM needs to be told to
// scan it's data bus.
//
// Parameters:
//
//     void.
//
// Return
//
//     void.
//
void PulseLcm()
{
    //
    // pull EN bit low
    //
    LCM_OUT &= ~LCM_PIN_EN;
    __delay_cycles(200);

    //
    // pull EN bit high
    //
    LCM_OUT |= LCM_PIN_EN;
    __delay_cycles(200);

    //
    // pull EN bit low again
    //
    LCM_OUT &= (~LCM_PIN_EN);
    __delay_cycles(200);
}



//
// Routine Desc:
//
// Send a byte on the data bus in the 4 bit mode
// This requires sending the data in two chunks.
// The high nibble first and then the low nible
//
// Parameters:
//
//    ByteToSend - the single byte to send
//
//    IsData - set to TRUE if the byte is character data
//                  FALSE if its a command
//
// Return
//
//     void.
//
void SendByte(char ByteToSend, int IsData)
{
    //
    // clear out all pins
    //
    LCM_OUT &= (~LCM_PIN_MASK);
    //
    // set High Nibble (HN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT |= (ByteToSend & 0x3C);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }

    //
    // we've set up the input voltages to the LCM.
    // Now tell it to read them.
    //
    PulseLcm();
     //
    // set Low Nibble (LN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT &= (~LCM_PIN_MASK);
    LCM_OUT |= ((ByteToSend & 0x0F) << 4);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }

    //
    // we've set up the input voltages to the LCM.
    // Now tell it to read them.
    //
    PulseLcm();
}


//
// Routine Desc:
//
// Set the position of the cursor on the screen
//
// Parameters:
//
//     Row - zero based row number
//
//     Col - zero based col number
//
// Return
//
//     void.
//
void LcmSetCursorPosition(char Row, char Col)
{
    char address;

    //
    // construct address from (Row, Col) pair
    //
    if (Row == 0)
    {
        address = 0;
    }
    else
    {
        address = 0x40;
    }

    address |= Col;

    SendByte(0x80 | address, FALSE);
}


//
// Routine Desc:
//
// Clear the screen data and return the
// cursor to home position
//
// Parameters:
//
//    void.
//
// Return
//
//     void.
//
void ClearLcmScreen()
{
    //
    // Clear display, return home
    //
    SendByte(0x01, FALSE);
    SendByte(0x02, FALSE);
}


//
// Routine Desc:
//
// Initialize the LCM after power-up.
//
// Note: This routine must not be called twice on the
//           LCM. This is not so uncommon when the power
//           for the MCU and LCM are separate.
//
// Parameters:
//
//    void.
//
// Return
//
//     void.
//
void InitializeLcm(void)
{
    //
    // set the MSP pin configurations
    // and bring them to low
    //
    LCM_DIR |= LCM_PIN_MASK;
    LCM_OUT &= ~(LCM_PIN_MASK);


    //
    // wait for the LCM to warm up and reach
    // active regions. Remember MSPs can power
    // up much faster than the LCM.
    //
    __delay_cycles(100000);


    //
    // initialize the LCM module
    //
    // 1. Set 4-bit input
    //
    LCM_OUT &= ~LCM_PIN_RS;
    LCM_OUT &= ~LCM_PIN_EN;

    LCM_OUT = 0x20;
    PulseLcm();

    //
    // set 4-bit input - second time.
    // (as reqd by the spec.)
    //
    SendByte(0x28, FALSE);

    //
    // 2. Display on, cursor on, blink cursor
    //
    SendByte(0x0E, FALSE);

    //
    // 3. Cursor move auto-increment
    //
    SendByte(0x06, FALSE);
}


//
// Routine Desc
//
// Print a string of characters to the screen
//
// Parameters:
//
//    Text - null terminated string of chars
//
// Returns
//
//     void.
//
void PrintStr(char *Text)
{
    char *c;

    c = Text;

    while ((c != 0) && (*c != 0))
    {
        SendByte(*c, TRUE);
        c++;
    }
}


//
// Routine Desc
//
// main entry point to the sketch
//
// Parameters
//
//     void.
//
// Returns
//
//     void.
//
void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer

    InitializeLcm();

    ClearLcmScreen();

    PrintStr("Hello World!");

    while (1)
    {
        __delay_cycles(1000);
    }

}


Was muss eurer Meinung nach am Code noch geändert werden?

Ich würde mich für jede Hilfe sehr freuen.

Gruß

Der Rookie

von Ben P. (ben5en)


Lesenswert?

Hallo,

ich stehe gerade vor selbiger Frage und möchte, auch wenn der Thread alt 
ist, keinen neuen aufmachen.

Gibt es mittlerweile eine Lösung oder kann sich noch mal jmd. der Sache 
annehmen?

Vielen Dank.

von Nop (Gast)


Lesenswert?

Was ist denn überhaupt mit dem analogen Kontrastspannungseingang des 
Displays, wurde der vernünftig gesetzt? Lauter Balken klingt nach 
verkehrter Kontrastspannung. Wahrscheinlich der Bequemlichkeit halber 
nach GND gebrückt, was maximalen Kontrast ergibt.

von spess53 (Gast)


Lesenswert?

Hi

>ich stehe gerade vor selbiger Frage und möchte, auch wenn der Thread alt
>ist, keinen neuen aufmachen.

Vielleicht hängst du dein aktuelles Programm mal an.

MfG Spess

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mikrocontroller Rookie schrieb:
> DB7 -> P2.5
> DB6 -> P2.4
> DB5 -> P2.3
> DB4 -> P2.2

Mikrocontroller Rookie schrieb:
> // set High Nibble (HN) -
>     // usefulness of the identity mapping
>     // apparent here. We can set the
>     // DB7 - DB4 just by setting P1.7 - P1.4
>     // using a simple assignment
>     //
>     LCM_OUT |= (ByteToSend & 0x3C);

Das klappt schon mal nicht. Du maskierst zwar die richtigen Bits, 
schiebst aber die Daten nicht an die richtige Stelle. Wenn du das 
Highnibble von 'ByteToSend' an den richtigen Pins haben willst, musst du 
noch zweimal nach rechts schieben.

Mikrocontroller Rookie schrieb:
> LCM_OUT &= (~LCM_PIN_MASK);
>     LCM_OUT |= ((ByteToSend & 0x0F) << 4);

Und hier nochmal. Hier nicht 4 mal, sondern nur 2 mal nach links 
schieben, und nicht das Maskieren mit 0x3C vergessen.

von Ben P. (ben5en)


Lesenswert?

Das ist mein Code. Angeschlossen ist alles ordentlich. Kontrast über 
Poti.

Ich denke es liegt am Befehl "SendByte" - dort muss sicherlich noch das 
Verschieben angepasst werden, nur komme ich alleine einfach nicht drauf 
wie.

//
// MSP430 LCD Code
//

#include  "msp430x20x2.h"

#define     LCM_DIR               P2DIR
#define     LCM_OUT               P2OUT

#define     LCM_PIN_D4            BIT0          // P2.0
#define     LCM_PIN_D5            BIT1          // P2.1
#define     LCM_PIN_D6            BIT2          // P2.2
#define     LCM_PIN_D7            BIT3          // P2.3
#define     LCM_PIN_EN            BIT4          // P2.4
#define     LCM_PIN_RS            BIT5          // P2.5


#define     LCM_PIN_MASK  ((LCM_PIN_RS | LCM_PIN_EN | LCM_PIN_D7 | 
LCM_PIN_D6 | LCM_PIN_D5 | LCM_PIN_D4))

#define     FALSE                 0
#define     TRUE                  1

//
// Routine Desc:
//
// This is the function that must be called
// whenever the LCM needs to be told to
// scan it's data bus.
//
// Parameters:
//
//     void.
//
// Return
//
//     void.
//
void PulseLcm()
{
    //
    // pull EN bit low
    //
    LCM_OUT &= ~LCM_PIN_EN;
    __delay_cycles(200);

    //
    // pull EN bit high
    //
    LCM_OUT |= LCM_PIN_EN;
    __delay_cycles(200);

    //
    // pull EN bit low again
    //
    LCM_OUT &= (~LCM_PIN_EN);
    __delay_cycles(200);
}



//
// Routine Desc:
//
// Send a byte on the data bus in the 4 bit mode
// This requires sending the data in two chunks.
// The high nibble first and then the low nible
//
// Parameters:
//
//    ByteToSend - the single byte to send
//
//    IsData - set to TRUE if the byte is character data
//                  FALSE if its a command
//
// Return
//
//     void.
//
void SendByte(char ByteToSend, int IsData)
{
    //
    // clear out all pins
    //
    LCM_OUT &= (~LCM_PIN_MASK);
    //
    // set High Nibble (HN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT |= (ByteToSend & 0xF0);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }

    //
    // we've set up the input voltages to the LCM.
    // Now tell it to read them.
    //
    PulseLcm();
     //
    // set Low Nibble (LN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT &= (~LCM_PIN_MASK);
    LCM_OUT |= ((ByteToSend & 0x0F) << 4);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }

    //
    // we've set up the input voltages to the LCM.
    // Now tell it to read them.
    //
    PulseLcm();
}


//
// Routine Desc:
//
// Set the position of the cursor on the screen
//
// Parameters:
//
//     Row - zero based row number
//
//     Col - zero based col number
//
// Return
//
//     void.
//
void LcmSetCursorPosition(char Row, char Col)
{
    char address;

    //
    // construct address from (Row, Col) pair
    //
    if (Row == 0)
    {
        address = 0;
    }
    else
    {
        address = 0x40;
    }

    address |= Col;

    SendByte(0x80 | address, FALSE);
}


//
// Routine Desc:
//
// Clear the screen data and return the
// cursor to home position
//
// Parameters:
//
//    void.
//
// Return
//
//     void.
//
void ClearLcmScreen()
{
    //
    // Clear display, return home
    //
    SendByte(0x01, FALSE);
    SendByte(0x02, FALSE);
}


//
// Routine Desc:
//
// Initialize the LCM after power-up.
//
// Note: This routine must not be called twice on the
//           LCM. This is not so uncommon when the power
//           for the MCU and LCM are separate.
//
// Parameters:
//
//    void.
//
// Return
//
//     void.
//
void InitializeLcm(void)
{
    //
    // set the MSP pin configurations
    // and bring them to low
    //
    LCM_DIR |= LCM_PIN_MASK;
    LCM_OUT &= ~(LCM_PIN_MASK);


    //
    // wait for the LCM to warm up and reach
    // active regions. Remember MSPs can power
    // up much faster than the LCM.
    //
    __delay_cycles(100000);


    //
    // initialize the LCM module
    //
    // 1. Set 4-bit input
    //
    LCM_OUT &= ~LCM_PIN_RS;
    LCM_OUT &= ~LCM_PIN_EN;

    LCM_OUT = 0x20;
    PulseLcm();

    //
    // set 4-bit input - second time.
    // (as reqd by the spec.)
    //
    SendByte(0x28, FALSE);

    //
    // 2. Display on, cursor on, blink cursor
    //
    SendByte(0x0E, FALSE);

    //
    // 3. Cursor move auto-increment
    //
    SendByte(0x06, FALSE);
}


//
// Routine Desc
//
// Print a string of characters to the screen
//
// Parameters:
//
//    Text - null terminated string of chars
//
// Returns
//
//     void.
//
void PrintStr(char *Text)
{
    char *c;

    c = Text;

    while ((c != 0) && (*c != 0))
    {
        SendByte(*c, TRUE);
        c++;
    }
}


//
// Routine Desc
//
// main entry point to the sketch
//
// Parameters
//
//     void.
//
// Returns
//
//     void.
//
void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer

    InitializeLcm();

    ClearLcmScreen();

    PrintStr("A");

    while (1)
    {
        __delay_cycles(1000);
    }

}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Benjamin P. schrieb:
> // set High Nibble (HN) -
>     // usefulness of the identity mapping
>     // apparent here. We can set the
>     // DB7 - DB4 just by setting P1.7 - P1.4
>     // using a simple assignment
>     //
>     LCM_OUT |= (ByteToSend & 0xF0);

Habe ich dir doch schon mal erklärt. Wenn die Datenleitungen des LCD 
nicht an 7-4 angeschlossen sind, musst du nach rechts schieben. Z.B. so:
1
 
2
LCM_OUT |= ((ByteToSend >> 2) & 0x3C);
Wenn das zu schwierig für dich ist, dann schliess das LCD mit den 
Datenleitungen an P2.7 bis P2.4 an und lass den Code so wie er ist.

Wenn dus trotzdem probieren willst, vergiss nicht, das dann noch das low 
Nibble kommt. Die Verschieberei hier ist simpel und wird dem TE 
überlassen :-)

von Ben P. (ben5en)


Lesenswert?

Es lag einfach nur am Bitshift, welcher getauscht werden musste. Das 
habe ich abermals übersehen, das hier einfach die Reihenfolge des 
Verschiebens getauscht werden muss.

void SendByte(char ByteToSend, int IsData)
{
    //
    // clear out all pins
    //
    LCM_OUT &= (~LCM_PIN_MASK);
    //
    // set High Nibble (HN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT |= ((ByteToSend & 0xF0) >> 4);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }

    //
    // we've set up the input voltages to the LCM.
    // Now tell it to read them.
    //
    PulseLcm();
     //
    // set Low Nibble (LN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT &= (~LCM_PIN_MASK);
    LCM_OUT |= (ByteToSend & 0x0F);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.