LCD serial terminal


Closed Thread
Results 1 to 5 of 5
  1. #1
    Join Date
    Aug 2003
    Posts
    985

    Default LCD serial terminal

    Hi Guys

    This was pretty easy to share since it’s literally the schematic out of the manual, except 20 MHz clock, and has a serial input.

    I was looking for a simple serial terminal display project, even though a character LCD would be hopeless for a lot of applications,
    I wanted something simple, just to show some data is coming in.
    This is specifically intended for monitoring APRS packet data (Amateur Radio), but could easily be adapted to something else.

    It receives up to 60 bytes for a line, and is currently terminated with line feed 0x0A. This could be changed to return 0x0D.
    The first 20 characters are printed to LCD, and subsequent lines push the top line down (with no line wrapping).

    LCD graphics demo code is used for the intro, which is pixel based (not just rolling odometer effect), was done in 2013,
    and adjusted to work with this. A lot of functionality from the original demo code is removed to suit this program.

    Fancy Intro:


    Serial terminal - video made prior to intro being finished:


    Name:  LCD_Terminal_Schema.jpg
Views: 1578
Size:  109.8 KB

  2. #2
    Join Date
    Aug 2003
    Posts
    985


    Did you find this post helpful? Yes | No

    Default Re: LCD serial terminal

    and some code.
    16F628A with MCLR disabled, 20 MHz clock, and watchdog time left on.

    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
    '
    '
    ‘

  3. #3
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,793


    Did you find this post helpful? Yes | No

    Default Re: LCD serial terminal

    Nice work Brek! Especially with the effects!

    Ioannis

  4. #4
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default Re: LCD serial terminal

    Art (Brek?),
    This thread caught my attention enough to look at your YT page. Lots of impressive stuff there! I definitely have to spend more time looking at your ideas. Thanks for putting it out there.

    The videos in this thread don't seem to come up. Can I get a pointer to where they are so I can see them? I suspect I have a use for a simple serial display, and I'd like to see how you did it.

    Thanks
    bo

  5. #5
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default Re: LCD serial terminal

    After thinking about it, that was just silly. I'll just throw it together and see it for myself. I already know I have uses for it.

Similar Threads

  1. Using a parallel LCD(44780 based) as a serial LCD
    By mikejp56 in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 30th October 2015, 02:56
  2. Terminal Programme
    By Adrian in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 18th December 2007, 18:15
  3. Parallel LCD to Serial LCD
    By Mostafa in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 17th June 2007, 22:14
  4. parallel LCD to serial LCD
    By maxbao in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 28th October 2006, 12:44
  5. to convert LCD // hd 44780 --> serial LCD
    By in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 15th March 2003, 13:37

Members who have read this thread : 2

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts