Code:
'
' Dumb LCD Terminal - Brek Martin 2020
'
DEFINE OSC 20 '20 MHz oscillator
DEFINE NO_CLRWDT 1 'tell compiler not to insert clrwdt instructions
DEFINE HSER_RCSTA 90h 'enable hardware serial receiver
DEFINE HSER_TXSTA 24h 'at least one bit in this register must be set
DEFINE HSER_SPBRG 129 'set SPBRG directly 9600 baud 20 MHz clock
DEFINE HSER_CLROERR 1 'auto clear serial buffer overflow errors
DEFINE LCD_DATAUS 49 'lcd module timing
DEFINE LCD_COMMANDUS 1850 '
'
DATA 142,145,145,143,129,130,140,128 '9 graphic digits roll stored horizontal
DATA 142,145,147,149,153,145,142,128 '0
DATA 132,140,132,132,132,132,142,128 '1
DATA 142,145,129,130,132,136,159,128 '2
DATA 159,130,132,130,129,145,142,128 '3
DATA 130,134,138,146,159,130,130,128 '4
DATA 159,144,158,129,129,145,142,128 '5
DATA 134,136,144,158,145,145,142,128 '6
DATA 159,129,130,132,136,136,136,128 '7
DATA 142,145,145,142,145,145,142,128 '8
DATA 142,145,145,143,129,130,140,128 '9
DATA 142,145,147,149,153,145,142,128 '0
DATA " DISPLAY TERMINAL VK4FAST 2020" 'program credit in spare eeprom space
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''
' DO NOT DECLARE ANY PROGRAM VARIABLES HERE! '
' PRIVATE PROPERTY - KEEP OUT OF MY CODESPACE! '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
serrec var byte[61] ' serial buffer also used as pixel buffer 24x17
rolls var byte [8] ' LCD RAM buffers
rolls0 var rolls[0] : rolls1 var rolls[1] '
rolls2 var rolls[2] : rolls3 var rolls[3] '
rolls4 var rolls[4] : rolls5 var rolls[5] '
rolls6 var rolls[6] : rolls7 var rolls[7] '
L0 var byte ' LCD RAM index and used as counter
CW var byte : CL var byte ' multi purpose counters
lind var byte : pind var byte ' framebuffer indexing variables
slug var byte : invert var byte ' set invert 0xFF to invert display
wtemp var word '
temp var wtemp.byte0 '
tempb var wtemp.byte1 '
px var byte : py var byte ' coordinates for library routines
''''''''''''''''''''''''''''''''''''''''''''''''''''' end graphics memory private property
' terminal program variables
serincnt var byte 'serial input rotate counter
inputbyte var byte 'serial input byte
larray var byte[40] 'display character array
lcdcnt var byte 'lcd character counter
sercnt var byte 'serial input character counter
' graphic demo variables
cx var byte ' shared with square drawing routine
cy var byte '
glc_x var byte '
glc_y var byte '
glc_s var word ' slope
radius var byte ' radius
cdx var byte ' circle demo horizontal coordinate
' rolling odometer effect variables
digit var byte 'buffer for printing sprites
doff var byte 'digit odometer effect variables
doffl var byte '
doffm var byte '
xdoffl var byte '
xdoffm var byte '
dcompl var byte '
dcompm var byte '
xdcompl var byte'
xdcompm var byte'
demd var byte 'actual digits on the screen
xdemd var byte 'another two digits on the screen
demdl var byte '
dval var byte 'value for printed variable
dgx var byte 'coordinates to print sprite
dgy var byte '
index var byte 'eeprom index for sprite data
dfc var byte 'digit frame counter
yfix var byte 'dynamic circle radius
qualify var bit '
demo var byte 'circles or digits flag
speed var byte 'odometer effect speed
acount var byte 'another counter
'
pause 16 'startup delay
CMCON = 7 'set ports to digital
trisb = %00000010 'set direction
trisa = %00000000 'set direction
porta = $00 'default states
portb = $00 'default states
gosub delayb '
gosub cleararrays '
lcdout $FE,$01 'clear display
inputbyte = $FF 'used as counter for the intro demo
invert = $FF 'set inverted graphics display mode
dfc = 0 'reset digit frame counter
cdx = 11 'set initial circle position
yfix = 7 'set initial circle radius
demd = 75 'rolling odometer display value
xdemd = 19 'first two year digits
dcompm = $FF '
dcompl = $FF '
xdcompm = $FF '
xdcompl = $FF '
doff = 0 'may break things if not initialised
speed = 1 'set speed
dgy = $F7 'initial digits position off screen
'
'******************* demo section *********************
demo = 0 'circles demo flag value
while inputbyte > 204
@ clrwdt
cx = cdx : cy = 8 'trick to use the entire display
radius = yfix
gosub drawcircle
cx = cdx + 24
gosub drawcircle
cdx = cdx - 1
if cdx = 242 then 'check bounds for moving circle demos
cdx = 10 '
endif '
gosub writecg 'write the frame buffer to LCD
inputbyte = inputbyte - 1
pause 1
if inputbyte = 204 then
invert = 0
endif
wend
'
'
'
' " VK4FAST 2020 " - template for rolling odometer intro
gosub cleararrays '
lcdout $FE,$01 'clear display
lcdout $FE,$80
gosub printfourspaces
acount = 116
while acount < 124
read acount,digit
lcdout digit
acount = acount + 1
wend
gosub printfourspaces
gosub printfourspaces
inputbyte = $FF '
yfix = 1 'used as a delay value here
demo = 2 'invisible until start digits appear
while inputbyte > 1 'draw rolling odometer effect digits
dval = demd /10 'example of drawing sprites
demdl = demd 'data is stored horizontal
demdl = demdl - (dval * 10)
if dval != dcompm then
dcompm = dval
doffm = 8
endif
doff = doffm
if doffm > 0 then
doffm = doffm - 1
else
demo = 1 'activate rolling odometer effect
endif
dgx = 12
gosub printdigit
if demdl != dcompl then
dcompl = demdl
doffl = 8
endif
doff = doffl
if doffl > 0 then
doffl = doffl - speed
else
inputbyte = inputbyte - 1
endif
dval = demdl
dgx = 18
gosub printdigit
if demd = 0 then ' change first two year digits
xdemd = 20
endif
dval = xdemd /10 'two more digits for year
demdl = xdemd 'data is stored horizontal
demdl = demdl - (dval * 10)
if dval != xdcompm then
xdcompm = dval
xdoffm = 8
endif
doff = xdoffm
if xdoffm > 0 then
xdoffm = xdoffm - 1
else
demo = 1 'activate rolling odometer effect
endif
dgx = 0
gosub printdigit
if demdl != xdcompl then
xdcompl = demdl
xdoffl = 8
endif
doff = xdoffl
if xdoffl > 0 then
xdoffl = xdoffl - 1
endif
dval = demdl
dgx = 6
gosub printdigit
gosub writecg 'write the frame buffer to LCD
@ clrwdt
if demd = 21 then 'quit this section at the year 2020
inputbyte = 0 '
endif '
dfc = dfc + 1 'increment digit roll counter
if dfc > 7 then '
dfc = 0 '
demd = demd + 1 'increment counter for display variable
if dgy != 0 then 'slide year down for start of intro
dgy = dgy + 1
endif
endif '
if demd > 99 then 'keep display variable in two digit range
demd = 0 '
endif '
wend
inputbyte = $FF 'graphics mode has ended
'*******************************************************
'
'
'
'program intro section
lcdout $FE,$C0
acount = 96 ' "DISPLAY TERMINAL"
while acount < 116
read acount,digit
lcdout digit
acount = acount + 1
wend
gosub delays
lcdout $FE,$C2,"WAITING FOR DATA"
gosub cleararrays
'
'
'
HSERIN 1,nodatw,[inputbyte]'clear buffer
nodatw:
HSERIN 0,nodatx,[inputbyte]'clear buffer
nodatx:
HSERIN 0,nodaty,[inputbyte]'clear buffer
nodaty:
if inputbyte != $FF then ' ignore the first packet if incomplete
@ clrwdt
inputbyte = $FF
goto nodatw
endif
'
'
'
cycle: 'main program loop
@ clrwdt
HSERIN 0,cycle,[inputbyte]' hardware serial receive
if sercnt < 60 then 'rotate character into input array if received
for serincnt = 60 to 1 step - 1 '
serrec[serincnt] = serrec[serincnt-1]
next serincnt '
serrec[0] = inputbyte '
sercnt = sercnt + 1 'increment input character counter
endif '
'qualify line termination for data received from serial port
if inputbyte = $0a then ' check for enter character received - or $0d for line feed
gosub scrollprint
inputbyte = 0
endif
nodat: 'timeout label for no character received
goto cycle
'
'
'
scrollprint: 'scroll old line down and print to display top line
acount = 0
while acount < 20
larray[acount+20] = larray[acount]
acount = acount + 1
wend
lcdout $FE,$C0 'set second line position
lcdcnt = 0
while lcdcnt < 20 'print old data to second line
lcdout larray[lcdcnt+20]
lcdcnt = lcdcnt + 1
wend
lcdout $FE,$80 'set first line position
lcdcnt = 0
if sercnt > 0 then
sercnt = sercnt - 1
endif
while lcdcnt < 20 'print new data to first line
lcdout serrec[sercnt-lcdcnt]
larray[lcdcnt] = serrec[sercnt-lcdcnt]
lcdcnt = lcdcnt + 1
wend
@ clrwdt
gosub checkfortime 'extract data
sercnt = 0
return
'
'
'
'lcd character display graphics originally by Brek Martin 2013
drawcircle: ' draw circle to screen
cx = cx - (7-yfix) 'moved here for optimisation
glc_x = 0
glc_y = radius
glc_s = 2-2*radius
while (glc_x <= glc_y)
px = glc_x+cx : py=glc_y+cy
gosub setpixel
px = cx-glc_x : py=glc_y+cy
gosub setpixel
px = cx+glc_x : py=cy-glc_y
gosub setpixel
px = cx-glc_x : py=cy-glc_y
gosub setpixel
px = glc_y+cx : py=glc_x+cy
gosub setpixel
px = cx-glc_y : py=cy+glc_x
gosub setpixel
px = cx+glc_y : py=cy-glc_x
gosub setpixel
px = cx-glc_y : py=cy-glc_x
gosub setpixel
if (glc_s.15 =1) then
glc_s = glc_s + (4*glc_x + 6)
else
glc_s = glc_s + (4*(glc_x-glc_y) + 10)
glc_y = glc_y - 1
endif
glc_x = glc_x + 1
wend
return
'
setpixel: ' size and performance win for V2
lind = py * 3 ' byte index for line
pind = 0
slug = px
IF px > 7 THEN
pind = 1
slug = px - 8
ENDIF
IF px > 15 THEN
pind = pind + 1
slug = px - 16
ENDIF
IF lind+pind < 51 THEN ' range check
temp = serrec[lind+pind]
FOR CW = 0 TO 7
IF slug = CW THEN
temp.bit7 = 1
ENDIF
wtemp = wtemp << 1
NEXT CW
serrec[lind+pind] = tempb
ENDIF
return
'
writecg: ' size, ram and performance win for V2
L0 = $40 ' reset lines
FOR CL = 0 TO 7 ' write first half of display
FOR CW = 0 TO 3
rolls[CW] = (serrec[0] ^ invert) >> 3
gosub Rotate
NEXT CW
gosub lcdgfxchunk
NEXT CL
FOR CW = 0 TO 23 ' skip invisible line
gosub RotateDisplay
NEXT CW
'
if demo = 0 then 'not for rolling odometer
L0 = $60 ' reset lines
FOR CL = 0 TO 7 ' write second half of display
FOR CW = 0 TO 3
rolls[CW] = (serrec[0] ^ invert) >> 3
gosub Rotate
NEXT CW
gosub lcdgfxchunk
NEXT CL
' draw to LCD
LCDOUT $FE,$80 'draw first line of display
FOR CL = 0 TO 4
LCDOUT 0,1,2,3 '
NEXT CL
LCDOUT $FE,$C0 'draw second line of display
FOR CL = 0 TO 4
LCDOUT 4,5,6,7 '
NEXT CL
endif
if demo = 1 then ' digits on one display area only
LCDOUT $FE,($80+12) 'draw first line of display
LCDOUT 0,1,2,3
endif
return
'
Rotate: ' the only assembler routine
gosub rota ' needed for speed
rota: ' by neglecting to carry the
gosub RotateDisplay ' status bit, it also clears
gosub RotateDisplay ' the buffer for the next frame
RotateDisplay: ' bitwise rotate array right
@ rlf _serrec+50 ,F ; ditching the first bit
@ rlf _serrec+49 ,F ;
@ rlf _serrec+48 ,F ;
@ rlf _serrec+47 ,F ;
@ rlf _serrec+46 ,F ;
@ rlf _serrec+45 ,F ;
@ rlf _serrec+44 ,F ;
@ rlf _serrec+43 ,F ;
@ rlf _serrec+42 ,F ;
@ rlf _serrec+41 ,F ;
@ rlf _serrec+40 ,F ;
@ rlf _serrec+39 ,F ;
@ rlf _serrec+38 ,F ;
@ rlf _serrec+37 ,F ;
@ rlf _serrec+36 ,F ;
@ rlf _serrec+35 ,F ;
@ rlf _serrec+34 ,F ;
@ rlf _serrec+33 ,F ;
@ rlf _serrec+32 ,F ;
@ rlf _serrec+31 ,F ;
@ rlf _serrec+30 ,F ;
@ rlf _serrec+29 ,F ;
@ rlf _serrec+28 ,F ;
@ rlf _serrec+27 ,F ;
@ rlf _serrec+26 ,F ;
@ rlf _serrec+25 ,F ;
@ rlf _serrec+24 ,F ;
@ rlf _serrec+23 ,F ;
@ rlf _serrec+22 ,F ;
@ rlf _serrec+21 ,F ;
@ rlf _serrec+20 ,F ;
@ rlf _serrec+19 ,F ;
@ rlf _serrec+18 ,F ;
@ rlf _serrec+17 ,F ;
@ rlf _serrec+16 ,F ;
@ rlf _serrec+15 ,F ;
@ rlf _serrec+14 ,F ;
@ rlf _serrec+13 ,F ;
@ rlf _serrec+12 ,F ;
@ rlf _serrec+11 ,F ;
@ rlf _serrec+10 ,F ;
@ rlf _serrec+9 ,F ;
@ rlf _serrec+8 ,F ;
@ rlf _serrec+7 ,F ;
@ rlf _serrec+6 ,F ;
@ rlf _serrec+5 ,F ;
@ rlf _serrec+4 ,F ;
@ rlf _serrec+3 ,F ;
@ rlf _serrec+2 ,F ;
@ rlf _serrec+1 ,F ;
@ rlf _serrec+0 ,F ;
@ bcf _serrec+50 ,0 ;clear MSB
return
'
'
'
printdigit: 'print a single graphic digit to screen
index = dval * 8' set the index position for digit
FOR L0 = 0 TO 6
read (index-doff)+8,digit 'rolling odometer data
FOR CL = 0 TO 4
IF digit.bit4 = 1 THEN
px = dgx+CL
py = dgy+L0
gosub setpixel
ENDIF
digit = digit << 1
NEXT CL
index = index + 1
NEXT L0
return
'
'
'
cleararrays:
sercnt = 0 ' reset to use as a counter
while sercnt < 61
serrec[sercnt] = 0 'clear serial receive buffer
if sercnt < 40 then 'clear both display buffer lines
larray[sercnt] = $20
endif
sercnt = sercnt + 1
wend
sercnt = 0
return
'
'
'
printfourspaces:
lcdout " "
return
'
'
'
lcdgfxchunk: ' program memory optimisation
LCDOUT $FE,L0+$00,rolls[0]
LCDOUT $FE,L0+$08,rolls[1]
LCDOUT $FE,L0+$10,rolls[2]
LCDOUT $FE,L0+$18,rolls[3]
L0 = L0 + 1
return
'
'
'
delays:
@ clrwdt
pause 660
delayb:
@ clrwdt
pause 660
@ clrwdt
pause 660
@ clrwdt
return
'
'
'
checkfortime:
qualify = 0 : digit = 0
acount = sercnt 'used as a counter here
while acount > 8
acount = acount - 1
if serrec[acount] = ":" && serrec[acount-1] = "@" then
digit = acount-4 : acount = 0
endif
wend
'
if digit > 0 then
if serrec[digit-3] < $3A then 'extra sanity check
if serrec[digit-3] > $2F then '
if serrec[digit] < $33 then
lcdout $FE,$C0 'set second line position
gosub printfourspaces
lcdout "TIME: " 'start of time display line
'convert to local time here
cx = serrec[digit] - $30 'get real values
cy = serrec[digit-1] - $30 '
cx = cx * 10 'move to msd
cx = cx + cy 'cx should be true value now
cx = cx + 10 'convert to local eastern time
if cx > 23 then 'fix possible overflow
cx = cx - 24 '
endif '
cy = cx/10 'split digits and convert back to ascii
serrec[digit] = cy + $30 'most significant hour digit restored
cx = cx - (cy*10) '
serrec[digit-1] = cx + $30 'least significant hour digit restored
'
lcdout serrec[digit],serrec[digit-1],":",serrec[digit-2],serrec[digit-3]," " ' use z for zulu if not local time
gosub printfourspaces
endif
endif
endif
endif
return
'
'
‘
Bookmarks