今回は、LCDキャラクタ・ディスプレーを接続、メッセージを表示したいと思います。
LCDには、Z80でも使用していた、「KKHMF DC 5V 1602 LCD ディスプレイモジュール 16×2キャラクタ LCDブルーブラックライト」 (amazonで購入)を使用しました。
LCDは4bitモードで使用します。また、R/WはWrite(Lowレベル)に固定しました。STC12C2052のP1ポートに接続しましたが、使用していないP1.0及びP1.1は出力設定となっていますので抵抗1Kでプルダウンしています。
書き込み時P1.0及びP1.1をLowレベルに落とさないといけませんので1KΩでのプルダウンとしました。
LCDを接続した回路は次のようになります。

まずポートの設定を行います。PIMO及びP1M1レジスタに設定することで出力タイプ及び入力に設定できます。今回は8051コンパチの設定にしました。
mov P1M0,0b00000000 ;output
mov P1M1,0b00000000 ;P1.0 - P1.7 output
LCDに接続するポートを設定します。
LCD_PORT .equ P1
LCD_RS .equ P1.2
LCD_E .equ P1.3
LCDを初期化します。
lcdinit: ;LCD init(4bit mode)
mov a,#0x03
lcall lcd4bitwrite
mov a,#5 ;5ms delay
lcall delayms
mov a,#0x03
lcall lcd4bitwrite
mov a,#0x03
lcall lcd4bitwrite
mov a,#0x02 ;4bit mode
lcall lcd4bitwrite
mov a,#0x28 ;function set
lcall lcd8bitwrite ;4bit bus, 2 line, 1 line=8
mov a,#0x0c ;disp on,under cursor off,block cursor off
lcall lcd8bitwrite
mov a,#0x01 ;disp clr
lcall lcd8bitwrite
mov a,#02 ;2 ms delay
lcall delayms
mov a,#0x06 ;disp address incrmant on,disp shift off
lcall lcd8bitwrite
mov a,#0x02 ;cursor home set
lcall lcd8bitwrite
mov a,#02 ;2 ms delay
lcall delayms
ret
4ビットモードでの書き込みと8ビット単位での書き込みのサブルーチンをコマンド用及びデータ用に作成します。
lcd8bitwrite: ;command mode 8bit data LCD output
mov r1,a
lcall llcd4bitwrite
mov a,r1
lcall lcd4bitwrite
ret
lcd4bitwrite:
rl a ;command mode 4bit data LCD output
rl a ;4bit data upper 4bit set
rl a
rl a
llcd4bitwrite:
ANL a,#0xf0 ;LCD RS or E Low
mov LCD_PORT,a ;LCD PORT output
lcall delay100us
setb LCD_E ;LCD E Hi
lcall delay100us
clr LCD_E
lcall delay100us
ret
datalcd8bitwrite: ;data mode 8bit data LCD output
mov r1,a
lcall ldatalcd4bitwrite
mov a,r1
lcall datalcd4bitwrite
ret
datalcd4bitwrite:
rl a ;data mode 4bit data LCD output
rl a ;4bit data upper 4bit set
rl a
rl a
ldatalcd4bitwrite:
ANL a,#0xf0 ;LCD RS or E Low
mov LCD_PORT,a ;LCD PORT output
lcall delay100us
setb LCD_RS ;LCD RS Hi
lcall delay100us
setb LCD_E ;LCD E Hi
lcall delay100us
clr LCD_E
lcall delay100us
clr LCD_RS
lcall delay100us
ret
時間稼ぎのdelayルーチンを作成します。100μSの基準となるカウント値をD100Uに設定します。delayルーチンでは R0,R1,R2レジスタを使用しています。
D100U .equ 0x88
delayms: ;a reg ms delay
mov r2,a
delaymloop:
lcall delay1ms
djnz r2,delaymloop
ret
delay1ms:
lcall delay500us
lcall delay500us
ret
delay500us:
mov r1,#0x05
delay500uloop:
lcall delay100us
djnz r1,delay500uloop
ret
delay100us:
mov r0,#D100U
delay1:
djnz r0,delay1
ret
実際のLCDにの表示には、DPTRレジスタに文字列の先頭アドレスを設定し、0x00で終端をチェックしています。
mov DPTR, #lcd_msg
main_msg1_loop:
clr a
movc a,@a+DPTR
jz main_msg2
inc DPTR
lcall datalcd8bitwrite
sjmp main_msg1_loop
main_msg2:
mov a,#0xc0 ;0x80 +0x40(2line top address)
lcall lcd8bitwrite
mov DPTR, #lcd_msg2
main_msg2_loop:
clr a
movc a,@a+DPTR
jz loop
inc DPTR
lcall datalcd8bitwrite
sjmp main_msg2_loop
lcd_msg:
.db 'H
.db 'e
.db 'l
.db 'l
.db 'o
.db '8
.db '0
.db '5
.db '1
.db 0xba ;コ
.db 0xb1 ;ア
.db 'W
.db 'o
.db 'r
.db 'l
.db 'd
.db 0x00
lcd_msg2:
.db 'S
.db 'T
.db 'C
.db '1
.db '2
.db 'C
.db '2
.db '0
.db '5
.db '2
.db 0xc6 ;ニ
.db 0xd3 ;モ
.db 0xb4 ;エ
.db 0xc0 ;タ
.db 0xb2 ;イ
.db '!
.db 0x00
全体的なソフトは次ようようになります。
サブルーチンを多用しているので、スタックポインタの設定と表示後は、無限ロープとなっています。
表示は1行目に Hello8051コアWorld 2行目にSTC12C2052ニモエタイ! と表示されます。
; STC12C2052 LCD Character Display Test Pinecone 2019/11/29
;
; STC12C2052 cpu
; Flash ROM 2Kbyte
; RAM 256byte
; External clock -
;
; assembler
; program start 000H 0000H-07ffH
; main 100H
;
; assemblers ASxxxx and ASlink V5.10
; file name 2052_lcd01.asm
; $ as8051 -l -s -o 2052_lcd01.asm
; $ aslink -i 2052_lcd01
; $ program download stcgl 2052_lcd01.ixh
;
D100U .equ 0x88
LCD_PORT .equ P1
LCD_RS .equ P1.2
LCD_E .equ P1.3
P1M0 .equ 0x91
P1M1 .equ 0x92
.area TEST(ABS)
.org 0x0000
ljmp main
.org 0x0100
main:
mov sp,#0x3f
mov P1M0,0b00000000 ;output
mov P1M1,0b00000000 ;P1.0 - P1.7 output
mov a,#15 ;15ms delay
lcall delayms
lcall lcdinit
mov DPTR, #lcd_msg
main_msg1_loop:
clr a
movc a,@a+DPTR
jz main_msg2
inc DPTR
lcall datalcd8bitwrite
sjmp main_msg1_loop
main_msg2:
mov a,#0xc0 ;0x80 +0x40(2line top address)
lcall lcd8bitwrite
mov DPTR, #lcd_msg2
main_msg2_loop:
clr a
movc a,@a+DPTR
jz loop
inc DPTR
lcall datalcd8bitwrite
sjmp main_msg2_loop
loop: sjmp loop
lcdinit: ;LCD init(4bit mode)
mov a,#0x03
lcall lcd4bitwrite
mov a,#5 ;5ms delay
lcall delayms
mov a,#0x03
lcall lcd4bitwrite
mov a,#0x03
lcall lcd4bitwrite
mov a,#0x02 ;4bit mode
lcall lcd4bitwrite
mov a,#0x28 ;function set
lcall lcd8bitwrite ;4bit bus, 2 line, 1 line=8
mov a,#0x0c ;disp on,under cursor off,block cursor off
lcall lcd8bitwrite
mov a,#0x01 ;disp clr
lcall lcd8bitwrite
mov a,#02 ;2 ms delay
lcall delayms
mov a,#0x06 ;disp address incrmant on,disp shift off
lcall lcd8bitwrite
mov a,#0x02 ;cursor home set
lcall lcd8bitwrite
mov a,#02 ;2 ms delay
lcall delayms
ret
lcd8bitwrite: ;command mode 8bit data LCD output
mov r1,a
lcall llcd4bitwrite
mov a,r1
lcall lcd4bitwrite
ret
lcd4bitwrite:
rl a ;command mode 4bit data LCD output
rl a ;4bit data upper 4bit set
rl a
rl a
llcd4bitwrite:
ANL a,#0xf0 ;LCD RS or E Low
mov LCD_PORT,a ;LCD PORT output
lcall delay100us
setb LCD_E ;LCD E Hi
lcall delay100us
clr LCD_E
lcall delay100us
ret
datalcd8bitwrite: ;data mode 8bit data LCD output
mov r1,a
lcall ldatalcd4bitwrite
mov a,r1
lcall datalcd4bitwrite
ret
datalcd4bitwrite:
rl a ;data mode 4bit data LCD output
rl a ;4bit data upper 4bit set
rl a
rl a
ldatalcd4bitwrite:
ANL a,#0xf0 ;LCD RS or E Low
mov LCD_PORT,a ;LCD PORT output
lcall delay100us
setb LCD_RS ;LCD RS Hi
lcall delay100us
setb LCD_E ;LCD E Hi
lcall delay100us
clr LCD_E
lcall delay100us
clr LCD_RS
lcall delay100us
ret
delayms: ;a reg ms delay
mov r2,a
delaymloop:
lcall delay1ms
djnz r2,delaymloop
ret
delay1ms:
lcall delay500us
lcall delay500us
ret
delay500us:
mov r1,#0x05
delay500uloop:
lcall delay100us
djnz r1,delay500uloop
ret
delay100us:
mov r0,#D100U
delay1:
djnz r0,delay1
ret
lcd_msg:
.db 'H
.db 'e
.db 'l
.db 'l
.db 'o
.db '8
.db '0
.db '5
.db '1
.db 0xba ;コ
.db 0xb1 ;ア
.db 'W
.db 'o
.db 'r
.db 'l
.db 'd
.db 0x00
lcd_msg2:
.db 'S
.db 'T
.db 'C
.db '1
.db '2
.db 'C
.db '2
.db '0
.db '5
.db '2
.db 0xc6 ;ニ
.db 0xd3 ;モ
.db 0xb4 ;エ
.db 0xc0 ;タ
.db 0xb2 ;イ
.db '!
.db 0x00
.end