LCDキャラクタディスプレイモジュール(SC1602)表示プログラミング
AKI-H8/3048のオプション
(cygwin+GCC)
17Sep2002 Kosaka
1.はじめに
この文書はAKI-H8/3048のオプションであるLCDキャラクタディスプレイモジュール(以下LCDユニット)表示プログラミングを解説した学習用文書です。LCDを駆動するためにはLCDの使い方および,AKI-H8のポート割付を知らなければなりません。これらのことに興味がなく,使える関数をすぐに入手したい場合は
松林氏のライブラリ
または hamayanさんのライブラリ
を参照してください。
LCDキャラクタディスプレイモジュール 16×2 の使用を前提に解説します。
ファイルのダウンロード
DownLoad |
2.LCDユニットの取り付け
説明書にしたがってLCDユニットを取り付けます。マザーボード上で+5VとGNDラインを追ってゆくと,それぞれ1箇所ずつ未接続の個所があるので,はんだ付けで接続します。よく見ると,この接続位置のマザーボードの表面に「+」「-」と書いて○が3個ずつ書いてあります。
LCDユニットを取り付けと,マザーボード上の「+5V」と「GND」の処理
3.AKI-H8/3048でのLCDユニットのポート割り付け
AKI-H8のPort3がLCDユニットに接続されています。本来LCDユニットは8ビットのコードで表現された文字(半角文字)を表示します。
しかしAKI-H8では配線数を減らすために,LCDユニットの機能を利用して4ビット幅でデータを送信しています。
LCDユニット側にはRead/~Writeの端子がありますがこれは常にライト(書き込み)の状態(マザーボード上でGNDに接続)になっています。
本来はLCDユニットへのライトではbusy信号を見ながら作業を行なわなければならないのですが,CPU側で適当に待ちを入れて,タイミングを保ちます。(busy信号を見るように改造した例もある)
H8から見たPort3のbit
LCDユニット(SC1602)の信号
0
DataBus4(DB4)
1
DataBus5(DB5)
2
DataBus6(DB6)
3
DataBus7(DB7)
4
RegisterSelect(RS)
5
EnableSignal(ES)
6
not used
7
not used
4.LCDユニットの受け付ける命令(instruction
set)
以下の表に示す命令中,(1)〜(6)までと,(10)を使用します。
データ幅が上位4ビットなので,起動時には(5)(6)しか使えません。起動時の初期設定で(6)のDB4(DL)を用いて4ビット動作に切り替えます。切り替え後は8ビットのデータを「上位4ビット」「下位4ビット」の順に分けて「上位4ビット」の通路を通してデータの送信が出来ます。
CPUからLCDユニットへ命令を与えるには次のようにします。
LCDユニットに「RSとDB4〜DB7」を与えておいて,「ES」を0→1に立ち上げると,そのときの「RSとDB4〜DB7」の信号をLCDユニットは信号を受け取ります。
「RS=0」の状態での書き込みはLCDユニットへの制御コード送信となり,「RS=1」の状態での書き込みは表示文字コードの送信となります。
instruction set
5.LCDユニットの初期化手順
初期化は以下のように行なわれます。ただし,LCDユニットの表示機能の設定は一例です。
表示機能設定
「4ビット通信」「デューティ1/16」「キャラクタサイズ5*7」「カーソルOFF」「ブリンク(カーソルの点滅)OFF」「書き込み後自動カーソル右移動」「表示シフトOFF」
(1)15msec待ちます
(2)「4.(6)ファンクションセット」を設定します。
以下DB7,DB6,DB5,DB4の設定で,RS=0のまま,ES:0→1→0と変化させます。 「4.(6)」を設定します。
この作業は電源投入時の不安定さ解消のため,時間待ちをはさみ全部で3回行ないます。
ここでは8ビット送信のままなので,接続されていないDB3,DB2,DB1,DB0は無効なデータをLCDユニットが取得している。
DB7 |
DB6 |
DB5 |
DB4 |
0 |
0 |
1 |
1 |
(3)4.1ms待ちます
(4)2回目の「4.(6)ファンクションセット」を設定します。作業内容は(2)と同じです。
(5)100μs待ちます
(6)3回目の「4.(6)ファンクションセット」を設定します。作業内容は(2)と同じです。
(7)4ビット通信に変更します。以下の設定で,RS=0のまま,ES:0→1→0と変化させます。「4.(6)」を設定します。
ここでは8ビット送信のままなので,接続されていないDB3,DB2,DB1,DB0は無効なデータをLCDユニットが取得している。
DB7 |
DB6 |
DB5 |
DB4 |
0 |
0 |
1 |
0 |
(8)「4.(6)」を設定します。「4ビット通信」「デューティ1/16」「キャラクタサイズ5*7」
RS=0のまま4ビットずつ区切って送信する関数を使って,以下のデータを送信します。
DB7 |
DB6 |
DB5 |
DB4 |
DB3 |
DB2 |
DB1 |
DB0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
(9)「4.(4)」を設定します。「表示ON」「カーソルOFF」「ブリンク(カーソルの点滅)OFF」
RS=0のまま4ビットずつ区切って送信する関数を使って,以下のデータを送信します。
DB7 |
DB6 |
DB5 |
DB4 |
DB3 |
DB2 |
DB1 |
DB0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
(10)「4.(3)」を設定します。「書き込み後自動カーソル右移動」「表示シフトOFF」
RS=0のまま4ビットずつ区切って送信する関数を使って,以下のデータを送信します。
DB7 |
DB6 |
DB5 |
DB4 |
DB3 |
DB2 |
DB1 |
DB0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
(11)「4.(1)」の命令を用いて全表示クリアします。
RS=0のまま4ビットずつ区切って送信する関数を使って,以下のデータを送信します。
DB7 |
DB6 |
DB5 |
DB4 |
DB3 |
DB2 |
DB1 |
DB0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
(12)1.64ms待つ
6.LCDユニット制御用関数群を収めたヘッダファイルlcd_ctrl.h
ここでは,単純化のために,ヘッダファイルにしてありますが,実用化する場合はCソース+ヘッダの形にしたほうがよいでしょう。
なお時間稼ぎ関数「msecwait」「microsecwait」はCPUクロック,コンパイラの最適化オプションにより,多少のwait時間が変化するため,システムにあわせて書き直しが必要な場合がある。
ヘッダファイルlcd_ctrl.h
/*****************************************************************
lcd_ctrl.h
LCD control function 2Sep2002 KOSAKA
AKI-H8のport3に接続されたLCDのドライバ関数群を定義するヘッダファイル
このファイルがインクルードされる前に3048f.hまたはこれを含んだヘッダ
がインクルードされている必要があります。(インクルード順に注意)
提供する関数
(1)LCDの初期化
void initLCD( void )
(2)LCDに向けた putchar()
void LCDputchar(char data)
(3)LCDに向けた puts()
void LCDputs(char *str)
(4)LCDに向けた gotoxy()
void LCDgotoxy(unsigned x,unsigned y)
(5)LCDに向けた clrscr() clear screen
void LCDclrscr(void)
(6)LCDに向けた byte の Hex 表示
void LCDputByteHex(char data)
(7)LCDに向けた short int の Hex 表示
void LCDputShortIntHex(short int data)
(8)LCDに向けた long int の Hex 表示
void LCDputLongIntHex(long int data)
*****************************************************************/
/*#include <3048f.h>*//* Port3 -> LCD */
/* 7 6 5 4 3 2 1 0 */
/* ES RS DB7 DB6 DB5 DB4 *//* i/o */
#define init_LCD_Port() P3.DDR = 0xff
#define LCD_Port P3.DR.BYTE
#define LCD_RegisterSelect P3.DR.BIT.B4
#define LCD_EnableSignal P3.DR.BIT.B5static void msecwait(unsigned int msec)
/*msec間なにもしない時間稼ぎ関数*/
{
int i;
long int j;
for (i=0;i<msec;i++) {
for (j=0;j<33300;j++); /*33300は実測によって求めた値*/
}
}static void microsecwait(unsigned int microsec)
{/*だいたいmicrosec間なにもしない時間稼ぎ関数*/
int i;
long int j;
for (i=0;i<microsec;i++) {
for (j=0;j<34;j++); /*34は実測によって求めた値*/
}
}static void LCDputCommand(char command) /*command width must be 4bits*/
{
LCD_Port=(LCD_Port&0xf0)|command;
LCD_EnableSignal=1;
microsecwait(40);
LCD_EnableSignal=0;
microsecwait(40);
}static void LCDputCommand2(char command2)
{
LCDputCommand((command2>>4)&0xf);
LCDputCommand(command2&0xf);
}/************************************************************
LCDに向けた putchar()
************************************************************/
void LCDputchar(char data)
{
LCD_RegisterSelect=1;
LCDputCommand((data>>4)&0xf);
LCDputCommand(data&0xf);
LCD_RegisterSelect=0;
}/************************************************************
LCDに向けた puts()
************************************************************/
void LCDputs(char *str)
{
while(*str) LCDputchar(*str++);
}/************************************************************
LCDの初期化
************************************************************/
void initLCD( void )
{
init_LCD_Port(); /* output */
LCD_Port=0;
msecwait(15); /* wait 15ms */
LCDputCommand(0x3); /* function set */
microsecwait(4100);
LCDputCommand(0x3); /* function set */
microsecwait(100);
LCDputCommand(0x3); /* function set */
LCDputCommand(0x2); /* function set data width=4bit*/
LCDputCommand2(0x28); /* function set 4bit duty:1/16,size:5*7 */
LCDputCommand2(0x0c); /* display on,cursor off,blink off */
LCDputCommand2(0x06); /* address:auto increment,cursor shift:right */
LCDputCommand2(0x01); /* clear display */
microsecwait(1640);
}/************************************************************
LCDに向けた gotoxy()
************************************************************/void LCDgotoxy(unsigned x,unsigned y)
{
unsigned char point;
point=0x80+x+0x40*y;
LCDputCommand2(point);
}/************************************************************
LCDに向けた clrscr() clear screen
************************************************************/
void LCDclrscr(void)
{
LCDputCommand2(0x01); /* clear display */
microsecwait(1640);
}static char hexnumeric[]="0123456789abcdef";
/************************************************************
LCDに向けた byte の Hex 表示
************************************************************/
void LCDputByteHex(char data)
{
LCDputchar(hexnumeric[(data>>4)&0xf]);
LCDputchar(hexnumeric[data&0xf]);
}/************************************************************
LCDに向けた short int の Hex 表示
************************************************************/
void LCDputShortIntHex(short int data)
{
LCDputByteHex((data>>8)&0xff);
LCDputByteHex(data&0xff);
}/************************************************************
LCDに向けた long int の Hex 表示
************************************************************/
void LCDputLongIntHex(long int data)
{
LCDputShortIntHex((data>>16)&0xffff);
LCDputShortIntHex(data&0xffff);
}
7.「lcd_ctrl.h」を用いたテストmain
「lcd_ctrl.h」を用いたテストmain
/* lcd_test.c */
/* LCD control function 2Sep2002 KOSAKA */#include "3048f.h"
#include "h8_3048.h"
#include "lcd_ctrl.h"main( void )
{
char *teststr[2]={"Hello world!","Hello mates!"};
int flipflop=0;
long int counter;initLed(); /*LED初期化*/
initLCD();
LCDgotoxy(0,0);LCDputs(teststr[0]);
LCDgotoxy(0,1);LCDputs(teststr[1]);
while(1) {/*これは無限ループ*/
turnOnLed(0); /*LED0のON*/
turnOffLed(1); /*LED1のOFF*/
msecwait(500);/*500msecの間なにもしない*/
turnOnLed(1); /*LED0のOFF*/
turnOffLed(0); /*LED1のON*/
msecwait(500);
LCDclrscr();
LCDgotoxy(0,0);LCDputs(teststr[flipflop]);
LCDgotoxy(0,1);LCDputLongIntHex(counter);
counter++;
flipflop=1-flipflop;
}
}
参考 LCD PIN Connection (LCDモジュールについている14本のピンの説明)
No Symbol Function 1 VDD 5V 2 VSS GND 3 V0 Contrast Adjust 4 RS Register Select 5 R/W Read/Write 6 E Enable Signal 7 DB0 Data Bit 0 8 DB1 Data Bit 1 9 DB2 Data Bit 2 10 DB3 Data Bit 3 11 DB4 Data Bit 4 12 DB5 Data Bit 5 13 DB6 Data Bit 6 14 DB7 Data Bit 7