News:

Let's find out together what makes a PIC Tick!

Main Menu

Positron8 - Serial Alphanumeric LCD Controller

Started by top204, Apr 20, 2024, 07:11 PM

Previous topic - Next topic

top204

There was talk on the forum recently concerning a serial alphanumeric LCD controller available that, In My Opinion, was rather lacking, so I set about knocking up a simple program to show how easy it is to create a serial LCD controller using any PIC device that contains a USART, using the Positon8 BASIC Compiler, and the program listing for the serial controller is shown below:

'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A simple Serial LCD using the USART of the device.
'
' Written for the Positron8 BASIC compiler by Les Johnson.
'
    Device = 16LF1823                                   ' Tell the compiler what device to compile for
    Declare Xtal = 32                                   ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Watchdog = On                               ' Tell the compiler that the watchdog timer is enabled
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600                        ' Set the default Baud rate for the USART
    Declare HRSOut1_Pin = PORTC.4                       ' Tell the compiler what pin to use for the USART TX
    Declare HRSIn1_Pin = PORTC.5                        ' Tell the compiler what pin to use for the USART RX
    Declare Hserial_Clear = On                          ' Enable Error clearing on received bytes
'
' Setup the LCD
'
    Declare LCD_Data4_Pin = PORTC.0                     ' Connect PORTC.0 to the LCD's D4 line
    Declare LCD_Data5_Pin = PORTC.1                     ' Connect PORTC.1 to the LCD's D5 line
    Declare LCD_Data6_Pin = PORTC.2                     ' Connect PORTC.2 to the LCD's D6 line
    Declare LCD_Data7_Pin = PORTC.3                     ' Connect PORTC.3 to the LCD's D7 line
    Declare LCD_ENPin = PORTA.0                         ' Connect PORTA.0 to the LCD's EN line
    Declare LCD_RSPin = PORTA.1                         ' Connect PORTA.1 to the LCD's RS line
    Declare LCD_Interface = 4                           ' Use a 4-line interface to the LCD
    Declare LCD_Lines = 2                               ' Tell the compiler that the LCD has two lines
    Declare LCD_Type = Alphanumeric                     ' Tell the compiler that the LCD is a Hitachi alphanumeric type
    Declare LCD_CommandUs = 2000                        ' Delay for 2000us between sending command bytes to the LCD
    Declare LCD_DataUs = 50                             ' Delay for 50us between sending data bytes to the LCD

$define Baud_Pin PORTA.5                                ' Chooses the Baud rate of the serial LCD (high is 9600 Baud, low is 19200 Baud)
'
' Create some variables
'
    Dim wBaudRate As Word = 9600                        ' Holds the Baud rate
    Dim ByteIn As Byte                                  ' Holds the received byte to send to the LCD

'------------------------------------------------------------------------------------------------
' The main program starts here
' Wait in a loop and send bytes received via the USART directly to the LCD
'
Main:
    Setup()                                             ' Setup the program and any peripherals
    Do                                                  ' Create a loop
        ByteIn = HRSIn, {1024, Continue}                ' Receive a byte serially into ByteIn, with a timeout of approx 1 second
        Print ByteIn                                    ' Send the byte received to the LCD
        BaudCheck()                                     ' Check for a Baud rate change
    Loop                                                ' Do it forever

'------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : PinMode is only available on the devices that can control pull-up resistors on individual pins.
'
Proc Setup()
    Osc_Init()                                          ' Initialise the internal oscillator
    PinMode(wBaudRate, Input_PullUp)                    ' Make the Baud change pin an input with its internal pull-up enabled
    HRSOutLn ""                                         ' Transmit a dummy byte to settle the PPS and the USART
    Cls                                                 ' Clear the LCD's display
    Print At 1, 1, "    Positron    ",                  ' \
          At 2, 1, " Serial LCD 1.0 "                   ' / Transmit a start-up message on the LCD
EndProc

'------------------------------------------------------------------------------------------------
' Check for a change of Baud rate
' Input     : None
' Output    : wBaudRate holds the Baud rate chosen
' Notes     : None
'
Proc BaudCheck()
    If Baud_Pin = 1 Then                                ' Is the Baud pin high?
        If wBaudRate <> 9600 Then                       ' Yes. So is the Baud rate already 9600?
            HSerial1_ChangeBaud(9600)                   ' No. So change the Baud rate of the USART to 9600
            wBaudRate = 9600                            ' Change the Baud rate holding variable to the Baud rate chosen
        EndIf
    Else                                                ' Otherwise... The Baud pin is low
        If wBaudRate <> 19200 Then                      ' So... Is the Baud rate already 19200?
            HSerial1_ChangeBaud(19200)                  ' No. So change the Baud rate of the USART to 19200
            wBaudRate = 19200                           ' Change the Baud rate holding variable to the Baud rate chosen
        EndIf
    EndIf
EndProc

'------------------------------------------------------------------------------------------------
' Initialise the internal oscillator
' Input     : None
' Output    : None
' Notes     : Setup is for a PIC16F1823 device
'
Proc Osc_Init()
    OSCCON = $70                                        ' 8MHz_HF
    OSCTUNE = $00
    BORCON = $00
    Repeat: Clrwdt: Until OSCSTATbits_PLLR = 1          ' Wait for the PLL to stabilise
EndProc

'------------------------------------------------------------------------------------------------
' Setup the config fuses for internal oscillator and 4xPLL enabled on a PIC16F1823 device
' OSC pins are general purpose I/O pins
'
     Config1 FOSC_INTOSC,_                              ' INTOSC oscillator and I/O function on CLKIN pin
             WDTE_ON,_                                  ' WDT enabled
             PWRTE_OFF,_                                ' PWRT disabled
             MCLRE_ON,_                                 ' MCLR/VPP pin function is MCLR
             CP_OFF,_                                   ' Program memory code protection is disabled
             CPD_OFF,_                                  ' Data memory code protection is disabled
             BOREN_ON,_                                 ' Brown-out Reset enabled
             CLKOUTEN_OFF,_                             ' CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
             IESO_ON,_                                  ' Internal/External Switchover mode is enabled
             FCMEN_ON                                   ' Fail-Safe Clock Monitor is enabled

     Config2 WRT_OFF,_                                  ' Flash Memory Write protection off
             PLLEN_ON,_                                 ' 4xPLL enabled
             STVREN_ON,_                                ' Stack Overflow or Underflow will cause a Reset
             BORV_19,_                                  ' Brown-out Reset Voltage (Vbor), low trip point selected
             LVP_OFF                                    ' High-voltage on MCLR/VPP must be used for programming                   

As can be seen, the code is very easy to create using the Positron compiler, and performs perfectly. It acts as if the master device is actually interfaced to the LCD normally and not via a single wire, so whatever is sent via serial, gets transferred directly to the LCD. This means LCD commands can also be sent, such as Clear Display, Position Cursor, Scroll, Create UDGs etc... The compiler caters for commands being sent to the LCD via the Print command by first using the value $FE, then the command. The compiler also has special functions for serial LCD controllers that operate directly, such as HRsout Cls and HRSout At Line, X Position, just like interfacing to the LCD directly using the Print command.

A simple master program is listed below, that communicates with the serial LCD controller and displays a barchart on it using UDGs (User Defined Graphics), and it also shows how text and integer and floating point values can be displayed, as well as cursor positioning and clearing the LCD:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' To test the serial LCD. Transmit to the serial LCD and increment variables and display a bargraph on it.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K20                                   ' Tell the compiler what device to compile for
    Declare Xtal = 16                                   ' Tell the compiler what frequency the device will be operating at (in MHz)
    Declare Float_Display_Type = Fast                   ' Use the faster, more accurate, floating point display library routine
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600                        ' Set the Baud rate for the USART
    Declare HRSOut1_Pin   = PORTC.6                     ' Tell the compiler what pin to use for the USART TX
'
' Create global variables here
'
    Dim MyWord As Word                                  ' Holds the integer value to display
    Dim MyFloat As Float                                ' Holds the floating point value to display

'------------------------------------------------------------------------------------------------
' The main program starts here
' Transmit text, values and a bargraph to the serial LCD
'
Main:
    Setup()                                             ' Setup the program and any peripherals
    Do                                                  ' Create a loop
        HRSOut1 At 1, 1, "Int:", Dec2 MyWord, " ",      ' \ Display the integer and floating point values on line 1 of the LCD
                         "Flt:", Dec1 MyFloat           ' /
        MyWord = MyWord + 1                             ' Increment MyWord
        MyFloat = MyFloat + 0.2                         ' Increment MyFloat by a value of 0.2
        LCD_BarGraph(2, 1, MyWord)                      ' Display the bargraph on line 2 of the LCD
        If MyWord > 48 Then                             ' Has the value reached the maximum for the bargraph?
            HRSOut1 At 2, 1, "                "         ' Yes. So clear line 2 of LCD's display
            MyWord = 0                                  ' Reset MyWord
        EndIf
        DelayMS 100                                     ' Create a delay bewteen value increments (so they can be seen changing on the LCD)
    Loop                                                ' Do it forever

'------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    DelayMS 1000                                        ' Wait for the serial LCD to become stable
    MyWord = 0                                          ' \ Reset the variables
    MyFloat = 0                                         ' /
    HRSOut1 Cls                                         ' Clear the LCD's display
    LCD_CreateIcons()                                   ' Create the bargraph UDGs in the LCD
EndProc

'-------------------------------------------------------------------------------
' A horizontal bar graph is displayed on the LCD that represents a value
' Input     : pLine holds the line on the LCD to draw the bargraph
'           : pXpos holds the X position to start drawing the bargraph
'           : pBarVal holds the length of the bar
' Output    : None
' Notes     : Each character position can represent a maximum value of 3 using the cFullBar character |||.
'             The routine calculates how many full bars to use by dividing by 3.
'             If there is a remainder after dividing by 3, the routine joins on a partial-bar character
'             (| or ||) to represent the balance.
'             Then it pads out the remainder of the bar width with spaces to erase any leftover bars
'
Proc LCD_BarGraph(pLine As Byte, pXpos As Byte, pBarVal As Byte)
    Dim bBars    As Byte                                ' Number of full ||| Bars to draw
    Dim bBalance As Byte                                ' Balance left after all |||s are drawn
    Dim bBalf    As Byte                                ' Chooses if a balance character needed
'
' Create constants for the LCD BarGraph
'
    Symbol cBarWidth = 16                               ' Max width in characters of bar
    Symbol cMaxBar = (cBarWidth * 3)                    ' Max bar counts
    Symbol cFullBar = 3                                 ' ASCII value of ||| bar
    Symbol cBaseBar = 0                                 ' ASCII value of 0 bar (blank)

    If pXpos = 0 Then pXpos = 1                         ' \
    If pBarVal > cMaxBar Then pBarVal = cMaxBar         ' / Check boundaries
    bBars = pBarVal / 3                                 ' One full bar for each 3 graph units
    bBalance = pBarVal // 3                             ' bBalance is the remainder after a division by 3
    bBalf = bBalance
    If bBalf > 1 Then bBalf = 1
    HRSOut At pLine, pXpos, Rep cFullBar\bBars,_        ' Display the bargraph on the LCD
                            Rep (bBalance + cBaseBar)\bBalf,_
                            Rep " "\cBarWidth - (bBars + bBalf)
EndProc

'------------------------------------------------------------------------------------------------
' Create the UDGs for the barchart in the LCD's CGRAM
' Input     : None
' Output    : None
' Notes     : The bars are made up of 3 bit patterns
'             A | bar consists of 6 times   %00010000
'             A || bar consists of 6 times  %00010100
'             A ||| bar consists of 6 times %00010101
'
Proc LCD_CreateIcons()
    HRSOut1 $FE, 64, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000,_
                     %00010000, %00010000, %00010000, %00010000, %00010000, %00010000, %00000000, %00000000,_
                     %00010100, %00010100, %00010100, %00010100, %00010100, %00010100, %00000000, %00000000,_
                     %00010101, %00010101, %00010101, %00010101, %00010101, %00010101, %00000000, %00000000
    DelayMS 10
EndProc

Below is a screenshot of the two programs above operating in the proteus simulator, where a Master device is transmitting to the serial LCD controller via a single pin using async serial data at 9600 Baud. The two programs and a proteus project is also attached below, named: "Serial_LCD_16Fe.zip", because the serial controller is using an enhanced 14-bit core device, but any device with a USART can be used. And if the device is capable, use its internal oscillator:

Serial_LCD_Screenshot.jpg