bobledoux said:
Mike,
I saw this concept earlier, but I didn't have time to study the code and concept. If I read you correctly,
1. You are running an LCD that requires a minimum of six I/O pins with a PIC that only has six I/O pins.
2. GP3 is both the RS control and serial input.
3. You raise the E line to write to the LCD, which is normal.
4. You prefer MS Excel Pink for your color background.
Explain the RS function more. I'm also confused by the data lines to the host PIC, that appear to by a parallel, 4 bit, input
Hi Bob,
1) Yes, I'm driving an LCD that requires 6 signals minimum from a PIC with only 5 outputs
2) Yes, the serial signal on GP3 provides the LCD with the 'RS' register select signal during the 'E' pulse.
3) Yes, qualified by the CX bit (b6) which when CX=1 doesn't produce the 'E' pulse and so doesn't write the LCD
4) Yes, pink is "in" (grin)
The LCD 'RS' register select pin is used to select 'command' or 'data' LCD registers during an LCD write operation. This LCD interface design requires the Host to send each byte of data as two serial bytes which contain nybble data in b3:b0 and the 'RS' register select bit in b7;
send '0000 nnnn' to write nybble 'nnnn' to LCD RS0 (LCD command register)
send '1000 nnnn' to write nybble 'nnnn' to LCD RS1 (LCD data register)
This means we need a small (12 word) low-level driver on the Host to send each byte as two serial
nybble+rs bytes to the LCD interface;
Code:
;******************************************************************
;
; Host low level LCD interface driver
;
PutCmd
clrf mask ; mask = '00000000' (RS=0) |B0
skpz ; |B0
PutDat
bsf mask,7 ; mask = '10000000' (RS=1) |B0
movwf Temp ; save data |B0
call PutNyb ; send right nybble + RS bit |B0
swapf Temp,W ; send left nybble + RS bit |B0
PutNyb
andlw 0x0F ; mask off left nybble |B0
iorwf mask,W ; copy RS bit into WREG bit 7 |B0
PutSer
btfss PIR1,TXIF ; UART transmit buffer empty? |B0
goto PutSer ; no, branch and wait, else |B0
movwf TXREG ; send it |B0
return ; |B0
;******************************************************************
We also need to use Host macros and code which are aware of the LCD 'command' and 'data' registers;
Code:
radix dec
;******************************************************************
;
; Host program example macro usage
;
Line1 equ 128 ;
Line2 equ 128+64 ;
Line3 equ 128+20 ;
Line4 equ 128+64+20 ;
;
PutLCD cmd,0x20 ; setup 4 bit interface
PutLCD cmd,0x0C ; display on, cursor off
PutLCD cmd,Line1+10 ; lcd line 1, htab 10
PutLCD str,"GMT" ;
PutLCD cmd,Line2+10 ; lcd line 2, htab 10
PutLCD dat,'?' ;
PutLCD cmd,0x10 ; cursor shift left
PutLCD cmd,0x0F ; cursor on (blink)
;******************************************************************
Code:
;--< macro definitions >-------------------------------------------
cmd equ 1 ; single byte command/control type
dat equ 2 ; single byte character/data type
str equ 3 ; multi-byte string character type
PutLCD macro ptype,pdata
if ptype == cmd ; generates 2 words
movlw pdata ;
call PutCmd ; send with RS=0
endif
if ptype == dat ; generates 2 words
movlw pdata ;
call PutDat ; send with RS=1
endif
if ptype == str ; generates 6 words + inline table
local string,done
movlw low(string) ;
movwf PtrL ;
movlw high(string) ;
movwf PtrH ;
call PutStr ;
goto done ;
string dt pdata,0 ; inline table, 0 terminated
done
endif
endm
I defined the 'CX' control bit as bit 6 in the serial
nybble+rs bytes. This allows me to use the D4..D7 lines to drive a column driven switch matrix in-between LCD write operations. The host would send one of the following bytes to setup the column lines before reading its switch input pin(s) which you see on the left side of the matrix.
send '0100 1110' to set column 0 active low
send '0100 1101' to set column 1 active low
send '0100 1011' to set column 2 active low
send '0100 0111' to set column 3 active low
You would need one Host switch input pin for every four switches or jumpers installed on the LCD interface board.
I use interrupt-on-change to detect the start bit leading edge and trigger the (untested) ISR on the LCD interface PIC;
Code:
;******************************************************************
;* Interrupt Vector *
;******************************************************************
org 0x0004
b0 uDelay (bTime/3) ; delay 1/3 bit time |B0
uDelay (bTime-3) ; delay bit time - 3 cycles |B0
bcf D4 ; clr LCD 'D4' pin (GP0) |B0
btfsc SerPin ; bit '0'? yes, skip, else |B0
bsf D4 ; set LCD 'D4' pin |B0
b1 uDelay (bTime-3) ; |B0
bcf D5 ; clr LCD 'D5' pin (GP1) |B0
btfsc SerPin ; bit '0'? yes, skip, else |B0
bsf D5 ; set LCD 'D5' pin |B0
b2 uDelay (bTime-3) ; |B0
bcf D6 ; clr LCD 'D6' pin (GP2) |B0
btfsc SerPin ; bit '0'? yes, skip, else |B0
bsf D6 ; set LCD 'D6' pin |B0
b3 uDelay (bTime-3) ; |B0
bcf D7 ; clr LCD 'D7' pin (GP4) |B0
btfsc SerPin ; bit '0'? yes, skip, else |B0
bsf D7 ; set LCD 'D7' pin |B0
b4 uDelay (bTime) ; ignore bit 4 |B0
b5 uDelay (bTime) ; ignore bit 5 |B0
b6 uDelay (bTime-3) ; test CX bit (lcd or non-lcd) |B0
clrf Emask ; assume non-lcd latch byte |B0
btfss SerPin ; bit '1'? yes, skip, else |B0
bsf Emask,5 ; setup 'E' pulse bit |B0
b7 uDelay (bTime-3) ; pulse 'E' during 'RS' data bit |B0
movf Emask,W ; get mask 00000000 or 00100000 |B0
iorwf GPIO,F ; pulse 'E' (or not) |B0
xorwf GPIO,F ; force 'E' pin low |B0
st uDelay (bTime-3) ; within middle 1/3 of stop bit |B0
movf GPIO,W ; read GPIO port |B0
bcf INTCON,RAIF ; clr IOC interrupt flag bit |B0
retfie ; |B0
Take care. Mike