目次
前
次
キャラクタLCDの6ピン制御
キャラクタLCDは、14ピンをもち、4種類に分けられる。
- 電源ピン Vdd GND
- コントラスト調整 Vo
- 制御ピン E RS WR
- データ DB0 -> DB7
通常は、キャラクタLCDからデータを入力することは殆どないので
WRピンを、0Vに固定し、書き込みだけできるようにすればよい。
制御ピンがE RS の2本、データピンが8本の合計10ピンで、表示を
制御できる。
LCD制御のデファクトスタンダードのHD47780では、データを
4ビット2回に分けて転送するモードをもつ。このインタフェースを
もつLCDでは、10ピンから、さらに4ピン減らした6ピン制御が
できる。
最下層処理
LCDにデータを転送するシーケンスは、以下とする。
- EをLにする
- RSを、HかLのどちらかに設定
- データの上位4ビットを出力
- EをHにする
- EをLにする
- データの下位4ビットを出力
- EをHにする
- EをLにする
最下層処理関数
メモリマップドI/OとI/OマップドI/Oで、動作の違いがあるので
それぞれの関数を定義する。
メモリマップドI/Oの場合
typedef unsigned char UBYTE ;
#define OFF 0
#define ON OFF+1
void put_lcd_primitive(UBYTE which,UBYTE dat)
{
UBYTE i,tmp ;
tmp = dat ;
LCD_E = OFF ;
LCD_RS = which ;
/* upper nibble */
LCD_NIBBLE = (tmp >> 4) & 0x0f ;
LCD_E = ON ;
LCD_E = OFF ;
/* lower nibble */
tmp &= 0x0f ;
LCD_NIBBLE = tmp ;
LCD_E = ON ;
LCD_E = OFF ;
}
I/OマップドI/Oの場合
#define LCD_E 0x20
#define LCD_RS 0x10
void put_lcd_primitive(UBYTE which,UBYTE dat)
{
UBYTE ctmp;
/* 0 -> E */
ctmp &= ~LCD_E ;
outp( LCD_CP , ctmp );
/* RS */
ctmp &= ~LCD_RS ;
if ( which ) { ctmp |= LCD_RS ; }
outp( LCD_CP , ctmp );
/* upper nibble */
ctmp &= 0xf0 ;
ctmp |= ((dat >> 4) & 0x0f) ;
outp( LCD_DP , ctmp );
/* 1 -> E */
ctmp |= LCD_E ;
outp( LCD_CP , ctmp );
/* 0 -> E */
ctmp &= ~LCD_E ;
outp( LCD_CP , ctmp );
/* lower nibble */
ctmp &= 0xf0 ;
ctmp |= dat & 0x0f ;
outp( LCD_DP , ctmp );
/* 1 -> E */
ctmp |= LCD_E ;
outp( LCD_CP , ctmp );
/* 0 -> E */
ctmp &= ~LCD_E ;
outp( LCD_CP , ctmp );
}
初期化処理
8ビットデータアクセスの場合は、以下のように初期化する。
- 最短15ms待ち
- RS=L状態で、0x30を転送
- 最短4.1ms待ち
- RS=L状態で、0x30を転送
- 最短100us待ち
- RS=L状態で、0x30を転送
- RS=L状態で、0x20を転送
- RS=L状態で、0x28を転送
- RS=L状態で、0x08を転送
- 最短2ms待ち
- RS=L状態で、0x0eを転送
- 最短1ms待ち
- RS=L状態で、0x06を転送
- 最短1ms待ち
- RS=L状態で、0x01を転送
- 最短1ms待ち
ms単位での時間待ちをすることができる関数があるとして
次のように、初期化コードを記述する。
void init_lcd(void)
{
/* initialize hardware */
delay_ms(45) ;
put_lcd_p4(OFF,0x30); /* select 8 bits */
delay_ms(5) ;
put_lcd_p4(OFF,0x30); /* select 8 bits */
delay_ms(1);
put_lcd_p4(OFF,0x30); /* select 8 bits */
delay_ms(1);
/* set function */
put_lcd_p4(OFF,0x20); /* select 4 bits */
delay_ms(1);
/* select 2 line display */
put_lcd_function(0x28);
delay_ms(1);
/* display off */
put_lcd_function(0x08);
delay_ms(1);
/* display on , cursor appear */
put_lcd_function(0x0e);
delay_ms(1);
/* entry mode*/
put_lcd_function(0x06);
delay_ms(1);
/* clear */
put_lcd_function(0x01);
delay_ms(1);
}
8ビットのバスインタフェースの場合
初期化関数は、以下となります。
void init_lcd(void)
{
/* initialize hardware */
delay_ms(15) ; /* 15ms */
put_lcd_primitive(OFF,0x30);
delay_ms(5) ; /* 5ms */
put_lcd_primitive(OFF,0x30);
delay_ms(1); /* 1ms */
put_lcd_primitive(OFF,0x30);
delay_ms(1); /* 1ms */
/* set function */
put_lcd_primitive(OFF,0x38);
put_lcd_primitive(OFF,0x08);
put_lcd_primitive(OFF,0x01);
delay_ms(2); /* 2ms */
put_lcd_primitive(OFF,0x0c);
}
文字列表示
行と桁を指定し、文字列を表示するには、次のシーケンスを実行する。
- 桁と行から、LCD内部のメモリアドレスを求める
- メモリアドレスを転送
- 1文字ずつ転送
2行のLCDでは、次のようにアドレスがエントリーを指定されている
0行0桁 → 0x00
1行0桁 → 0x40
4行のLCDでは、次のようにアドレスがエントリーを指定されている
0行0桁 → 0x00
1行0桁 → 0x40
2行0桁 → 0x14
3行0桁 → 0x54
文字列表示の関数を定義すると、次のようになる。
#define MASK80 0x80
void put_lcd_str(UBYTE r,UBYTE c,UBYTE *ptr)
{
UBYTE adr ;
/* check range */
#ifdef LCD_4LINES
if ( r > 3 ) return ;
if ( c > 19 ) return ;
#else
if ( r > 1 ) return ;
if ( c > 15 ) return ;
#endif
/* set address */
switch ( r ) {
case 1 : adr = 0x40 ; break ;
case 2 : adr = 0x14 ; break ;
case 3 : adr = 0x54 ; break ;
default : adr = 0x00 ; break ;
}
adr += c ;
adr |= MASK80 ;
put_lcd_primitive(OFF,adr);
while ( *ptr != '\0' ) {
put_lcd_primitive(ON,*ptr);
ptr++ ;
}
}
AVRで利用できる、初期化、最下層処理
ラッパー関数をまとめると、以下。
void init_lcd(void)
{
/* initialize hardware */
delay_ms(45) ;
put_lcd_p4(OFF,0x30); /* select 8 bits */
delay_ms(5) ;
put_lcd_p4(OFF,0x30); /* select 8 bits */
delay_ms(1);
put_lcd_p4(OFF,0x30); /* select 8 bits */
delay_ms(1);
/* set function */
put_lcd_p4(OFF,0x20); /* select 4 bits */
delay_ms(1);
/* select 2 line display */
put_lcd_function(0x28);
delay_ms(1);
/* display off */
put_lcd_function(0x08);
delay_ms(1);
/* display on , cursor appear */
put_lcd_function(0x0e);
delay_ms(1);
/* entry mode*/
put_lcd_function(0x06);
delay_ms(1);
/* clear */
put_lcd_function(0x01);
delay_ms(1);
}
void put_lcd_function(UBYTE xdat)
{
put_lcd_primitive(OFF,xdat);
}
void put_lcd_data(UBYTE xdat)
{
put_lcd_primitive(ON,xdat);
}
void put_lcd_primitive(UBYTE which,UBYTE dat)
{
put_lcd_p4(which,dat & MASKF0);
put_lcd_p4(which,(dat << 4) & MASKF0);
}
void put_lcd_p4(UBYTE which,UBYTE dat)
{
/* LCD_E : OFF */
PORTD &= ~(1 << LCD_E) ;
/* LCD_RS : ON or OFF */
PORTD &= ~(1 << LCD_RS) ;
if ( which ) { PORTD |= (1 << LCD_RS) ;}
/* nibble */
{
/* clear upper nibble */
PORTD &= MASK0F ;
/* impress upper nibble */
PORTD |= (dat & MASKF0) ;
/* trigger H */
PORTD |= (1 << LCD_E) ;
/* delay */
delay_ms(1);
/* trigger L */
PORTD &= ~(1 << LCD_E) ;
}
}
void put_lcd_str(UBYTE r,UBYTE c,UBYTE *ptr)
{
UBYTE adr ;
/* check range */
if ( r > 1 ) return ;
if ( c > 7 ) return ;
/* set address */
adr = 0x00 ;
if ( r ) { adr += 0x40 ; }
adr += c ;
adr |= MASK80 ;
put_lcd_function(adr);
/* send character */
for ( adr = c ; adr < 16 ; adr++ ) {
put_lcd_data(*ptr);
ptr++ ;
}
}
目次
前
次