PICでキャラクタ液晶制御

前々からやってみたかったキャラクLCDの制御をPICでやってみました。

Cコンパイラを使えばライブラリが用意されているので簡単にLCDの制御ができますが、今回はアセンブラで書いたので少し面倒でした。
"はじめてのPICアセンブラ入門(CQ出版)"で制御の手順が解説されているのでそれを見ながら作っていきました。
使用PICはPIC16F887。通信は4ビット×2
無事"Hello World!"の表示ができました。

	list		p=16f887	; list directive to define processor
	#include	<p16f887.inc>	; processor specific variable definitions

	__CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
	__CONFIG    _CONFIG2, _WRT_OFF & _BOR21V

#define lcdRS PORTE,0
#define lcdRW PORTE,1
#define lcdE PORTE,2
#define lcdPort PORTB

tm1 equ 0x20
tm2 equ 0x21
lcdData equ 0x22
lcdWrite4temp equ 0x23
lcdReadReg equ 0x24

;**********************************************************************
	ORG     0x000             	; processor reset vector

	nop
  	goto    main          		; go to beginning of program

main
	bcf	STATUS,RP0		;bank0
	bcf	STATUS,RP1

	clrf INTCON

	bcf STATUS,RP1
	bsf	STATUS,RP0		;bank1

	clrf TRISA
	clrf TRISB
	clrf TRISC
	clrf TRISD
	clrf TRISE

	bsf STATUS,RP1
	bsf	STATUS,RP0		;bank3

	clrf ANSEL
	clrf ANSELH

	bcf	STATUS,RP0		;bank0
	bcf STATUS,RP1

	clrf PORTA
	clrf PORTB
	clrf PORTC
	clrf PORTD
	clrf PORTE

	call clearAllReg

	call lcdInit

	goto mainLoop

clearAllReg
	clrf tm1
	clrf tm2
	clrf lcdData
	clrf lcdWrite4temp
	clrf lcdReadReg

	return

mainLoop
	call lcdBusyCheck

	movlw 'H'
	movwf lcdData
	call lcdWriteData

	movlw 'e'
	movwf lcdData
	call lcdWriteData

	movlw 'l'
	movwf lcdData
	call lcdWriteData

	movlw 'l'
	movwf lcdData
	call lcdWriteData

	movlw 'o'
	movwf lcdData
	call lcdWriteData

	movlw ' '
	movwf lcdData
	call lcdWriteData

	movlw 'W'
	movwf lcdData
	call lcdWriteData

	movlw 'o'
	movwf lcdData
	call lcdWriteData

	movlw 'r'
	movwf lcdData
	call lcdWriteData
	movlw 'l'
	movwf lcdData
	call lcdWriteData

	movlw 'd'
	movwf lcdData
	call lcdWriteData

	movlw '!'
	movwf lcdData
	call lcdWriteData

	bsf PORTD,0

	goto breakLoop

breakLoop
	nop

	goto breakLoop

lcdInit
	bcf lcdE
	bcf lcdRW
	bcf lcdRS

	call wait_10ms
	call wait_10ms

	movlw b'00000011'
	movwf lcdPort
	call lcdWrite

	call wait_10ms

	movlw b'00000011'
	movwf lcdPort
	call lcdWrite

	call wait_10ms

	movlw b'00000011'
	movwf lcdPort
	call lcdWrite

	call wait_10ms

	movlw b'00000010'
	movwf lcdPort
	call lcdWrite

	call wait_10ms

	movlw 0x2C
	movwf lcdData
	call lcdWriteCmdNoBusyCheck

	movlw 0x08
	movwf lcdData
	call lcdWriteCmd

	movlw 0x0F
	movwf lcdData
	call lcdWriteCmd

	movlw 0x06
	movwf lcdData
	call lcdWriteCmd

	call lcdClear

	return

lcdWriteData
	call lcdBusyCheck
	bsf lcdRS

	goto lcdWrite4
	

lcdWriteCmdNoBusyCheck
	bcf lcdRS

	goto lcdWrite4

lcdWriteCmd
	call lcdBusyCheck
	bcf lcdRS

	goto lcdWrite4

lcdWrite4
	;上位ビット
	movfw lcdData
	andlw b'11110000'		;lcdDataの上位ビットのみwに保持=xxxx0000
	movwf lcdWrite4temp
	swapf lcdWrite4temp,f		;lcdDataの上位ビットがlcdWrite4tempの下位ビットに入ってる=0000xxxx
	movfw lcdWrite4temp		;lcdWrite4tempをwへ
	movwf lcdPort			;上位ビット書き込み
	bsf lcdE			;送信
	bcf lcdE

	;下位ビット
	movfw lcdData
	andlw b'00001111'		;lcdDataの下位ビットのみwに保持=0000xxxx
	movwf lcdPort			;下位ビット書き込み
	bsf lcdE			;送信
	bcf lcdE
	
	return

lcdWrite
	bsf lcdE			;送信
	bcf lcdE

	return

lcdBusyCheck
	bcf STATUS,RP1
	bsf	STATUS,RP0		;bank1

	movlw b'00001111'		;LCDのデータポートだけ入力に設定
	movwf TRISB

	bcf STATUS,RP1
	bcf	STATUS,RP0		;bank0

	bcf lcdRS			;busy読み込み指定
	bsf lcdRW

;lcdBusyCheckに続けて書くこと
lcdBusyMain
	call lcdRead
	btfsc lcdReadReg,7
	goto lcdBusyMain

	bcf lcdRW

	bcf STATUS,RP1
	bsf	STATUS,RP0		;bank1

	clrf TRISB

	bcf STATUS,RP1
	bcf	STATUS,RP0		;bank0

	return

lcdRead
	clrf lcdReadReg

	;上位ビット
	bsf lcdE
	movfw lcdPort			;液晶からの上位ビットがwの下位ビットに入る=0000xxxx
	movwf lcdReadReg
	swapf lcdReadReg,f		;液晶からの上位ビットがlcdReadRegの上位ビットに入る=xxxx0000
	bcf lcdE

	;下位ビット
	bsf lcdE
	movfw lcdPort			;液晶からの下位ビットがwの下位ビットに入る=0000xxxx
	iorwf lcdReadReg,f		;lcdReadRegと論理和=xxxxxxxx
	bcf lcdE

	return

lcdClear
	movlw 01H			;clear command
	movwf lcdData
	call lcdWriteCmd

	return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;10ms待機
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
wait_10ms
	movlw d'70'
	movwf tm1

wait_10ms_sub
	decfsz tm1,f
	goto wait_10ms_loop
	return

wait_10ms_loop
	movlw d'237'
	movwf tm2
	decfsz tm2,f
	goto $-1
	goto wait_10ms_sub
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	END                       ; directive 'end of program'