How do you drive a Serial LCD?


Closed Thread
Results 1 to 20 of 20

Hybrid View

  1. #1
    Join Date
    Oct 2009
    Location
    Utah, USA
    Posts
    427


    Did you find this post helpful? Yes | No

    Default Re: How do you drive a Serial LCD?

    Thanks Mike,

    That was quite innovative of you to use the incomming data to both talk to the PIC and control the RS line of the LCD!!

    nice work.

    So is your new design going to use a differend PIC with more I/O pins??

    Dwight
    Dwight
    These PIC's are like intricate puzzles just waiting for one to discover their secrets and MASTER their capabilities.

  2. #2
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: How do you drive a Serial LCD?

    So is your new design going to use a differend PIC with more I/O pins?
    I'm upgrading the interface that uses the 8 pin PIC and actually studying another two slightly more advanced designs.

    If you're interested, I've attached the source (assembler) for the 12F635 backpack as well as the source (also assembler) for the 16F1823 on that prototype board. This is the old software and, as I mentioned, probably not very useful for PBP users who are used to having all those wonderful LCD output formatting capabilities.

    Happy Holidays! Mike
    Attached Files Attached Files

  3. #3
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: How do you drive a Serial LCD?

    Hi Dwight (and gang),

    If you're interested... I just finished testing the upgrade to the 8-pin PIC serial LCD interface and it works great. The mod involved adding an RC integrator/filter (10K + 330pF) between the GP0/D4 pin and the LCD RS pin. Now I can drive all six LCD control pins directly from the little 8-pin PIC which means I can collect serial data, analyze it, and write data to the LCD display any way I want. In short, you should be able to feed the serial interface using the DEBUG, SEROUT2 or HSEROUT commands with all of the same formatting parameters you're using now with the LCDOUT command. I'm pretty geeked (yes, I'm a nerd - LOL).

    If anyone is interested, I'll start a new thread in the 'schematic' sub-forum after characterizing and testing the firmware. The only real advantages I can think of for this interface is its size (very small footprint on a project board when using the 2x5 header for a MikroE LCD Adapter board) and its ability to drive four lines of a switch matrix (one additional pin on the host can read four switches, an encoder, etc.).

    Cheers, Happy Holidays, Mike
    Attached Images Attached Images  
    Last edited by Mike, K8LH; - 9th December 2011 at 19:47.

  4. #4
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: How do you drive a Serial LCD?

    Drawing of the updated backpack hardware...
    Attached Images Attached Images  

  5. #5
    Join Date
    Sep 2004
    Location
    Mentor, Ohio
    Posts
    352


    Did you find this post helpful? Yes | No

    Default Re: How do you drive a Serial LCD?

    Hi Mike,

    Mind if I ask what program you are using to illustrate your drawings?

    Thanks,

    BobK

  6. #6
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: How do you drive a Serial LCD?

    Greetings BobK.

    The drawings were made using the drawing tools in Excel...

    The paper silkscreen on the Radio Shack prototyping board was a printout of the silkscreen layer from DipTrace. The paper silkscreen is laminated with plastic tape and glued onto the board.

    Cheerful regards, Mike
    Last edited by Mike, K8LH; - 14th December 2011 at 13:07.

  7. #7
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: How do you drive a Serial LCD?

    Better late than never? Here's firmware for the 12F683 version of the serial backpack.

    Cheerful regards, Mike

    Code:
    ;******************************************************************
    ;                                                                 *
    ;   Filename: ezLCD v3 (12F683).asm                               *
    ;     Author: Mike McLaren, K8LH                                  *
    ;    (C)2010: Micro Application Consultants, All Rights Reserved  *
    ;       Date: 08-Dec-11  (rev:111210.0637z)                       *
    ;                                                                 *
    ;   K8LH 12F683 serial HD44780 LCD 4-bit interface experiment     *
    ;                                                                 *
    ;   8-bit test code.  this interface traps a 0xFE character and   *
    ;   writes the character immediately following it to the LCD as   *
    ;   a command character (RS = 0)                                  *
    ;                                                                 *
    ;                                                                 *
    ;      MPLab: 8.80    (tabs=8)                                    *
    ;      MPAsm: 5.43                                                *
    ;                                                                 *
    ;******************************************************************
    
        #include <p12f683.inc>
        list st=off
        errorlevel -302
    
        radix   dec
    
        __config  _FCMEN_OFF&_IESO_OFF&_MCLRE_OFF&_WDT_OFF&_INTRC_OSC_NOCLKOUT
    
    ;--< variables >---------------------------------------------------
    
    datahi  equ     0x40            ; shadow for 1st nibble
    datalo  equ     0x41            ; shadow for 2nd nibble
    temp    equ     0x42            ; low level LCD routines
    delayhi equ     0x43            ;
    rsflag  equ     0x44            ;
    
    ;--< constants >---------------------------------------------------
    ;
    ;  bit time (cycles) used to sample a serial bit stream
    ;
    ;    9600 baud, 208 (208.3) cycles, 0.16% bit rate error
    ;   19200 baud, 104 (104.2) cycles, 0.16% bit rate error
    ;   57600 baud,  35 ( 34.7) cycles, 0.80% bit rate error
    ;
    clock   equ     8               ; 8 MHz clock
    usecs   equ     clock/4         ; cycles/usec multiplier
    msecs   equ     clock/4*1000    ; cycles/msec multiplier
    bRate   equ     57600           ; baudrate 9600, 19200, or 57600
    bTime   equ     (usecs*10000000/bRate+5)/10
                                    ; bTime = 208, 104, or 35 cycles
    ;
    #define D4      0               ; GP0 -> LCD 'D4'
    #define D5      1               ; GP1 -> LCD 'D5'
    #define D6      2               ; GP2 -> LCD 'D6'
    #define SerPin  GPIO,3          ; GP3 -> Serial Input
    #define D7      4               ; GP4 -> LCD 'D7'
    #define E       5               ; GP5 -> LCD 'E'
    
    #define RS      D4              ; RS 'rc' integrator output
    
    ;--< macros >------------------------------------------------------
    ;
    ;  inDlyCy() in-line delay macro, range 0..1023 cycles,
    ;  produces 0 to 6 instructions.
    ;
    inDlyCy macro   pTime
            local   dloop
          if pTime > 3
            movlw   (pTime)/4-1     ;
    dloop   addlw   -1              ;
            bc      dloop           ;
          endif
          if pTime%4 & 1
            nop                     ; 1 cycle
          endif
          if pTime%4 & 2
            goto    $+1             ; 2 cycles
          endif
            endm
    ;
    ;  K8LH DelayCy() subsystem macro generates four instructions
    ;
    DelayCy macro   cycles          ; 11..327690 cycle range
        if (cycles<11)|(cycles>(5*65536+10))
            error " DelayCy range error "
        endif
            movlw   high((cycles-11)/5)+1
            movwf   delayhi
            movlw   low ((cycles-11)/5)
            call    uDelay-((cycles-11)%5)
            endm
    
    ;******************************************************************
    ;   Reset Vector                                                  *
    ;******************************************************************
    
            org     0x0000
    v_reset
            clrf    STATUS          ;				  |B0
            goto    Main            ;                                 |B0
    
    ;******************************************************************
    ;   Interrupt Vector                                              *
    ;******************************************************************
    
            org     0x0004
    v_int
    ;
    ;  using IOC interrupt on start bit leading edge
    ;
            inDlyCy(bTime/2-4)      ; half bit time minus 4 cycles    |B0
            movlw   1<<E            ; preset E bit                    |B0
            movwf   datahi          ;                                 |B0
            movwf   datalo          ;                                 |B0
    ;
    ;  collect lo nibble in 'datalo' (LCD data bits b0..b3)
    ;
    bit0    inDlyCy(bTime-3)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datalo,D4       ; set LCD D4 shadow bit           |B0
    bit1    inDlyCy(bTime-2)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datalo,D5       ; set LCD D5 shadow bit           |B0
    bit2    inDlyCy(bTime-2)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datalo,D6       ; set LCD D6 shadow bit           |B0
    bit3    inDlyCy(bTime-2)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datalo,D7       ; set LCD D7 shadow bit           |B0
    ;
    ;  collect hi nibble in 'datahi' (LCD data bits b4..b7)
    ;
    bit4    inDlyCy(bTime-2)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datahi,D4       ; set LCD D4 shadow bit           |B0
    bit5    inDlyCy(bTime-2)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datahi,D5       ; set LCD D5 shadow bit           |B0
    bit6    inDlyCy(bTime-2)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datahi,D6       ; set LCD D6 shadow bit           |B0
    bit7    inDlyCy(bTime-2)        ;                                 |B0
            btfsc   SerPin          ; bit = 0?  yes, skip, else       |B0
            bsf     datahi,D7       ; set LCD D7 shadow bit           |B0
    ;
    ;     if(datahi == 0x0F)        // if data == 0xF0..0xFF
    ;     { datahi.E = 0;           // don't write LCD (E bit off)
    ;       datalo.E = 0;           // don't write LCD (E bit off)
    ;     }                         // 
    ;     gpio = rsflag;            // charge or drain RS cap
    ;     delay_us(3);              //
    ;     gpio = datahi;            // setup D4..D7 and E=1
    ;     gpio.E = 0;               // E = 0 (write LCD)
    ;     gpio = rsflag;            // charge or drain RS cap
    ;     delay_us(3);              //
    ;     gpio = datalo;            // setup D4..D7 and E=1
    ;     gpio.E = 0;               // E = 0 (write LCD)
    ;
    ;     rsflag ^= 1<<RS;          // toggle rs flag
    ;     if(datahi.E)              // if not 0xFE character
    ;       rsflag = 1<<RS;         // reset rs flag (RS=1)
    ;
    wrhi
            movf    rsflag,W        ; the RS bit flag & mask          |B0
            movwf   GPIO            ; charge or drain RS cap          |B0
            movlw   b'00110111'     ; mask for datahi = 0x0F          |B0 --
            xorwf   datahi,W        ; is data == 0xF0..0xFF?          |B0 --
            skpnz                   ; no, skip, else                  |B0 --
            bcf     datahi,E        ; don't write LCD                 |B0 --
            skpnz                   ; no, skip, else                  |B0 --
            bcf     datalo,E        ; don't write LCD                 |B0 --
            movf    datahi,W        ; get data 7..4 bits              |B0
            movwf   GPIO            ; setup D4..D7, E=1               |B0
            bcf     GPIO,E          ; E = 0 (write LCD)               |B0
    wrlo
            movf    rsflag,W        ; the RS bit flag & mask          |B0
            movwf   GPIO            ; charge or drain RS cap          |B0
            movlw   1<<RS           ;                                 |B0 --
            xorwf   rsflag,F        ; toggle RS flag & mask           |B0 --
            btfsc   datahi,E        ; if datahi not 0x0F              |B0 --
            iorwf   rsflag,F        ; reset RS flag & mask (RS=1)     |B0 --
            goto    $+1             ;                                 |B0 --
            movf    datalo,W        ; get data 3..0 bits              |B0
            movwf   GPIO            ; setup D4..D7, E = 1             |B0
            bcf     GPIO,E          ; E = 0 (write LCD)               |B0
    stop
            inDlyCy(bTime-24)       ; during middle of stop bit       |B0
            movf    GPIO,W          ; clear IOC mismatch              |B0
            bcf     INTCON,GPIF     ; clear IOC interrupt flag        |B0
            retfie                  ;                                 |B0
    
    ;******************************************************************
    ;  main                                                           *
    ;******************************************************************
    ;
    ;  void main()
    ;  { 
    ;    cmcon0 = 7;                // comparator off
    ;    gpio = 0;                  // clear gpio output latches
    ;    trisio = 0b00001000;       // gp3 input, others outputs
    ;    osccon = 0b01110000;       // setup intosc for 8 MHz
    ;    while(osccon.HTS == 0);    // wait for osc stable
    ;
    Main
            movlw   b'00000111'     ;                                 |B0
            movwf   CMCON0          ; comparator off                  |B0
            clrf    GPIO            ; clear GPIO output latches       |B0
            bsf     STATUS,RP0      ; bank 1                          |B1
    ;       clrf    ANSEL           ; no analog, all digital          |B1
            movlw   b'00001000'     ; GP3 input, all others outputs   |B1
            movwf   TRISIO          ;                                 |B1
            movwf   IOCA            ; enable IOC for GP3 'SerPin'     |B1
            movlw   b'01110000'     ;                                 |B1
            movwf   OSCCON          ; 8-mhz INTOSC system clock       |B1
    stable  btfss   OSCCON,HTS      ; oscillator stable?              |B1
            goto    stable          ; no, branch, else                |B1
    ;
    ;  HD44780 "initialize by instruction" for 4-bit interface mode
    ;
            bcf     STATUS,RP0      ; bank 0                          |B0
            DelayCy(50*msecs)       ; LCD 50 msec 'power up' reset    |B0
            movlw   0x03            ; hi nibble of "8-bit" command    |B0
            call    PutNyb          ; step 1 (send nibble only)       |B0
            DelayCy(4*msecs)        ; required 4 msec delay           |B0
            movlw   0x03            ;                                 |B0
            call    PutNyb          ; step 2 (send nibble only)       |B0
            DelayCy(160*usecs)      ; required 160-us delay           |B0
            movlw   0x03            ;                                 |B0
            call    PutNyb          ; step 3 (send nibble only)       |B0
            DelayCy(160*usecs)      ; required 160-us delay           |B0
            movlw   0x02            ; hi nibble of "4-bit" command    |B0
            call    PutNyb          ; select 4-bit interface mode     |B0
            DelayCy(160*usecs)      ; required 160-us delay           |B0
    ;
    ;  now in 4-bit interface mode. ok to send full bytes.
    ;
            movlw   0x28            ; 4-bit, 2-lines, 5x7 font        |B0
            call    PutCmd          ; send "function set" command     |B0
            movlw   0x0C            ; display on, cursor & blink off  |B0
            call    PutCmd          ; send "display on/off" command   |B0
            movlw   0x06            ; cursor inc, shift off           |B0
            call    PutCmd          ; send "entry mode set" command   |B0
            movlw   0x01            ; clear display (1.53-msecs)      |B0
            call    PutCmd          ; send "entry mode set" command   |B0
            DelayCy(1530*usecs)     ; 1.53 msec delay for "clear"     |B0
    ;
    ; // setup RA3 'SerPin' for interrupt-on-change
    ;
    ;    rsflag = 1<<RS;            // set RS flag & mask
    ;    while(SerPin == 0);        // wait for hi level on GP3
    ;    temp = gpio;               // clear any mismatch condx
    ;    intcon.RAIF = 0;           // clear IOC interrupt flag
    ;    ioca.IOCA3 = 1;            // eanble IOC for GP3 'SerPin'
    ;    intcon.GIE = 1;            // enable global interrupts
    ;
    ;    while(1);                  // loop forever
    ;  }
    ;
            bcf     STATUS,RP0      ; bank 0                          |B0
            movlw   1<<RS           ;                                 |B0
            movwf   rsflag          ; set RS flag & mask (RS=1)       |B0
            btfss   SerPin          ; stop state? yes, skip, else     |B0
            goto    $-1             ; loop (wait)                     |B0
            movf    GPIO,W          ; clear GPIO mismatch condition   |B0
            bcf     INTCON,GPIF     ; clear IOC interrupt flag        |B0
            bsf     INTCON,GIE      ; enable global interrupts        |B0
            bsf     INTCON,GPIE     ; enable 'IOC' interrupts         |B0
    loop
            goto    loop            ; loop forever                    |B0
    
    ;******************************************************************
    ;  low level lcd subroutines                                      *
    ;******************************************************************
    
    PutCmd                          ; entry point for "cmd" data
            clrc                    ; RS = 0 (command)                |B?
            skpnc                   ; skip unconditionally            |B?
    PutDat                          ; entry point for "dat" data
            setc                    ; RS = 1 (data)                   |B?
            banksel temp            ; bank 0                          |B0
            movwf   temp            ; save WREG data byte             |B0
            swapf   temp,W          ;                                 |B0
            call    PutNyb          ; send hi nybble                  |B0
            swapf   temp,W          ;                                 |B0
            call    PutNyb          ; send lo nybble                  |B0
            DelayCy(50*usecs)       ; required between writes         |B0
            return                  ;                                 |B0
    PutNyb
            movwf   temp            ;                                 |B0
            bcf     GPIO,RS         ; RS = 0 (discharge RS cap)       |B0
            skpnc                   ; RS = 0?  yes, skip, else        |B0
            bsf     GPIO,RS         ; RS = 1 (charge RS cap)          |B0
            movlw   1<<E            ;                                 |B0
            btfsc   temp,0          ;                                 |B0
            iorlw   1<<D4           ;                                 |B0
            btfsc   temp,1          ; b1 = 0?  yes, skip, else        |B0
            iorlw   1<<D5           ;                                 |B0
            btfsc   temp,2          ; b2 = 0?  yes, skip, else        |B0
            iorlw   1<<D6           ;                                 |B0
            btfsc   temp,3          ; b3 = 0?  yes, skip, else        |B0
            iorlw   1<<D7           ;                                 |B0
            movwf   GPIO            ; LCD D4..D7 = data1, E = 1       |B0
            bcf     GPIO,E          ; E = 0                           |B0
            return                  ;                                 |B0
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  K8LH DelayCy() 16-bit uDelay subroutine                        ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            nop                     ; entry for (delay-11)%5 == 4     |B0
            nop                     ; entry for (delay-11)%5 == 3     |B0
            nop                     ; entry for (delay-11)%5 == 2     |B0
            nop                     ; entry for (delay-11)%5 == 1     |B0
    uDelay  addlw   -1              ; subtract 5 cycle loop time      |B0
            skpc                    ; borrow? no, skip, else          |B0
            decfsz  delayhi,F       ; done?  yes, skip, else          |B0
            goto    uDelay          ; do another loop                 |B0
            return                  ; return with C = Z = 0           |B0
    
    ;******************************************************************
            end
    Attached Images Attached Images  

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