PIC16 Code to drive a HD44780 display over SPI, using a HC595
; Sample to drive a HD44780 LCD over SPI, using a 74HC595 shift register
; See: https://highfieldtales.wordpress.com/2011/12/04/very-fast-spi-to-parallel-interface-for-netduino/
;
; PIC 74HC595 HD44780
; 15 D4
; 1 D5
; 2 D6
; 3 D7
; 4 RS
; 5 RW
; 6 E
; 7
; 9 - 12
; 10
; CLK 11
; 12 - 9
; 13 - GND
; DAT 14
;
; The SS port resets the shift register, via an inverter
list P=16F876A
#include p16f876a.inc
__CONFIG _CP_ALL & _DEBUG_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC
#define SS_PORT PORTB
#define SS PORTB,1
RES_VECT CODE 0x0000 ; processor reset vector
GOTO START ; go to beginning of program
; TODO ADD INTERRUPTS HERE IF USED
MAIN_PROG CODE ; let linker place main program
START
banksel TRISC ; Set up pins for SPI
bcf TRISC,5 ; Data pin 16
bcf TRISC,3 ; Clock pin 14
bsf TRISC,4 ; Data in
clrf TRISB
banksel SSPCON ; Set up SPI
bcf SSPCON,5 ; Disable SPI
movlw b'00010000'
movwf SSPCON
movlw b'11000000' ; 1 = Input data sampled at end of data output time
; 1 = Transmit occurs on transition from active to Idle clock state
movwf SSPSTAT ;
bsf SSPCON,4 ; CKP 1 = Idle state for clock is a high level
bcf SSPCON,0 ; 0000 = SPI Master mode, clock = FOSC/4
bcf SSPCON,1
bcf SSPCON,2
bcf SSPCON,3
bsf SSPCON,5 ; SSPEN 1 = Enables serial port and configures SCK, SDO, SDI, and SS as serial port pins
call init_lcd
loop:
GOTO loop ; loop forever
init_lcd
; Remember to init ports!
; Initialise HD44780 for 4-bits, 2 lines
call Delay_100ms ; 100ms, step 1
banksel FLAGS
movlw 0 ; Command
movwf FLAGS
movlw B'00110000' ; initialise module, step 2
call lcd_byte
call Delay5ms ; > 4.1ms
movlw B'00110000' ; initialise module, step 3
call lcd_byte
call Delay100us ; > 100us
movlw B'00110000' ; initialise module, step 4
call lcd_byte
call Delay100us ; > 100us
movlw B'00100000' ; initialise module, step 5
call lcd_byte
call Delay100us ; > 100us
;x3 goto x3 ; Step 6, the real function select
movlw B'00101100' ; display function (4-bits, 2 lines, 5x10 dots)
call lcd_byte
call Delay100us ; > 53us
movlw B'00001000' ; Step 7, display on/off
call lcd_byte
call Delay100us ; > 53us
movlw B'00000001' ; Step 8, display clear
call lcd_byte
call Delay5ms ; > 3ms
; |- 0 = Display off, 1 = display on
; |- 0 = 1 line, 1 = 2 line
movlw B'00000110' ; Step 9, entry mode. cursor moves right, display not shifted
call lcd_byte
call Delay100us ; > 53us
; Actual init ends here
; |- 0 = Display off, 1 = Display on
; |- 0 = Cursor off, 1 = Cursor on
; |- 0 = Blink off, 1 = Blink on
movlw B'00001111' ; display on, cursor on, blink on
call lcd_byte
call Delay100us ; > 53us
; Init done, stuff below is just for testing.
banksel FLAGS
movlw 1 ; Data
movwf FLAGS
movlw 'A'
call lcd_byte
movlw 'B'
call lcd_byte
movlw 'C'
call lcd_byte
xy movlw 'D'
call lcd_byte
call Delay_100ms
movlw 'E'
call lcd_byte
return
; Send byte in W to LCD as command or data, depending on FLAGS
; 0 in flags as command or 1 as data
lcd_byte
banksel D_STO
movwf D_STO
swapf D_STO,w ; Swap high and low nibbles, result in W
andlw b'00001111' ; Mask out
call lcd_push_nibble ; Push high nibble
banksel D_STO
movf D_STO,w ; get byte
andlw b'00001111' ; Mask ou
call lcd_push_nibble ; Push low nibble
call Delay100us ; > 100us delay
return
; Push high nibble in w as data or cmd
; Input: Nibble in W, 0 in flags as command or 1 as data
lcd_push_nibble ; Push high nibble in w as data or cmd
btfsc FLAGS,0 ; flag set=data, set Q4 in that case
iorlw b'00010000'
; Not set leave as is
iorlw b'10000000' ; Set high bit
call send_w_on_spi ; Send nibble, E is still low
iorlw b'11000000' ; Set E bit
call send_w_on_spi ; Send nibble, E is high
andlw b'10111111' ; E -> low
call send_w_on_spi ; Send nibble, E is low
return
send_w_on_spi
;banksel SS_PORT
bcf SS ; Assert SS (low)
movwf SSPBUF ; begin transmission
WAIT btfss PIR1, SSPIF ; send completed? if Yes skip next
goto WAIT
bcf PIR1, SSPIF ; yes, clear flag
;banksel SS_PORT
bsf SS ; Unassert SS (high)
return
;-----------------------------------------------
; Delay = 0.0001 seconds
; Clock frequency = 20 MHz
; Actual delay = 0.0001 seconds = 500 cycles
; Error = 0 %
Delay100us
;banksel STORE1
;499 cycles
movlw 0xA6
movwf STORE1
Delay100us_0
decfsz STORE1, f
goto Delay100us_0
;1 cycle
nop
return
;-----------------------------------------------
; Delay = 0.005 seconds
; Clock frequency = 20 MHz
; Actual delay = 0.005 seconds = 25000 cycles
; Error = 0 %
Delay5ms
;banksel STORE1
;24998 cycles
movlw 0x87
movwf STORE1
movlw 0x14
movwf STORE2
Delay5ms_0
decfsz STORE1, f
goto $+2
decfsz STORE2, f
goto Delay5ms_0
;2 cycles
goto $+1
return
Delay_100ms
;-----------------------------------------------
; Delay = 0.1 seconds
; Clock frequency = 20 MHz
; Actual delay = 0.1 seconds = 500000 cycles
; Error = 0 %
banksel STORE1
;499994 cycles
movlw 0x03
movwf STORE1
movlw 0x18
movwf STORE2
movlw 0x02
movwf STORE3
Delay_100ms_0
decfsz STORE1, f
goto $+2
decfsz STORE2, f
goto $+2
decfsz STORE3, f
goto Delay_100ms_0
;6 cycles
goto $+1
goto $+1
goto $+1
return
udata
STORE1 res 1
STORE2 res 1
STORE3 res 1
FLAGS res 1
D_STO res 1
END
file: /Techref/io/lcd/dh44780_spi_hc595.htm, 5KB, , updated: 2016/11/9 08:25, local time: 2025/2/4 22:15,
owner: AWG-PIA-TA5,
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/Techref/io/lcd/dh44780_spi_hc595.htm"> PIC16 Code to drive a HD44780 display over SPI, using a HC595</A> |
Did you find what you needed?
|