1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice
languer

Simple Serial LCD

Creating a serial LCD can be very useful for quick debugging; as well as projects requiring LCD sup

  1. languer
    Creating a serial LCD can be very useful for quick debugging; as well as projects requiring LCD support with minimal interface. The circuit presented here may not satisfy all needs, but it should serve as a good starting point for further work.

    How does serial LCD interface work?
    It is quite simple really. Using a microcontroller with a built-in HW UART, the information form the HW UART is received and passed on to the LCD using 4-bit control. The LCD is a standard 2x16 character based display compatible with a HD44780 controller. The microcontroller is a 16F688 with built-in UART. A baud-select function is included to allow for the selection of two different input baud rates. The following figure shows how the circuit used.

    [​IMG]


    Code Description:
    The code for the simple serial LCD was created using Oshonsoft Basic. This language is not as complete or provides as much functionality as others (e.g. CCS C), but it can be readily obtained and used.

    The code can be summarized as follows:
    • On power-up read the baud-select input (select between 9600bps and 1200bps),
    • Continuously monitor the HW UART and parse any received characters,
    • a null character is ignored,
    • a carriage return starts the second line of the LCD,
    • an escape character clears the LCD,
    • everything else is passed on to the LCD.

    Oshonsoft Code:
    Code (text):
    '* PIC16F688 Serial LCD Test Bed *'
    'Title: Simple Serial LCD Test Program
    'Description: This program uses PIC16F688 to drive a 2x16 LCD from an RS-232 input (9600bps)
    'Author: languer (2010)
    'Pin Allocation:
        'PIN#   Main_Fn
        'RA0 -> PGD - Programming data
        'RA1 -> PGC - Programming clock
        'RA2 -> not used
        'RA3 -> not used
        'RA4 -> LCD EBIT
        'RA5 -> LCD RSBIT
        'RC0 -> LCD DB4
        'RC1 -> LCD DB5
        'RC2 -> LCD DB6
        'RC3 -> LCD DB7
        'RC4 -> BAUD SELECT
        'RC5 -> RS232 RX
    'Usage Information:
        'BAUD Select
            'low -> 1200
            'high -> 9600
        'RS232 Input
            '0x00 -> ignore
            '0x0D -> LCD line 2, clear line 2
            '0x1B -> LCD line 1, clear LCD

    'General Device Configuration
    Define CONF_WORD = 0x33c4
    OSCCON = 0x70  'define internal 8MHz clock
    Define CLOCK_FREQUENCY = 8

    'HW UART Setup
    Define ALLOW_MULTIPLE_HSEROPEN = 1

    'LCD Configuration
    Define LCD_BITS = 4  'allowed values are 4 and 8 - the number of data interface lines
    Define LCD_DREG = PORTC
    Define LCD_DBIT = 0  '0 or 4 for 4-bit interface, ignored for 8-bit interface
    Define LCD_RSREG = PORTA
    Define LCD_RSBIT = 5
    Define LCD_EREG = PORTA
    Define LCD_EBIT = 4
    Define LCD_RWREG = 0  'set to 0 if not used, 0 is default
    Define LCD_RWBIT = 0  'set to 0 if not used, 0 is default
    Define LCD_COMMANDUS = 2000  'delay after LCDCMDOUT, default value is 5000
    Define LCD_DATAUS = 50  'delay after LCDOUT, default value is 100
    Define LCD_INITMS = 10  'delay used by LCDINIT, default value is 100


    'Variable Declarations
    Const trisa1 = %11001111
    Const trisc1 = %11010000

    Symbol lcd_db4 = PORTC.0
    Symbol lcd_db5 = PORTC.1
    Symbol lcd_db6 = PORTC.2
    Symbol lcd_db7 = PORTC.3
    Symbol lcd_rs = PORTA.4
    Symbol lcd_e = PORTA.5

    Symbol baud_select = PORTC.4
    Symbol rs232_rx = PORTC.5

    Dim _true As Bit
    Dim _false As Bit
    Dim char As Byte

    _true = True
    _false = False

    'Main Program
    main:
        Call init()
        WaitMs 1000
        While _true
            Call get_rs232_char()
            Call send_lcd_char()
        Wend
    End                                              
    Proc init()
        AllDigital  'set all ports to digital
        TRISA = trisa1
        TRISC = trisc1
        WaitMs 1
        Lcdinit 1  'initialize LCD module; cursor is blinking
        Lcdcmdout LcdClear  'clear LCD display
        Lcdout "LCD Display"  'line 1
        Lcdcmdout LcdLine2Home  'set cursor at the beginning of line 2
        Lcdout "LR@2010"  'line 2
        WaitMs 1
        If baud_select = 1 Then
            Hseropen 9600
        Else
            Hseropen 1200
        Endif
    End Proc                                          
    Proc get_rs232_char()
            Hserin char
    End Proc                                          
    Proc send_lcd_char()
            Select Case char
            Case 0
                'do nothing
            Case 13
                Lcdcmdout LcdLine2Home
                Lcdcmdout LcdLine2Clear
            Case 27
                Lcdcmdout LcdHome
                Lcdcmdout LcdClear
            Case Else
                Lcdout char
            EndSelect
    End Proc
    CCS Code:
    Code (text):
    /*** PREPROCESSOR ***/
    #include <16F688.h>
    #device ADC=10
    #fuses INTRC_IO,NOPROTECT,NOBROWNOUT,NOMCLR,NOCPD,NOWDT,PUT,NOIESO,NOFCMEN
    #use delay(clock=8000000)

    /*** INCLUDES ***/

    /*** BUILD INFORMATION ***/
    #ORG 0x01F0,0x01FF
    const char build_rev[] = {"Rev 1.0"};

    /*** DEFINITIONS ***/
    #byte PORTA = 0x05
    #byte PORTC = 0x07
    #byte INTCON = 0x0B
    #byte PIR1 = 0x0C
    #byte CMCON = 0x19
    #byte ADCON0 = 0x1F
    #byte OPTION_REG = 0x81
    #byte TRISA = 0x85
    #byte TRISC = 0x87

    #define LINE_16_1   0x00
    #define LINE_16_2   0x40
    #define LINE_16_3   0x10
    #define LINE_16_4   0x50
    // These defines are specifically for a 4x20 line display.
    #define LINE_20_1   0x00
    #define LINE_20_2   0x40
    #define LINE_20_3   0x14
    #define LINE_20_4   0x54
    // Another define for use in LCD_PutCmd
    #define CLEAR_DISP  0x01

    struct lcd_pin_map
    {
        int8 empty1: 4; // RA0-RA3 unused
        int1 en :   1;  // RA5
        int1 rs :   1;  // RA4
        int1 na1:   1;  // RA6 - not implemented
        int1 na2:   1;  // RA7 - not implemented
        int8 empty2: 8; // not implemented
        int8 data:  4;  // RC0-RC3
        int8 na3:   4;  // RC4-7 - not implemented
    } lcd;

    #byte LCD = PORTA   //PORT A & C

    /*** VARIABLES / CONSTANTS ***/
    #define _TRISA 0b11001111
    #define _TRISC 0b11110000
    #define scrollDelay 100
    #define ioCommTx PIN_A0
    #define ioHwUartRx PIN_C5
    #define ioHwUartTx PIN_C4
    #define ioBaudSelect PIN_C4
    #define bufferSize 35   //includes 32bytes to cover 2x16 display, plus STX and ETX, plus 1
    #define STX 0x81
    #define ETX 0x18
    int8 commMsg[bufferSize];
    int8 msgCnt;
    int1 baudSelect;

    /*** FUNCTION PROTOTYPES ***/
    void init();
    void getMsg1200();
    void getMsg9600();
    void displayMsg();
    void LCD_SetPosition( char cX );
    void LCD_PutChar( char cX );
    void LCD_ScrollChar( char cX );
    void LCD_PutCmd( char cX );
    void LCD_Init( void );
    void LCD_pulseEN( void );

    #use rs232 (baud=1200,xmit=ioCommTx,parity=N,bits=8,stream=DEBUG)
    #use rs232 (baud=1200,xmit=ioHwUartTx,rcv=ioHwUartRx,parity=N,bits=8,stream=HWUART1200,ERRORS)
    #use rs232 (baud=9600,xmit=ioHwUartTx,rcv=ioHwUartRx,parity=N,bits=8,stream=HWUART9600,ERRORS)

    /*** FUNCTION - Main ***/
    void main()
    {
        init();                                 // initializes pic

        LCD_Init ();

        LCD_PutCmd ( CLEAR_DISP );
        LCD_SetPosition ( LINE_16_1 );
        printf ( LCD_PutChar, "SERIAL DISPLAY" );
        LCD_SetPosition ( LINE_16_2 );
        printf ( LCD_PutChar, "LR@2013 " );
        printf ( LCD_PutChar, build_rev );

        baudSelect = input(ioBaudSelect);

        delay_ms(2500);

        if (baudSelect == 0)
        {
            LCD_PutCmd ( CLEAR_DISP );
            LCD_SetPosition ( LINE_16_1 );
            printf ( LCD_PutChar, "1200 BAUD" );
        }
        else
        {
            LCD_PutCmd ( CLEAR_DISP );
            LCD_SetPosition ( LINE_16_1 );
            printf ( LCD_PutChar, "9600 BAUD" );
        }

        while( true )
        {
            if (baudSelect == 0)
            {
                getMsg1200();
            }
            else
            {
                getMsg9600();
            }
            displayMsg();
        }
    }

    /*** FUNCTION - MCU Intialization ***/
    void init()
    {
        set_tris_A( _TRISA );
        set_tris_C( _TRISC );
        setup_adc( ADC_OFF );
        setup_adc_ports( NO_ANALOGS );
        setup_comparator( NC_NC_NC_NC );
    }

    /*** FUNCTION - Get UART Message (1200baud) ***/
    void getMsg1200()
    {
        int8 commChar = 0;
        int8 msgState = 0;
        int1 msgComplete = False;
        while ( ~msgComplete )
        {
            if ( kbhit(HWUART1200) )
            {
                commChar = fgetc(HWUART1200);           // receive character
                switch (msgState)
                {
                    case 0:
                    {
                        if (commChar == STX)
                        {
                            msgState++;
                            msgCnt = 0;
                        }
                        else
                        {
                            msgState = 0;
                            msgCnt = 0;
                        }
                        break;
                    }
                    case 1:
                    {
                        if (commChar == ETX)
                        {
                            msgState = 0;
                            msgComplete = True;
                        }
                        else
                        {
                            if (msgCnt >= bufferSize)
                            {
                                msgState = 0;
                                msgCnt = 0;
                            }
                            else
                            {
                                commMsg[msgCnt] = commChar;
                                msgCnt++;
                            }
                        }
                        break;
                    }
                    default:
                    {
                        msgState = 0;
                        msgCnt = 0;
                        msgComplete = False;
                        break;
                    }
                }
            }
        }
    }

    /*** FUNCTION - Get UART Message (9600baud) ***/
    void getMsg9600()
    {
        int8 commChar = 0;
        int8 msgState = 0;
        int1 msgComplete = False;
        while ( ~msgComplete )
        {
            if ( kbhit(HWUART9600) )
            {
                commChar = fgetc(HWUART9600);           // receive character
                switch (msgState)
                {
                    case 0:
                    {
                        if (commChar == STX)
                        {
                            msgState++;
                            msgCnt = 0;
                        }
                        else
                        {
                            msgState = 0;
                            msgCnt = 0;
                        }
                        break;
                    }
                    case 1:
                    {
                        if (commChar == ETX)
                        {
                            msgState = 0;
                            msgComplete = True;
                        }
                        else
                        {
                            if (msgCnt >= bufferSize)
                            {
                                msgState = 0;
                                msgCnt = 0;
                            }
                            else
                            {
                                commMsg[msgCnt] = commChar;
                                msgCnt++;
                            }
                        }
                        break;
                    }
                    default:
                    {
                        msgState = 0;
                        msgCnt = 0;
                        msgComplete = False;
                        break;
                    }
                }
            }
        }
    }

    /*** FUNCTION - Display Message On LCD ***/
    void displayMsg()
    {
        int8 cnt;

        for (cnt=0;cnt<msgCnt;cnt++)
        {
            LCD_PutChar(commMsg[cnt]);
        }
    }

    /*** FUNCTION - Initialize LCD ***/
    void LCD_Init ( void )
    {
        // Initializing into 4-bit mode is a very exact sequence
        // as defined in the datasheets for these displays.
        delay_ms( 200 );        /* wait enough time after Vdd rise */
        lcd.rs = 0;
        lcd.data = 0x00;
        lcd.data = 0x03;        /* init with specific nibbles to start 4-bit mode */
        LCD_pulseEN();
        LCD_pulseEN();
        LCD_pulseEN();
        lcd.data = 0x02;        /* set 4-bit interface */
        LCD_pulseEN();          /* send dual nibbles hereafter, MSN first */
        LCD_PutCmd( 0x2C );     /* function set (2 lines, 5x7 characters) */
        LCD_PutCmd( 0x0C );     /* display ON, cursor OFF, blink OFF */
    //  LCD_PutCmd( 0x0E );     /* display ON, cursor ON, blink OFF */
    //  LCD_PutCmd( 0x0F );     /* display ON, cursor ON, blink ON */
    //  LCD_PutCmd( 0x01 );     /* clear display */
        LCD_PutCmd( 0x01 );     /* clear display */
        LCD_PutCmd( 0x06 );     /* entry mode set, increment */
    }

    /*** FUNCTION - Set LCD X,Y Position ***/
    void LCD_SetPosition( cX )
    {
        /*
        This subroutine works specifically for 4-bit Port A.
        Value received cX will place cursor at a particular line and offset.
                        16-char display     20-char display
                        ===============     ===============
        Line 1 is hex:      00 - 0F             00 - 13
        Line 2 is hex:      40 - 4F             40 - 53
        Line 3 is hex:      10 - 1F             14 - 27
        Line 4 is hex:      50 - 5F             54 - 67
        */
        lcd.data = swap( cX ) | 0x08;
        LCD_pulseEN();
        lcd.data = swap( cX );
        LCD_pulseEN();
    }

    /*** FUNCTION - Write Character To LCD ***/
    void LCD_PutChar( cX )
    {
        /* this subroutine works specifically for 4-bit Port A */
        switch ( cX )
        {
            case '\f':
            {
                LCD_PutCmd( CLEAR_DISP );
                break;
            }
            case '\n':
            {
                LCD_SetPosition ( LINE_16_2);
                break;
            }
            case '\r':
            {
                LCD_SetPosition ( LINE_16_2);
                break;
            }
            default:
            {
                lcd.rs = 1;
                lcd.data = swap( cX );      // send high nibble
                LCD_pulseEN();
                lcd.data = swap( cX );      // send low nibble
                LCD_pulseEN();
                lcd.rs = 0;
                break;
            }
        }
    }

    /*** FUNCTION - Scroll Character On LCD ***/
    void LCD_ScrollChar( cX )
    {
        /* this subroutine works specifically for 4-bit Port A */
        lcd.rs = 1;
        lcd.data = swap( cX );      /* send high nibble */
        LCD_pulseEN();
        lcd.data = swap( cX );      /* send low nibble */
        LCD_pulseEN();
        lcd.rs = 0;
        delay_ms(scrollDelay);
    }

    /*** FUNCTION - Write Command To LCD ***/
    void LCD_PutCmd( cX )
    {
        /* this subroutine works specifically for 4-bit Port A */
        lcd.data = swap( cX );      /* send high nibble */
        LCD_pulseEN();
        lcd.data = swap( cX );      /* send low nibble */
        LCD_pulseEN();
    }

    /*** FUNCTION - Toggle Enable Pin On Lcd To Load Command Or Character Into LCD ***/
    void LCD_pulseEN( void )
    {
        lcd.en = 1;
        delay_us( 10 );
        lcd.en = 0;
        delay_ms( 5 );
    }

    Attached Files: