Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 562 lines (512 sloc) 19.2 KB
;***********************************************************
;*
;* LCDDriver.asm - V2.0
;*
;* Contains the neccessary functions to display text to a
;* 2 x 16 character LCD Display. Additional functions
;* include a conversion routine from an unsigned 8-bit
;* binary number to and ASCII text string.
;*
;* Version 2.0 - Added support for accessing the LCD
;* Display via the serial port. See version 1.0 for
;* accessing a memory mapped LCD display.
;*
;***********************************************************
;*
;* Author: David Zier
;* Date: March 17, 2003
;* Company: TekBots(TM), Oregon State University - EECS
;* Version: 2.0
;*
;***********************************************************
;* Rev Date Name Description
;*----------------------------------------------------------
;* - 8/20/02 Zier Initial Creation of Version 1.0
;* A 3/7/03 Zier V2.0 - Updated for USART LCD
;*
;*
;***********************************************************
;***********************************************************
;* Internal Register Definitions and Constants
;* NOTE: A register MUST be named 'mpr' in the Main Code
;* It is recomended to use register r16.
;* WARNING: Register r17-r22 are reserved and cannot be
;* renamed outside of the LCD Driver functions. Doing
;* so will damage the functionality of the LCD Driver
;***********************************************************
.def wait = r17 ; Wait Loop Register
.def count = r18 ; Character Counter
.def line = r19 ; Line Select Register
.def type = r20 ; LCD data type: Command or Text
.def q = r21 ; Quotient for div10
.def r = r22 ; Remander for div10
.equ LCDLine1 = $80 ; LCD Line 1 select command
.equ LCDLine2 = $c0 ; LCD Line 2 select command
.equ LCDClear = $01 ; LCD Clear Command
.equ LCDHome = $02 ; LCD Set Cursor Home Command
.equ LCDPulse = $08 ; LCD Pulse signal, used to simulate
; write signal
.equ LCDCmd = $00 ; Constant used to write a command
.equ LCDTxt = $01 ; Constant used to write a text character
.equ LCDMaxCnt = 16 ; Maximum number of characters per line
.equ LCDLn1Addr = $0100 ; Beginning address for Line 1 data
.equ LCDLn2Addr = $0110 ; Beginning address for Line 2 data
;-----------------------------------------------------------
;***********************************************************
;* Public LCD Driver Suboutines and Functions
;* These functions and subroutines can be called safely
;* from within any program
;***********************************************************
;-----------------------------------------------------------
;*******************************************************
;* SubRt: LCDInit
;* Desc: Initialize the Serial Port and the Hitachi
;* Display 8 Bit inc DD-RAM
;* Pointer with no features
;* - 2 LInes with 16 characters
;*******************************************************
LCDInit:
push mpr ; Save the state of machine
in mpr, SREG ; Save the SREG
push mpr ;
push wait ; Save wait
; Setup the Communication Ports
; Port B: Output
; Port D: Input w/ internal pullup resistors
; Port F: Output on Pin 3
ldi mpr, $00 ; Initialize Port B for outputs
out PORTB, mpr ; Port B outputs high
ldi mpr, $ff ; except for any overrides
out DDRB, mpr ;
ldi mpr, $00 ; Initialize Port D for inputs
out PORTD, mpr ; with Tri-State
ldi mpr, $00 ; except for any overrides
out DDRD, mpr ;
ldi mpr, $00 ; Initialize Port F Pin 3 to
sts PORTF, mpr ; output inorder to twiddle the
ldi mpr, (1<<DDF3) ; LCD interface
sts DDRF, mpr ; Must NOT override this port
; Setup the Serial Functionality
; SPI Type: Master
; SPI Clock Rate: 2*1000.000 kHz
; SPI Clock Phase: Cycle Half
; SPI Clock Polarity: Low
; SPI Data Order: MSB First
ldi mpr, (1<<SPE|1<<MSTR)
out SPCR, mpr ; Set Serial Port Control Register
ldi mpr, (1<<SPI2X)
out SPSR, mpr ; Set Serial Port Status Register
; Setup External SRAM configuration
; $0460 - $7FFF / $8000 - $FFFF
; Lower page wait state(s): None
; Uppoer page wait state(s): 2r/w
ldi mpr, (1<<SRE) ;
out MCUCR, mpr ; Initialize MCUCR
ldi mpr, (1<<SRL2|1<<SRW11)
sts XMCRA, mpr ; Initialize XMCRA
ldi mpr, (1<<XMBK) ;
sts XMCRB, mpr ; Initialize XMCRB
; Initialize USART0
; Communication Parameter: 8 bit, 1 stop, No Parity
; USART0 Rx: On
; USART0 Tx: On
; USART0 Mode: Asynchronous
; USART0 Baudrate: 9600
ldi mpr, $00 ;
out UCSR0A, mpr ; Init UCSR0A
ldi mpr, (1<<RXEN0|1<<TXEN0)
out UCSR0B, mpr ; Init UCSR0B
ldi mpr, (1<<UCSZ01|1<<UCSZ00)
sts UCSR0C, mpr ; Init UCSR0C
ldi mpr, $00 ;
sts UBRR0H, mpr ; Init UBRR0H
ldi mpr, $67 ;
out UBRR0L, mpr ; Init UBRR0L
; Initialize the LCD Display
ldi mpr, 6 ;
LCDINIT_L1:
ldi wait, 250 ; 15ms of Display
rcall LCDWait ; Bootup wait
dec mpr ;
brne LCDINIT_L1 ;
ldi mpr, $38 ; Display Mode set
rcall LCDWriteCmd ;
ldi mpr, $08 ; Display Off
rcall LCDWriteCmd ;
ldi mpr, $01 ; Display Clear
rcall LCDWriteCmd ;
ldi mpr, $06 ; Entry mode set
rcall LCDWriteCmd ;
ldi mpr, $0c ; Display on
rcall LCDWriteCmd ;
rcall LCDClr ; Clear display
pop wait ; Restore wait
pop mpr ; Restore SREG
out SREG, mpr ;
pop mpr ; Restore mpr
ret ; Return from subroutine
;*******************************************************
;* Func: LCDWrite
;* Desc: Generic Write Function that writes both lines
;* of text out to the LCD
;* - Line 1 data is in address space $0100-$010F
;* - Line 2 data is in address space $0110-$010F
;*******************************************************
LCDWrite:
rcall LCDWrLn1 ; Write Line 1
rcall LCDWrLn2 ; Write Line 2
ret ; Return from function
;*******************************************************
;* Func: LCDWrLn1
;* Desc: This function will write the first line of
;* data to the first line of the LCD Display
;*******************************************************
LCDWrLn1:
push mpr ; Save mpr
push ZL ; Save Z pointer
push ZH ;
push count ; Save the count register
push line ; Save the line register
ldi ZL, low(LCDLn1Addr)
ldi ZH, high(LCDLn1Addr)
ldi line, LCDLine1 ; Set LCD line to Line 1
rcall LCDSetLine ; Restart at the beginning of line 1
rcall LCDWriteLine ; Write the line of text
pop line
pop count ; Restore the counter
pop ZH ; Restore Z pointer
pop ZL ;
pop mpr ; Restore mpr
ret ; Return from function
;*******************************************************
;* Func: LCDWrLn2
;* Desc: This function will write the second line of
;* data to the second line of the LCD Display
;*******************************************************
LCDWrLn2:
push mpr ; Save mpr
push ZL ; Save Z pointer
push ZH ;
push count ; Save the count register
push line ; Save the line register
ldi ZL, low(LCDLn2Addr)
ldi ZH, high(LCDLn2Addr)
ldi line, LCDLine2 ; Set LCD line to Line 2
rcall LCDSetLine ; Restart at the beginning of line 2
rcall LCDWriteLine ; Write the line of text
pop line
pop count ; Restore the counter
pop ZH ; Restore Z pointer
pop ZL ;
pop mpr ; Restore mpr
ret ; Return from function
;*******************************************************
;* Func: LCDClr
;* Desc: Generic Clear Subroutine that clears both
;* lines of the LCD and Data Memory storage area
;*******************************************************
LCDClr:
rcall LCDClrLn1 ; Clear Line 1
rcall LCDClrLn2 ; Clear Line 2
ret ; Return from Subroutine
;*******************************************************
;* Func: LCDClrLn1
;* Desc: This subroutine will clear the first line of
;* the data and the first line of the LCD Display
;*******************************************************
LCDClrLn1:
push mpr ; Save mpr
push line ; Save line register
push count ; Save the count register
push ZL ; Save Z pointer
push ZH ;
ldi line, LCDline1 ; Set Access to Line 1 of LCD
rcall LCDSetLine ; Set Z pointer to address of line 1 data
ldi ZL, low(LCDLn1Addr)
ldi ZH, high(LCDLn1Addr)
rcall LCDClrLine ; Call the Clear Line function
pop ZH ; Restore Z pointer
pop ZL ;
pop count ; Restore the count register
pop line ; Restore line register
pop mpr ; Restore mpr
ret ; Return from Subroutine
;*******************************************************
;* Func: LCDClrLn2
;* Desc: This subroutine will clear the second line of
;* the data and the second line of the LCD Display
;*******************************************************
LCDClrLn2:
push mpr ; Save mpr
push line ; Save line register
push count ; Save the count register
push ZL ; Save Z pointer
push ZH ;
ldi line, LCDline2 ; Set Access to Line 2 of LCD
rcall LCDSetLine ; Set Z pointer to address of line 2 data
ldi ZL, low(LCDLn2Addr)
ldi ZH, high(LCDLn2Addr)
rcall LCDClrLine ; Call the Clear Line function
pop ZH ; Restore Z pointer
pop ZL ;
pop count ; Restore the count register
pop line ; Restore line register
pop mpr ; Restore mpr
ret ; Return from Subroutine
;*******************************************************
;* Func: LCDWriteByte
;* Desc: This is a complex and low level function that
;* allows any program to write any ASCII character
;* (Byte) anywhere in the LCD Display. There
;* are several things that need to be initialized
;* before this function is called:
;* count - Holds the index value of the line to where
;* the char is written, 0-15(39). i.e. if
;* count has the value of 3, then the char is
;* going to be written to the third element of
;* the line.
;* line - Holds the line number that the char is going
;* to be written to, (1 or 2).
;* mpr - Contains the value of the ASCII character to
;* be written (0-255)
;*********************************************************
LCDWriteByte:
push mpr ; Save the mpr
push line ; Save the line
push count ; Save the count
; Preform sanity checks on count and line
cpi count, 40 ; Make sure count is within range
brsh LCDWriteByte_3 ; Do nothing and exit function
cpi line, 1 ; If (line == 1)
brne LCDWriteByte_1 ;
ldi line, LCDLine1 ; Load line 1 base LCD Address
rjmp LCDWriteByte_2 ; Continue on with function
LCDWriteByte_1:
cpi line, 2 ; If (line == 2)
brne LCDWriteByte_3 ; Do nothing and exit function
ldi line, LCDLine2 ; Load line 2 base LCD Address
LCDWriteByte_2: ; Write char to LCD
add line, count ; Set the correct LCD address
rcall LCDSetLine ; Set the line address to LCD
rcall LCDWriteChar ; Write Char to LCD Display
LCDWriteByte_3: ; Exit Function
pop count ; Restore the count
pop line ; Restore the line
pop mpr ; Restore the mpr
ret ; Return from function
;*******************************************************
;* Func: Bin2ASCII
;* Desc: Converts a binary number into an ASCII
;* text string equivalent.
;* - The binary number needs to be in the mpr
;* - The Start Address of where the text will
;* be placed needs to be in the X Register
;* - The count of the characters created are
;* added to the count register
;*******************************************************
Bin2ASCII:
push mpr ; save mpr
push r ; save r
push q ; save q
push XH ; save X-pointer
push XL ;
; Determine the range of mpr
cpi mpr, 100 ; is mpr >= 100
brlo B2A_1 ; goto next check
ldi count, 3 ; Three chars are written
adiw XL, 3 ; Increment X 3 address spaces
rjmp B2A_3 ; Continue with program
B2A_1: cpi mpr, 10 ; is mpr >= 10
brlo B2A_2 ; Continue with program
ldi count, 2 ; Two chars are written
adiw XL, 2 ; Increment X 2 address spaces
rjmp B2A_3 ; Continue with program
B2A_2: adiw XL, 1 ; Increment X 1 address space
ldi count, 1 ; One char is written
B2A_3: ;Do-While statement that converts Binary to ASCII
rcall div10 ; Call the div10 function
ldi mpr, '0' ; Set the base ASCII integer value
add mpr, r ; Create the ASCII integer value
st -X, mpr ; Load ASCII value to memory
mov mpr, q ; Set mpr to quotiant value
cpi mpr, 0 ; does mpr == 0
brne B2A_3 ; do while (mpr != 0)
pop XL ; restore X-pointer
pop XH ;
pop q ; restore q
pop r ; restore r
pop mpr ; restore mpr
ret ; return from function
;-------------------------------------------------------
;*******************************************************
;* Private LCD Driver Functions and Subroutines
;* NOTE: It is not recommended to call these functions
;* or subroutines, only call the Public ones.
;*******************************************************
;-------------------------------------------------------
;*******************************************************
;* Func: LCDSetLine
;* Desc: Change line to be written to
;*******************************************************
LCDSetLine:
push mpr ; Save mpr
mov mpr,line ; Copy Command Data to mpr
rcall LCDWriteCmd ; Write the Command
pop mpr ; Restore the mpr
ret ; Return from function
;*******************************************************
;* Func: LCDClrLine
;* Desc: Manually clears a single line within an LCD
;* Display and Data Memory by writing 16
;* consecutive ASCII spaces $20 to both the LCD
;* and the memory. The line to be cleared must
;* first be set in the LCD and the Z pointer is
;* pointing the first element in Data Memory
;*******************************************************
LCDClrLine:
ldi mpr, ' ' ; The space char to be written
ldi count, LCDMaxCnt; The character count
LCDClrLine_1:
st Z+, mpr ; Clear data memory element
rcall LCDWriteChar ; Clear LCD memory element
dec count ; Decrement the count
brne LCDClrLine_1 ; Continue untill all elements are cleared
ret ; Return from function
;*******************************************************
;* Func: LCDWriteLine
;* Desc: Writes a line of text to the LCD Display.
;* This routine takes a data element pointed to
;* by the Z-pointer and copies it to the LCD
;* Display for the duration of the line. The
;* line the Z-pointer must be set prior to the
;* function call.
;*******************************************************
LCDWriteLine:
ldi count, LCDMaxCnt; The character count
LCDWriteLine_1:
ld mpr, Z+ ; Get the data element
rcall LCDWriteChar ; Write element to LCD Display
dec count ; Decrement the count
brne LCDWriteLine_1 ; Continue untill all elements are written
ret ; Return from function
;*******************************************************
;* Func: LCDWriteCmd
;* Desc: Write command that is in the mpr to LCD
;*******************************************************
LCDWriteCmd:
push type ; Save type register
push wait ; Save wait register
ldi type, LCDCmd ; Set type to Command data
rcall LCDWriteData ; Write data to LCD
push mpr ; Save mpr register
ldi mpr, 2 ; Wait approx. 4.1 ms
LCDWC_L1:
ldi wait, 205 ; Wait 2050 us
rcall LCDWait ;
dec mpr ; The wait loop cont.
brne LCDWC_L1 ;
pop mpr ; Restore mpr
pop wait ; Restore wait register
pop type ; Restore type register
ret ; Return from function
;*******************************************************
;* Func: LCDWriteChar
;* Desc: Write character data that is in the mpr
;*******************************************************
LCDWriteChar:
push type ; Save type register
push wait ; Save the wait register
ldi type, LCDTxt ; Set type to Text data
rcall LCDWriteData ; Write data to LCD
ldi wait, 16 ; Delay 160 us
rcall LCDWait ;
pop wait ; Restore wait register
pop type ; Restore type register
ret ; Return from function
;*******************************************************
;* Func: LCDWriteData
;* Desc: Write data or command to LCD
;*******************************************************
LCDWriteData:
out SPDR, type ; Send type to SP
ldi wait, 2 ; Wait 2 us
rcall LCDWait ; Call Wait function
out SPDR,mpr ; Send data to serial port
ldi wait, 2 ; Wait 2 us
rcall LCDWait ; Call Wait function
ldi wait, LCDPulse ; Use wait temporarially to
sts PORTF, wait ; to send write pulse to LCD
ldi wait, $00 ;
sts PORTF, wait ;
ret ; Return from function
;*******************************************************
;* Func: LCDWait
;* Desc: A wait loop that is 10 + 159*wait cycles or
;* roughly wait*10us. Just initialize wait
;* for the specific amount of time in 10us
;* intervals.
;*******************************************************
LCDWait:push mpr ; Save mpr
LCDW_L1:ldi mpr, $49 ; Load with a 10us value
LCDW_L2:dec mpr ; Inner Wait Loop
brne LCDW_L2
dec wait ; Outer Wait Loop
brne LCDW_L1
pop mpr ; Restore mpr
ret ; Return from Wait Function
;*******************************************************
;* Bin2ASCII routines that can be used as a psuedo-
;* printf function to convert an 8-bit binary
;* number into the unigned decimal ASCII text
;*******************************************************
;***********************************************************
;* Func: div10
;* Desc: Divides the value in the mpr by 10 and
;* puts the remander in the 'r' register and
;* and the quotiant in the 'q' register.
;* DO NOT modify this function, trust me, it does
;* divide by 10 :) ~DZ
;***********************************************************
div10:
push r0 ; Save register
; q = mpr / 10 = mpr * 0.000110011001101b
mov q, mpr ; q = mpr * 1.0b
lsr q ; q >> 2
lsr q ; q = mpr * 0.01b
add q, mpr ; q = (q + mpr) >> 1
lsr q ; q = mpr * 0.101b
add q, mpr ; q = (q + mpr) >> 3
lsr q
lsr q
lsr q ; q = mpr * 0.001101b
add q, mpr ; q = (q + mpr) >> 1
lsr q ; q = mpr * 0.1001101b
add q, mpr ; q = (q + mpr) >> 3
lsr q
lsr q
lsr q ; q = mpr * 0.0011001101b
add q, mpr ; q = (q + mpr) >> 1
lsr q ; q = mpr * 0.10011001101b
add q, mpr ; q = (q + mpr) >> 4
lsr q
lsr q
lsr q
lsr q ; q = mpr * 0.000110011001101b
; compute the remainder as r = i - 10 * q
; calculate r = q * 10 = q * 1010b
mov r, q ; r = q * 1
lsl r ; r << 2
lsl r ; r = q * 100b
add r, q ; r = (r + q) << 1
lsl r ; r = q * 1010b
mov r0, r ; r0 = 10 * q
mov r, mpr ; r = mpr
sub r, r0 ; r = mpr - 10 * q
; Fix any errors that occur
div10_1:cpi r, 10 ; Compare with 10
brlo div10_2 ; do nothing if r < 10
inc q ; fix qoutient
subi r, 10 ; fix remainder
rjmp div10_1 ; Continue until error is corrected
div10_2:pop r0 ; Restore registers
ret ; Return from function
Jump to Line
Something went wrong with that request. Please try again.