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
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_*/