2-1, LCD表示器の使い方
とりあえずメータとしての体裁をとるためには何らかの表示器がいるわけだが、やっぱりLCDがハッタリ的によいでしょう、ということでLCDを採用するこ とにした。部品自体は結構安価で売っている。今回用いたLCDはSC1602BSLBという型番の16文字x2行のものだ。秋月で買うとついてくる紙切れ 一枚の取説にいろいろ制御方法が載っているわけだが、素人にははっきり言ってちんぷんかんぷんだった。なのでまた困ったときのネットだよりというわけで、 いろいろリサーチしたところ、汎用に使えるプログラム(サブルーチン)を入手できた。
参照したページは
NAO TECHNOHUT
「電子工作の実験室」のこのページ
で、例によって試験基板を作成してテストすることにした。作成した回路は4ビットパラレル接続で、PICのポートを節約することにした。


タイマーサブルーチンを使えるようにする
ところで参考にしたページでは10MHzでの動作を前提にしていたのだが、手持ちのオシレータは20MHzしかない。LCD表示はある程度正確なタイミン グ取りが要求されるらしいので、ここでタイマーサブルーチンの使い方をLED試験基板を用いてマスターしておくことにした。
参照したページは
工作の実験室のこのページ
20MHzってことは1秒間に20000000回振動しているわけで1クロックあたりは1/20000000s=50nsなんだがPICの動作単位である 1サイクルは4クロックで動作しているらしく、つまり1サイクル=200nsということになる。10MHzなら倍の400nsということ。で、たとえば1 秒間のインターバルを作りたいときは1秒間メインの計算をやめて適当な作業を繰り返すことで時間をつぶしてもらうことになる。1サイクルの作業を繰り返す なら1s/200ns=5000000ってことで500万回適当な作業で時間をつぶせばよいということになる。これをプログラム的に実現するには以下のよ うにする。
50usのサブルーチンを作る→50usのサブルーチンをループして10msのサブルーチンを作る→10msのサブルーチンをループして1sのサブルーチ ンを作る、といった具合。なお命令によっては2サイクル消費するものもあるので、ぴったりのサイクル数を作るのは案外難しいが、そもそもセラロックのク ロック動作の精度が大して高くないので、その辺は適当でいいかもしれない。(まあ念のため多少余裕を持ったウエイトをとっておけばよいだろう)


LCD表示サブルーチン
で、実際に作成したサブルーチンを以下に示す。
作成したといっても実際にいじくったのはタイマーサブルーチン部分だけで、その他の部分はほぼパクりであるが。


	LIST		P=PIC16F84
	INCLUDE		"P16F84.INC"
;************************************
;設定
;************************************
DPDT	EQU	0DH		;LCDに表示するデータおよびコマンド格納
CNT1	EQU	0EH		;タイマー用カウンタ1
CNT2	EQU	0FH		;タイマー用カウンタ2
CNT3	EQU	010H		;タイマー用カウンタ3
CNT4	EQU	011H		;タイマー用カウンタ4

;************************************
;LCDサブルーチン
;************************************
;**** LCD command out *****
 LCD_CMD
	MOVWF	DPDT		;Commandデータの一時保存
	ANDLW	0F0H		;上位4ビットをまず出力
	MOVWF	PORTB		;RB4-7のデータバスへ出力
	BCF	PORTA,1		;R/Wを0にセット Command条件セット
	BCF	PORTA,2		;RSを0にセット
	BSF	PORTA,0		;E high ストローブ信号出力
	BCF	PORTA,0		;E low
	SWAPF	DPDT,W		;
	ANDLW	0F0H		;下位4ビットを出力
	MOVWF	PORTB		;RB4-7へ出力
	BSF	PORTA,0		;ストローブ信号出力
	BCF	PORTA,0
	CALL	LCD_BUSY	;Busy信号が無くなるまで待つ
	RETURN
;	
;**** LCD Data Write ****
LCD_DATA
	MOVWF	DPDT		;表示データ(ASCII)の一時保存
	ANDLW	0F0H		;上位4ビット転送
	MOVWF	PORTB
	BCF	PORTA,1		;R/Wを0にセット、データ送信モードセット
	BSF	PORTA,2		;RSを1にセット
	BSF	PORTA,0		;E high ストローブ信号出力
	BCF	PORTA,0		;E low
	SWAPF	DPDT,W		;get data lower
	ANDLW	0F0H		;下位4ビットの転送
	MOVWF	PORTB
	BSF	PORTA,0		;ストローブ信号出力
	BCF	PORTA,0
	CALL	LCD_BUSY	;Busy信号が無くなるまで待つ
	RETURN
;
;**** LCD Busy Check ************
LCD_BUSY
	CLRF	DPDT		;データバッファクリア
	BSF	STATUS,RP0	;PICモード変更のためBank1へ切替え
	BSF	OPTION_REG,7	;ポートBのプルアップをOFF指定
	MOVLW	0FEH		;PORTBRB0以外を入力モードにセット
	MOVWF	TRISB
	BCF	STATUS,RP0	;Bank 0へ戻す
	BCF	PORTA,2		;RSを0にセット
	BSF	PORTA,1		;R/Wを1にセット Busy入力モードをセット
	BSF	PORTA,0		;E high ストローブ信号出力
	MOVF	PORTB,W		;データを2回に分けて入力
	BCF	PORTA,0		;E low
	ANDLW	0F0H		;まず上位4ビットを入力
	MOVWF	DPDT		;一時保存
	BSF	PORTA,0		;E high 次のストローブ信号出力
	MOVF	PORTB,W		;下位4ビットを入力
	BCF	PORTA,0		;E low
	ANDLW	0FH		;Mask out upper
	IORWF	DPDT,F		;上位と下位をORで合併
	BTFSC	DPDT,7		;BUSY FLAGビットをチェック
	GOTO	LCD_BUSY	;Busy状態だったら再度入力繰り返し
;
	BCF	PORTA,1		;R/Wを0に戻す(出力モードに戻す)
	BSF	STATUS,RP0	;PICのモード変更のためBank 1へ切替え
	MOVLW	0EH		;RB1,2,3 以外は出力へ戻す
	MOVWF	TRISB		;PORTBモードセット
	BCF	STATUS,RP0	;Bank 0へ戻す
	RETURN 
; 
;**** Initialize *****
LCD_INI
	CALL	TIME5M		;15msec以上待つ(5msec3回待ちにしている)
	CALL	TIME5M
	CALL	TIME5M
	MOVLW	030H		;8ビットモード設定制御
	MOVWF	PORTB
	BCF	PORTA,1		;R/W 0セット
	BCF	PORTA,2		;RS 0セット
	BSF	PORTA,0		;E high ストローブ
	BCF	PORTA,0		;E low
	CALL	TIME5M		;4.1msec以上待つ(5msec待ち)
	MOVLW	030H		;再度8ビットモード設定制御 
	MOVWF	PORTB
	BCF	PORTA,1		;R/W 0セット
	BCF	PORTA,2		;RS 0セット
	BSF	PORTA,0		;E high ストローブ
	BCF	PORTA,0		;E low
	CALL	TIME02M		;100usec以上待つ(200usec待ち)
	MOVLW	030H		;再々度8ビットモード設定制御
	MOVWF	PORTB
	BCF	PORTA,1		;R/W 0セット
	BCF	PORTA,2		;RS 0セット
	BSF	PORTA,0		;ストローブ
	BCF	PORTA,0
	CALL	TIME02M		;念のため200usec待ち
	MOVLW	020H		;4ビットモード設定制御
	MOVWF	PORTB		;(この時はまだ8ビットモード)
	BCF	PORTA,1		;R/W 0セット
	BCF	PORTA,2		;RS 0セット
	BSF	PORTA,0		;ストローブ
	BCF	PORTA,0
	CALL	TIME02M		;念のため200usec待ち
;以降4ビットモードで動作かつBusyFlag有効
	MOVLW	02CH		;Function Set(2行、5x10Dot表示指定)
	CALL	LCD_CMD
	MOVLW	08H		;Display off (Cursor,Blinkなし)
	CALL	LCD_CMD
	MOVLW	0CH		;Display on (Cursor,Blinkなし)
	CALL	LCD_CMD
	MOVLW	06H		;Entry Mode Set(Increment,表示シフト指定)
	CALL	LCD_CMD
	RETURN
;
;タイマーサブルーチン20MHzオシレータの場合
;
;0.2msec
TIME02M
	MOVLW	0F9H		;249回
	MOVWF	CNT1		;ここまでで2サイクル
TIMLP1	NOP			;1
	DECFSZ	CNT1,F		;1
	GOTO	TIMLP1		;2 ここまでで2+4*249-1=997
	RETURN			;2 997+2=999 999*0.2usec=0.2msec
;5msec
TIME5M
	MOVLW	019H		;25回 
	MOVWF	CNT2		;ここまでで2サイクル
TIMLP2
	CALL	TIME02M		;2+999
	DECFSZ	CNT2,F		;1
	GOTO	TIMLP2		;2 2+1004*25-1=25101
	RETURN			;2 25101+2=25103
;50msec
TIME50M	MOVLW	0F9H		;249回 
	MOVWF	CNT3		;ここまでで2サイクル
TIMLP3	CALL	TIME02M		;2+999
	DECFSZ	CNT3,F		;1
	GOTO	TIMLP3		;2 2+1004*249-1=249997
	RETURN			;2 249997+2=249999
;1sec
TIME1S	MOVLW	014H		;20回
	MOVWF	CNT4		;50msec * 20
TIMLP4	CALL	TIME50M
	DECFSZ	CNT4,F		;このループは50msec
	GOTO	TIMLP4
	RETURN
	  

これに表示する内容等のメインルーチンを次のように作成してPICに書き込んで動作試験したところ、1発で表示に成功した。すばらしい。


;メインルーチン
	org	0		;reset
;ポート初期化
	BSF	STATUS,RP0	;バンク1へ切替
	CLRF	TRISA		;ポートAを出力モードに設定
	CLRF	TRISB		;ポートBを出力モードに設定
	BCF	STATUS,RP0	;バンク0に戻す
	MOVLW	00H		;初期出力
	MOVWF	PORTA
	MOVLW	00H		;初期出力
	MOVWF	PORTB
;LCD初期化
	CALL	LCD_INI
;文字列の表示
LCD_ON	MOVLW	'A'		;ascii文字データをWレジスタに保存
	CALL	LCD_DATA	;そのデータを描画
	CALL	TIME50M		;waitを入れることで文字が順にタイプされていく
	MOVLW	'R'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'E'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	' '
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'Y'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'O'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'U'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	' '
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'R'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'E'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'A'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'D'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'Y'
	CALL	LCD_DATA
	CALL	TIME50M
	MOVLW	'?'
	CALL	LCD_DATA
LOOP	GOTO	LOOP		;無限ループで動作停止
      

表示内容に深い意味はない
アセンブラソース(MPLAB用)はここにおいておく。


とりあえずこのプログラムの勘所は以下のとおり
基本的には

PICポートの設定 = ポートA,B両方を出力に設定
LCDの初期化 = LCD_INIサブルーチンをCALLする
表示アドレスを指定 = wレジスタにアドレスを読み込みLCD_CMDで指定
文字列の表示コマンド = Wレジスタを介してLCD_DATAサブルーチンで出力

という流れである。
ポート設定は実際にはRA0-2 RB4-7をLCD表示に使っているのでほかのポートはあとで入力にしても良い
表示アドレスはSC1602BSLBの場合下の表の16進数をMOVLWで読み込んでLCD_CMDをCALLすれば良い。アドレスを指定しないと直前に表示した文字の右隣に並ぶので文字列を表示する時は先頭の文字のアドレスだけを指定すれば良い。例えば2行目の左から3文字目から表示したければ
	MOVLW	0C2H
	CALL	LCD_CMD
とすれば良い
LCDアドレス
表示させる文字は' 'でくくったASCII文字を直接MOVLWすればアセンブラが2進数に変換してくれるようだ。ただしこの場合大文字しか表示できない。小文字や、記号等は秋月データシートに記載されている16進数をhigher-4bit lower-4bitの順に組み合わせてMOVLWで読み込めば表示できる。例えば温度記号℃を表示したければ
	MOVLW	0DFH
	CALL	LCD_DATA
	MOVLW	043H
	CALL	LCD_DATA
とすればよい。
Character code
Back  Menu  Next

[DIY home]