Post

PIC16 Controlling LCD

PIC16 Controlling LCD

Here you will find the source code and schematics for interfacing LCD displays based on the Hitachi HD44780U controller with Microchip PIC16 microcontrollers using only 3 I/O pins.

The design utilizes a 74HC164 8-bit serial-to-parallel shift register to minimize I/O pin usage.

Required I/O pins:

  • Clock - For shift register timing
  • Data - For serial data transmission
  • LCD Enable - For display control

The Clock and Data pins can be shared with other peripheral devices, making this solution ideal for pin-constrained applications.

The implementation is optimized for minimal assembly instructions to conserve program memory, particularly beneficial for microcontrollers with limited instruction space.

Schematics

Controlling LCD with 74HC164 Schematics Controlling LCD with 74HC164 Schematics

Code

Download the source code

;******************************************************************************
;   LCD interface for Microchip PIC16 microcontrollers.
;
;   author:   Ivan Dachev
;   email:    [email protected]
;   web:      www.lz2gl.com
;   version:  v1.0
;
;******************************************************************************
;
; Program control 8-Bit Serial-Input/Parallel-Output Shift Register 
; 74HC164 which is connected to LCD.
;
; It is implement to use only 3 ports from microcontroller:
;   CLOCK - clock for 74HC164
;   DATA - data for 74HC164
;   STROBE - enable/disable for LCD read operation
;
; 14.01.2007 Initial Version
;   All source here is small parts from my programs 
;   so to be usable for own use, change position
;   of file registers to fit your program.
;
;******************************************************************************

;******************************************************************************
; Bit flags for SYNSTATUS
;
; Constants _XXX_BITS are used to make bit swapping
; example:
;       movlw   _LOCK_BITS  
;       xorwf   SYNSTATUS, F
;
#define _INSTLCD         SYNSTATUS, 5 ;5-bit Instruction/Data flag for LCD
#define _INSTLCD_BITS    B'00100000'


;******************************************************************************
;
; Main preferences for program.
;

#define OUT2LCD_DELAY_TIME .62 
        ;Delay counter for OUT2LCD_DATA.
        ;Each iteration is 3 instructions we must wait about 37000ns
        ;so (20Mhz - number is 62) (10Mhz - number is 31)

;******************************************************************************
;
; Defines IN/OUT for PORTA
;
#define OUT_LCDCLOCK   PORTA, 1 ;Share CLOCK at RA1 for LCD
#define OUT_LCDDATA    PORTA, 2 ;Share DATA at RA2 for LCD

#define OUT_LCDSTROBE  PORTA, 3 ;Strob signal at RA3 for LCD

;******************************************************************************
; Define commands for LCD
;
#define LCD_CLEAR     B'00000001' ; Clear display, home cursor
#define LCD_HOME      B'00000010' ; Send cursor home
#define LCD_8BIT      B'00111100' ; 8-bit interface, 2 display lines, 5x10 font
#define LCD_DISABLE   B'00001000' ; Disable entire display
#define LCD_ENABLE    B'00001100' ; Display enable, no cursor
#define LCD_MODESET   B'00000110' ; Increment cursor, no scrolling

#define LCD_CURSOFF   B'00001100' ; Cursor off
#define LCD_CURSON    B'00001111' ; Cursor on and blink at position
#define LCD_CURSRIGHT B'00010100' ; move cursor right one space

#define LCD_SETADDR   B'10000000' ; Set display address for writing

;******************************************************************************
; File registers
;

;general temp 
tmp   equ 0x50
;general counter
count equ 0x53  

;used for delay functions
delay1 equ  0x5D
delay2 equ  0x5E

;other variables
SYNSTATUS equ 0x73 ;boolean flags


;******************************************************************************
;
; INITLCD
; -------
;
; Initializing LCD
;
; 03.07.2004 Changed according to HITACHI specification !
;******************************************************************************
;

INITLCD
  ;--- START HITACHI INITIALIZING SPECIFICATION FOR LCD ----
#ifndef DEBUG_SIM
      movlw   .255
      CALL    WAITWMS
#endif
    ;Wait for more than 15 ms after VCC rises to 4.5 V
    ;Wait for more than 40 ms after VCC rises to 2.7 V

    ;Set Data Serial 8bit
    ;B 0011 1100
      movlw   LCD_8BIT
      CALL    OUT2LCD_INST
      CALL    WAIT5MS   ;Wait more then 4.1ms

    ;Again set Data Serial 8bit
      CALL    LCDSTROBE ;Just enable LCD to read again same operation
      CALL    WAIT1MS   ;Wait more then 100us

    ;And again
      CALL    LCDSTROBE ;Just enable LCD to read again same operation

    ;Set Data Serial 8bit, display 2 lines, Font to 5x10 dots
    ;B 0011 1100
      movlw   LCD_8BIT
      CALL    OUT2LCD_INST

    ;Turns display off / cursor off / blinck off
    ;B 0000 1000
      movlw   LCD_DISABLE
      CALL    OUT2LCD_INST

    ;Clears display and set address 0 of RAM
    ;B 0000 0001
      movlw   LCD_CLEAR
      CALL    OUT2LCD_INST
      CALL    WAIT2MS       ;LCD_CLEAR need more wait to execute

    ;Set Cursor to move Increment / No shift
    ;B 0000 0110
      movlw   LCD_MODESET
      CALL    OUT2LCD_INST

  ;--- END HITACHI INITIALIZING SPECIFICATION FOR LCD ----

    ;Turns display on / cursor off / blinck off
    ;B 0000 1100
      movlw   LCD_ENABLE
      GOTO    OUT2LCD_INST
    ;RETURN goto will return ! same as return save place
;
;  end  ***********************************************************************
;


;******************************************************************************
;
; OUT2LCD_INST & OUT2LCD_DATA
; ---------------------------
;
; Output character or instruction in W to LCD
;
; For all OUT2LCD_DATA we must wait 37000ns
;
; For all OUT2LCD_INST expect below we must wait 37000ns
;   for RETURN_TOHOME and CLEAR_DISPLAY we must wait 1,520,000ns
;
; Corrupts: count and tmp.
;******************************************************************************
;

OUT2LCD_INST
      bsf     _INSTLCD  ;Change to instruction send
      GOTO    POUT2LCD

OUT2LCD_DATA
      bcf     _INSTLCD  ;Change from instruction to data send

POUT2LCD
      movwf   tmp
      movlw   008H
      movwf   count

NEXTOUT
      bcf     OUT_LCDCLOCK
      GOTO    $+1
      bcf     OUT_LCDDATA
      rlf     tmp,F
      btfsc   STATUS, C  ;Check bit state skip if it is 0
      bsf     OUT_LCDDATA
      GOTO    $+1
      bsf     OUT_LCDCLOCK
      decfsz  count, F      
      GOTO    NEXTOUT    ;Go to send next bit

      btfsc   _INSTLCD ; OUT_LCDCLOCK is used for Instruction/Data switch
      bcf     OUT_LCDCLOCK
      GOTO    $+1

LCDSTROBE
    ;use this to repeat last operation again !
      bsf     OUT_LCDSTROBE       ;enable LCD to read operation
      GOTO    $+1                 ;wait LCD to do its job
      bcf     OUT_LCDSTROBE       ;disable LCD to read operation
    
    ;--- from here LCD starts to execute operation                 ---
    ;--- so we need to wait it to finish him before next operation ---

      movlw   OUT2LCD_DELAY_TIME  ;Wait for data and instructions
      movwf   delay1
      decfsz  delay1,F
      GOTO    $-1

      RETURN
;
;  end  ***********************************************************************
;


;******************************************************************************
;
; Delay functions
;
; For 20Mhz
;   1 instruction - 200ns
;   1 call/goto instruction - 400ns
;
; For 10Mhz
;   1 instruction - 400ns
;   1 call/goto instruction - 800ns
;
; Here is formula to calculate each iterations call
;
; (767*(delay2-1) + 766)
;  + 2 (call to WAITXXXLC)
;  + 2 (init delay2)
;  + 2 (goto delay2LOOP)
;  + 2 final RETURN)
;
; 1ns = 10^-9s
; 1mcrs = 10^-6s
; 1ms = 10^-3s
;
; Names are for 20Mhz
;
; delay2 = 255 -> (iters 195592) (10Mhz 78,236,800ns) (20Mhz 39,118,400ns)
;
WAIT1MS         
        movlw   .7          ;(iters 5376) (10Mhz 2,150,400ns) (20Mhz 1,075,200ns)
WAITWMS
        movwf   delay2
        GOTO    DELAY2LOOP

WAIT2MS         
        movlw   .13         ;(iters 9978) (10Mhz 3,991,200ns) (20Mhz 1,995,600ns)
        movwf   delay2
        GOTO    DELAY2LOOP

WAIT5MS         
        movlw   .33         ;(iters 25318) (10Mhz 10,127,200ns) (20Mhz 5,063,600ns)
        movwf   delay2
        GOTO    DELAY2LOOP

DELAY2LOOP      ;(767*(delay2-1) + 766) iterations (without return)

#ifdef DEBUG_NODELAYS
        RETURN        ;USE ONLY FOR DEBUG
#endif
        movlw   .255
        movwf   delay1

DELAY1LOOP
        decfsz  delay1,F
        GOTO    DELAY1LOOP

        decfsz  delay2,F
        GOTO    DELAY2LOOP

        RETURN
;
;  end  ***********************************************************************
;

Datasheets

More Info

This post is licensed under CC BY 4.0 by the author.