STRING2LCD Program
Build this using Code Warrior and the ee3376 Stationery .
;****************************************************************
;*
;* UTEP EE3376
;* string2lcd_hcs12.asm
;* Dragon12/HCS12 board, Code Warrior v3
;* 4 Dec 03
;*
;* This lab demonstrates the basic initialization and use
;* of a Hantronix LCD (Model HDM16216L-5) on the Dragon12 HCS12 board.
;* This is a 16 char x 2 line LCD with a 5x7 dots character format.
;* Uses a HD44780 based controller. The Dragon12 LCD is hardwired to use
;* a 4-bit interface to Port K with pins set up as follows:
;*
;* RS = PK0 (Port K bit 0 to RS Register Selector)
;* -> RS = 0 selects Instruction Register, RS=1 selects Data Register
;* EN = PK1 (Enable; pulse enable to latch data-write into LCD)
;* R/W = connected to ground (W = 0 since we only write)
;* DB4 = PK2; DB5 = PK3; DB6 = PK4; DB7 = PK5
;* PK6 and PK7 are unused
;*
;* The program is based on using strings to write to each line of the LCD.
;* The final display will show string1 'Code Warrior' on line 1
;* and string2 'Dragon12' on line 2. You can modify the strings manually
;* in the program itself or in DBug12 using the 'mm' command.
;*
;****************************************************************
; export symbols
XDEF Entry ; export 'Entry' symbol
ABSENTRY Entry ; for absolute assembly: mark this as application entry point
PSEUDO_ROM EQU $1000 ; absolute address to place code/constant data
RAM EQU $1400 ; absolute address to place variables
STACK EQU $3C00 ; top of stack
; registers
portk EQU $32 ;
portk_ddr EQU $33 ; data direction register for Port K
; masks
enable EQU %00000010 ; enable bit for enable on/off pulses
output EQU %11111111 ; make a port an output
; constants
msec EQU $1770 ; 6000 (=$1770) loops = 1 msec in startx loop
; LCD initialization strings; msb = most significant bits, lsb = least sig. bits
init_lcd1 EQU $0C ; first init string we write (3 times) to LCD on startup
init_lcd2 EQU $08 ; set to 4 bit transfer (repeat twice)
init_lcd3 EQU $08 ; set to 2 lines, 5x7 dots, 4 msb of 8 bits
init_lcd4 EQU $20 ; set to 2 lines, 5x7 dots, 4 lsb of 8 bits
init_lcd5 EQU $00 ; display off, 4 msb
init_lcd6 EQU $20 ; display off, 4 lsb
init_lcd7 EQU $00 ; display clear, 4 msb
init_lcd8 EQU $04 ; display clear, 4 lsb
init_lcd9 EQU $00 ; entry mode 4 msb
init_lcd10 EQU $18 ; entry mode, 4 lsb (increment DDRAM, cursor moves)
init_lcd11 EQU $00 ; display on, 4 msb
init_lcd12 EQU $3C ; display on, 4 lsb (display on, cursor on, blink on)
init_lcd13 EQU $30 ; display on, 4 lsb (display on, cursor/blink off)
;-----------------------------------------------------
; variable/data section
ORG RAM
string1: dc.b "Code Warrior"
string2: dc.b "Dragon12"
length1: dc.b 12 ; the length of string1
length2: dc.b 8 ; the length of string2
count: ds.b 1 ; buffer to hold length of string
portk_img ds.b 1 ; buffer to hold portk data
;------------------------------------------------------
; code section
ORG PSEUDO_ROM ;set PC to $1000
Entry:
; do some initialization
lds #STACK ; initialize stack pointer
movb #output, portk_ddr ; make Port K an Output
jsr LCD_INIT ; initialize the LCD
; write string1 to the LCD line 1
ldx #string1 ; pointer to string passed via reg X
movb length1, count ; load count buffer with length of string
jsr WRITE_STRING
; set LCD to line 2 at DDRAM address $40, RS=0
movb #$30, portk_img ; RS=0, %1100 to DB7-DB4
jsr ENABLE_PULSE
movb #$00, portk_img ; RS=0, %0000 to DB3-DB0
jsr ENABLE_PULSE
; write string2 to the LCD line 2
ldx #string2 ; pointer to string passed via reg X
movb length2, count ; load count buffer with length of string
jsr WRITE_STRING
; display on, cursor off, blink off; 2 4-bit writes needed
movb #init_lcd11, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
movb #init_lcd13, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
swi ; end the program
;------------------------------------------------------
; Subroutine LCD_INIT to initialize the LCD
; sets LCD to line 1
LCD_INIT: ldd #$14 ; wait 20 msec after power on (need delay > 15 msec)
jsr DELAY
; write first init string three times with various delays
movb #init_lcd1, portk_img
; write 1/delay 1
jsr ENABLE_PULSE ; pulse data in portk to write it
ldd #$05 ; wait 5 msec (need delay > 4.1 msec)
jsr DELAY
; write 2/delay 2
jsr ENABLE_PULSE ; pulse data in portk to write it
ldd #$01 ; wait 1 msec (need delay > 100 usec)
jsr DELAY
; write 3, no delay needed
jsr ENABLE_PULSE ; no delay needed here
; final initialization writes
; wait > 1 msec between each write ( > 40 usec delay needed)
; set to 4 bit transfers; only one 4-bit write needed
movb #init_lcd2, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
; set to 2 lines, 5x7 dot character display; two 4-bit writes needed
movb #init_lcd3, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
movb #init_lcd4, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
; display off; two 4-bit writes needed
movb #init_lcd5, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
movb #init_lcd6, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
; display clear; two 4-bit writes needed
movb #init_lcd7, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
movb #init_lcd8, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
; entry mode = increment, cursor move; two 4-bit writes needed
movb #init_lcd9, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
movb #init_lcd10, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
; display on, cursor on, blink on; two 4-bit writes needed
movb #init_lcd11, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
movb #init_lcd12, portk_img
jsr ENABLE_PULSE
ldd #$01
jsr DELAY
rts
;------------------------------------------------------
; Subroutine WRITE_STRING will write string to current line of LCD
; pass string pointer via reg X
WRITE_STRING:
begin: ldaa 0,x ; 4 msb nibble
ldab 0,x ; 4 lsb nibble
lsra ; center msb nibble
lsra
lslb ; center lsb nibble
lslb
staa portk_img ; write msb nibble
bset portk_img, $01 ; set RS=1
bclr portk_img, $C2 ; clear upper 2 bits and enable bit
jsr ENABLE_PULSE
stab portk_img ; write lsb nibble
bset portk_img, $01 ; set RS=1
bclr portk_img, $C2 ; clear upper 2 bits and enable bit
jsr ENABLE_PULSE
inx
dec count ; continue for count = length of the string
bne begin
rts
;------------------------------------------------------
; Subroutine ENABLE_PULSE
; Used each time a write occurs; portk holds write data
; portk gets write data from buffer portk_img
; Need enable high to latch the write data, then low to clear way for next write
; Need to wait at least 40 usec after enable for function to complete - we
; build this delay into this subroutine
ENABLE_PULSE:
; save A and B on stack since we need them
psha
pshb
movb portk_img, portk
bset portk,enable ; set portk enable bit high
; hold enable high for > 230 ns
; blcr takes 4 cycles before enable bit goes low
; so add a couple NOPs to give 6 cycles total = 240 ns
nop
nop
bclr portk, enable
; functions take at least 40 usec to complete
; so add 1 msec delay before we do next function
ldd #$01
jsr DELAY
; restore A and B
pulb
pula
rts
;------------------------------------------------------
; Subroutine DELAY - Register D contains number of Delay loops
; 1 msec delay per Delay loop
DELAY:
pshx
tfr d,y
starty: ldx #msec
startx: dex
bne startx
dey
bne starty
pulx
rts
;****************************************************************