MSP430 HD44780 seriell ansteuern

Im folgenden Beispiel-Programm wird ein LCD mit HD44780-Controller seriell angesteuert (Quick’n’Dirty). Realisiert wird die Ansteuerung per Schieberegister und der USI-Schnitstelle des MSPs (siehe “Daten per USI (SPI) an Schieberegister senden”). Ziel war es, mit so wenigen Ports wie möglich, ein HD44780-LCD (4bit-Interface) anzusteuern. Insgesamt benötigte Ports: 3.

Auf eine detaillierte Erklärung zum HD44780-Controller wird in diesem Beispiel nicht eingegangen. Das Display wird im 4bit-Modus betrieben. Es wird also immer High- und Low-Teil hintereinander übertragen. Es müssen also ingesamt pro Befehl 4*7bits an das Schieberegister übertragen werden:

1) High-Teil + Enable(High)
2) High-Teil + Enable(Low)
3) Low-Teil + Enable(High)
4) Low-Teil + Enable(Low)

Schaltplan

lcd_serial

Video

C-Programm

FILE: main.c

/*************************************************
 *     ___       _             _     
 *    |   |_ _ _| |___ ___   _| |___
 *    | | |_'_| . | -_|  _|_| . | -_|
 *    |___|_,_|___|___|___|_|___|___|
 *
 * FILE:     main.c
 * Author:   declis (xdec.de)
 ************************************************/

#include <msp430g2231.h>
#include "def_lcd.h"

void main(void)
{
    const char string_site[]={"www.xdec.de"};
    volatile signed char rechts=0,links=39;
    WDTCTL=WDTPW+WDTHOLD;
    BCSCTL1=CALBC1_1MHZ;
    DCOCTL=CALDCO_1MHZ;

    init_USI();                         // Init. USI
    init_lcd();                         // Init. LCD

    //small display-animation
    while(rechts<=14)
    {
        write_char(rechts,0,'>');
        write_char(rechts++,1,'>');
        write_char(links,0,'<');
        write_char(links--,1,'<');
        wait_ms(100);

        if(rechts==14)
        {
            write_string(14,0,string_site);
            while(rechts!=20)
            {
                write_char(rechts++,1,'>');
                write_char(links--,1,'<');
                wait_ms(100);
            }
        }
    }

    while(rechts>=0)
    {
        write_char(rechts--,1,' ');
        write_char(links++,1,' ');
        wait_ms(100);
    }

    rechts=13;
    links=26;

    while(rechts>=0)
    {
        write_char(rechts--,0,' ');
        write_char(links++,0,' ');
        wait_ms(100);
    }

    while(1);
}

FILE: lib_lcd.c

´/*************************************************
 *     ___       _             _     
 *    |   |_ _ _| |___ ___   _| |___
 *    | | |_'_| . | -_|  _|_| . | -_|
 *    |___|_,_|___|___|___|_|___|___|
 *
 * FILE:     lib_lcd.c
 * Author:   declis (xdec.de)
 ************************************************/

#include <msp430g2231.h>
#include "def_lcd.h"

// send one character to display ; x=0...39 ; y=0,1
void write_char(unsigned char x_pos,unsigned char y_pos,unsigned char character)
{
    set_cursor(x_pos,y_pos);            // set cursor to xy-position
    set_instruction(1,character);
}

// send a string to display ; x=0..39 ; y=0,1
void write_string(unsigned char x_pos,unsigned char y_pos,const char *string)
{
    set_cursor(x_pos,y_pos);            // set cursor to xy-position
    while(*string!=0)
        set_instruction(1,*string++);
}

// set cursor to xy-position ; x=0...39 ; y=0,1
void set_cursor(unsigned char x_pos,unsigned char y_pos)
{
    if(y_pos)                           // second row + x_pos
        set_instruction(0,second_row+x_pos);
    else                                // first row + x_pos
        set_instruction(0,first_row+x_pos);
}

// 8bit-interface emulation for 4bit-interface (8bit into 2*4bit converter)
// register_sel = 0,1 (0=instruction,1=data)
// number = 8bit value
void set_instruction(unsigned char register_sel,unsigned char number)
{
    volatile unsigned char high_part=0,low_part=0;

    high_part=(number>>4);            // transform 8bit into 2*4bit
    low_part=(number&0x0F);

    if(register_sel)                // if register_sel=1 -> RS=high
    {
        high_part|=RS;
        low_part|=RS;
    }

    send_lcd(high_part);            // send high part
    send_lcd(low_part);             // send low part
}

void send_lcd(unsigned char value)
{
    volatile unsigned char run=0;

    value|=Enable;                  // enable=high

    while(run!=2)
    {
        if(run) value&=~Enable;     // 2nd run, enable=low
        USISRL=value;               // USI 8bit shift register= = 7bit value
        USICNT=7;                   // start transmission (7bit)
        wait_us(100);
        run++;
    }
}

void init_lcd(void)
{
    wait_ms(20);
    send_lcd(_8bit_inter);
    wait_ms(5);
    send_lcd(_8bit_inter);
    wait_ms(2);
    send_lcd(_8bit_inter);
    send_lcd(2);                // change interface to 4bit

    set_instruction(0,40);      // 5x8, 2-rows
    set_instruction(0,8);       // display off
    set_instruction(0,1);       // clear display
    set_instruction(0,6);       // shift cursor to the right, no display shift
    set_instruction(0,12);      // display on
}

void init_USI(void)
{
    // P1.7 (strobe) -> output
    P1DIR|=strobe;
    P1OUT&=~strobe;
    // SPI Master, SI enabled, CLK enabled, LSB first, output enabled, USI in reset state
    USICTL0|=USIPE6+USIPE5+USIMST+USILSB+USIOE+USISWRST;
    // USI counter interrupt enabled,
    // data is captured on the first CLK edge and changed on the following edge
    USICTL1|=USICKPH+USIIE;
    // CLK-Source=SMCLK=1MHz
    USICKCTL|=USISSEL_2;
    // USI released for operation
    USICTL0&=~USISWRST;
    // clear USIIFG
    USICTL1&=~USIIFG;
    // global interrupt enabled
    _EINT();
}

#pragma INTERRUPT (USI)
#pragma vector=USI_VECTOR
void USI(void)
{
    P1OUT|=strobe;                  // strobe-pulse
    P1OUT&=~strobe;
    USICTL1&=~USIIFG;               // clear USIIFG
}

void wait_ms(unsigned int m_sec)
{
    while(m_sec--)
        __delay_cycles(1000);
}

void wait_us(unsigned int u_sec)
{
    while(u_sec--)
        __delay_cycles(1);
}

FILE: def_lcd.h

/*************************************************
 *     ___       _             _     
 *    |   |_ _ _| |___ ___   _| |___
 *    | | |_'_| . | -_|  _|_| . | -_|
 *    |___|_,_|___|___|___|_|___|___|
 *
 * FILE:     def_lcd.h
 * Author:   declis (xdec.de)
 ************************************************/

#ifndef DEF_LCD_H_
#define DEF_LCD_H_

void write_char(unsigned char x_pos,unsigned char y_pos,unsigned char character);
void write_string(unsigned char x_pos,unsigned char y_pos,const char *string);
void set_cursor(unsigned char x_pos,unsigned char y_pos);
void set_instruction(unsigned char register_sel,unsigned char number);
void send_lcd(unsigned char value);
void init_USI(void);
void init_lcd(void);
void wait_ms(unsigned int);
void wait_us(unsigned int);

#define _8bit_inter     0x03
#define Enable          0x40
#define RS              0x20

#define first_row       0x80
#define second_row      0xC0

//8bit-shift-register
#define clock       0x0020          //"Strobe" at P1.5
#define data        0x0040          //"Data" at P1.6
#define strobe      0x0080          //"Clock" at P1.7

#endif /*DEF_LCD_H_*/

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

This site uses Akismet to reduce spam. Learn how your comment data is processed.