PIC16 Controlling LCD

PIC16 Controlling LCD

Here you will find source code and schematic for controlling LCD based on Hitachi HD44780U with Microchip PIC16 microcontrollers using only 3 I/O ports.

To achieve that we use 8-Bit Serial-Input/Parallel-Output Shift Register 74HC164.

The I/O ports used for controlling are:

  • Clock
  • Data
  • LCD Enable

The Clock and Data ports can be shared with other peripheral devices.

The code is designed with minimum ASM instructions so to be as small as possible, especially for microcontrollers with less instruction memory.

Schematic

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

Code

Download the source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
;******************************************************************************
;   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

Leave a reply

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.