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.B5

static 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