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

  1. /*************************************************
  2.  *     ___       _             _    
  3.  *    |   |_ _ _| |___ ___   _| |___
  4.  *    | | |_'_| . | -_|  _|_| . | -_|
  5.  *    |___|_,_|___|___|___|_|___|___|
  6.  *
  7.  * FILE:     main.c
  8.  * Author:   declis (xdec.de)
  9.  ************************************************/
  10.  
  11. #include <msp430g2231.h>
  12. #include "def_lcd.h"
  13.  
  14. void main(void)
  15. {
  16.     const char string_site[]={"www.xdec.de"};
  17.     volatile signed char rechts=0,links=39;
  18.     WDTCTL=WDTPW+WDTHOLD;
  19.     BCSCTL1=CALBC1_1MHZ;
  20.     DCOCTL=CALDCO_1MHZ;
  21.  
  22.     init_USI();                         // Init. USI
  23.     init_lcd();                         // Init. LCD
  24.  
  25.     //small display-animation
  26.     while(rechts<=14)
  27.     {
  28.         write_char(rechts,0,'>');
  29.         write_char(rechts++,1,'>');
  30.         write_char(links,0,'<');
  31.         write_char(links--,1,'<');
  32.         wait_ms(100);
  33.  
  34.         if(rechts==14)
  35.         {
  36.             write_string(14,0,string_site);
  37.             while(rechts!=20)
  38.             {
  39.                 write_char(rechts++,1,'>');
  40.                 write_char(links--,1,'<');
  41.                 wait_ms(100);
  42.             }
  43.         }
  44.     }
  45.  
  46.     while(rechts>=0)
  47.     {
  48.         write_char(rechts--,1,' ');
  49.         write_char(links++,1,' ');
  50.         wait_ms(100);
  51.     }
  52.  
  53.     rechts=13;
  54.     links=26;
  55.  
  56.     while(rechts>=0)
  57.     {
  58.         write_char(rechts--,0,' ');
  59.         write_char(links++,0,' ');
  60.         wait_ms(100);
  61.     }
  62.  
  63.     while(1);
  64. }
/*************************************************
 *     ___       _             _     
 *    |   |_ _ _| |___ ___   _| |___
 *    | | |_'_| . | -_|  _|_| . | -_|
 *    |___|_,_|___|___|___|_|___|___|
 *
 * 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

  1. ´/*************************************************
  2.  *     ___       _             _    
  3.  *    |   |_ _ _| |___ ___   _| |___
  4.  *    | | |_'_| . | -_|  _|_| . | -_|
  5.  *    |___|_,_|___|___|___|_|___|___|
  6.  *
  7.  * FILE:     lib_lcd.c
  8.  * Author:   declis (xdec.de)
  9.  ************************************************/
  10.  
  11. #include <msp430g2231.h>
  12. #include "def_lcd.h"
  13.  
  14. // send one character to display ; x=0...39 ; y=0,1
  15. void write_char(unsigned char x_pos,unsigned char y_pos,unsigned char character)
  16. {
  17.     set_cursor(x_pos,y_pos);            // set cursor to xy-position
  18.     set_instruction(1,character);
  19. }
  20.  
  21. // send a string to display ; x=0..39 ; y=0,1
  22. void write_string(unsigned char x_pos,unsigned char y_pos,const char *string)
  23. {
  24.     set_cursor(x_pos,y_pos);            // set cursor to xy-position
  25.     while(*string!=0)
  26.         set_instruction(1,*string++);
  27. }
  28.  
  29. // set cursor to xy-position ; x=0...39 ; y=0,1
  30. void set_cursor(unsigned char x_pos,unsigned char y_pos)
  31. {
  32.     if(y_pos)                           // second row + x_pos
  33.         set_instruction(0,second_row+x_pos);
  34.     else                                // first row + x_pos
  35.         set_instruction(0,first_row+x_pos);
  36. }
  37.  
  38. // 8bit-interface emulation for 4bit-interface (8bit into 2*4bit converter)
  39. // register_sel = 0,1 (0=instruction,1=data)
  40. // number = 8bit value
  41. void set_instruction(unsigned char register_sel,unsigned char number)
  42. {
  43.     volatile unsigned char high_part=0,low_part=0;
  44.  
  45.     high_part=(number>>4);            // transform 8bit into 2*4bit
  46.     low_part=(number&0x0F);
  47.  
  48.     if(register_sel)                // if register_sel=1 -> RS=high
  49.     {
  50.         high_part|=RS;
  51.         low_part|=RS;
  52.     }
  53.  
  54.     send_lcd(high_part);            // send high part
  55.     send_lcd(low_part);             // send low part
  56. }
  57.  
  58. void send_lcd(unsigned char value)
  59. {
  60.     volatile unsigned char run=0;
  61.  
  62.     value|=Enable;                  // enable=high
  63.  
  64.     while(run!=2)
  65.     {
  66.         if(run) value&=~Enable;     // 2nd run, enable=low
  67.         USISRL=value;               // USI 8bit shift register= = 7bit value
  68.         USICNT=7;                   // start transmission (7bit)
  69.         wait_us(100);
  70.         run++;
  71.     }
  72. }
  73.  
  74. void init_lcd(void)
  75. {
  76.     wait_ms(20);
  77.     send_lcd(_8bit_inter);
  78.     wait_ms(5);
  79.     send_lcd(_8bit_inter);
  80.     wait_ms(2);
  81.     send_lcd(_8bit_inter);
  82.     send_lcd(2);                // change interface to 4bit
  83.  
  84.     set_instruction(0,40);      // 5x8, 2-rows
  85.     set_instruction(0,8);       // display off
  86.     set_instruction(0,1);       // clear display
  87.     set_instruction(0,6);       // shift cursor to the right, no display shift
  88.     set_instruction(0,12);      // display on
  89. }
  90.  
  91. void init_USI(void)
  92. {
  93.     // P1.7 (strobe) -> output
  94.     P1DIR|=strobe;
  95.     P1OUT&=~strobe;
  96.     // SPI Master, SI enabled, CLK enabled, LSB first, output enabled, USI in reset state
  97.     USICTL0|=USIPE6+USIPE5+USIMST+USILSB+USIOE+USISWRST;
  98.     // USI counter interrupt enabled,
  99.     // data is captured on the first CLK edge and changed on the following edge
  100.     USICTL1|=USICKPH+USIIE;
  101.     // CLK-Source=SMCLK=1MHz
  102.     USICKCTL|=USISSEL_2;
  103.     // USI released for operation
  104.     USICTL0&=~USISWRST;
  105.     // clear USIIFG
  106.     USICTL1&=~USIIFG;
  107.     // global interrupt enabled
  108.     _EINT();
  109. }
  110.  
  111. #pragma INTERRUPT (USI)
  112. #pragma vector=USI_VECTOR
  113. void USI(void)
  114. {
  115.     P1OUT|=strobe;                  // strobe-pulse
  116.     P1OUT&=~strobe;
  117.     USICTL1&=~USIIFG;               // clear USIIFG
  118. }
  119.  
  120. void wait_ms(unsigned int m_sec)
  121. {
  122.     while(m_sec--)
  123.         __delay_cycles(1000);
  124. }
  125.  
  126. void wait_us(unsigned int u_sec)
  127. {
  128.     while(u_sec--)
  129.         __delay_cycles(1);
  130. }
´/*************************************************
 *     ___       _             _     
 *    |   |_ _ _| |___ ___   _| |___
 *    | | |_'_| . | -_|  _|_| . | -_|
 *    |___|_,_|___|___|___|_|___|___|
 *
 * 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

  1. /*************************************************
  2.  *     ___       _             _    
  3.  *    |   |_ _ _| |___ ___   _| |___
  4.  *    | | |_'_| . | -_|  _|_| . | -_|
  5.  *    |___|_,_|___|___|___|_|___|___|
  6.  *
  7.  * FILE:     def_lcd.h
  8.  * Author:   declis (xdec.de)
  9.  ************************************************/
  10.  
  11. #ifndef DEF_LCD_H_
  12. #define DEF_LCD_H_
  13.  
  14. void write_char(unsigned char x_pos,unsigned char y_pos,unsigned char character);
  15. void write_string(unsigned char x_pos,unsigned char y_pos,const char *string);
  16. void set_cursor(unsigned char x_pos,unsigned char y_pos);
  17. void set_instruction(unsigned char register_sel,unsigned char number);
  18. void send_lcd(unsigned char value);
  19. void init_USI(void);
  20. void init_lcd(void);
  21. void wait_ms(unsigned int);
  22. void wait_us(unsigned int);
  23.  
  24. #define _8bit_inter     0x03
  25. #define Enable          0x40
  26. #define RS              0x20
  27.  
  28. #define first_row       0x80
  29. #define second_row      0xC0
  30.  
  31. //8bit-shift-register
  32. #define clock       0x0020          //"Strobe" at P1.5
  33. #define data        0x0040          //"Data" at P1.6
  34. #define strobe      0x0080          //"Clock" at P1.7
  35.  
  36. #endif /*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.

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.