How do you drive a Serial LCD?


Results 1 to 20 of 20

Threaded View

  1. #17
    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 : 1

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