PDA

View Full Version : How do you drive a Serial LCD?



Mike, K8LH
- 1st December 2011, 13:25
How do you drive a Serial LCD in PBP? Do you use the DEBUG command? Also, do Serial LCDs recognize the 0xFE character to set the LCD "RS" bit to 0 for the next character?

TIA Gentlemen. Happy Holidays everyone.

Cheerful regards, Mike

HenrikOlsson
- 1st December 2011, 14:08
Hi Mike,
You can use DEBUG, SEROUT, SEROUT2 or HSEROUT. DEBUG generates the smallest code but is the least flexible one. As for recognizing 0xFE you'd have to check the datahseet/manual for the particular serial LCD you're using regarding how you switch between command and data. I imagine they can have slightly different features/command sets depending on manufacturer etc.

/Henrik.

mackrackit
- 1st December 2011, 14:17
This data sheet has a Basic Stamp example
http://www.seetron.com/docs/bpp440mnl.pdf

Mike, K8LH
- 1st December 2011, 15:16
Hi Henrik,

But which of those functions would provide the most compatibility with the LCDOUT command? I assumed you would use DEBUG because it has data formatting options which are similar to LCDOUT.

What I'm trying to do is make a Serial LCD Backpack that would easily support PBP and I thought that if my LCD Backpack recognized the 0xFE character it might make it easier to take an existing PBP program and convert it for use with the Serial LCD Backpack by swapping out the LCDOUT keyword with the DEBUG keyword (leaving instruction operands intact).

Cheerful regards, Mike

mackrackit
- 1st December 2011, 15:18
http://www.picbasic.co.uk/forum/content.php?r=171-LCD-serial-backpacks

HenrikOlsson
- 1st December 2011, 15:51
Aah, you're MAKING one, OK.
That would be DEBUG, SEROUT2 and HSEROUT as they all support the same modifiers such as DEC, SDEC etc. DEBUG produces smaller code since its parameters are set at compiletime (with DEFINEs) while SEROUT2 uses runtime setable parameters.

For your backpack, select a PIC with USART and use HSERIN to capture the incomming data. Check mackrackits link as well!

Mike, K8LH
- 1st December 2011, 16:29
Henrik,

Thank you! That's the info' I was looking for.


For your backpack, select a PIC with USART and use HSERIN to capture the incoming data.

This version of my Serial LCD Backpack uses a 12F683 and an assembly language program. While building a prototype board a couple weeks ago for the new 8 pin, 14 pin, and 20 pin "enhanced" mid-range devices, I decided to add my old Serial LCD Backpack circuit onto the extra space at the bottom of the board (see silkscreen below). In the picture below, a 16F1823 is driving the backpack circuit at 57600 baud (one pin "overhead" on the 16F1823).


Check mackrackits link as well!

I checked the link (thanks Dave) but it's not really what I was looking for.

Thanks guys... Happy Holidays!

Cheerful regards, Mike

Archangel
- 4th December 2011, 09:27
OOPs my bad posted what Dave did. It does use the LCDOUT syntax though . . .

Heckler
- 4th December 2011, 23:37
Hey Mike K8LH,

Nice looking board... I have several of the 12F683 PIC's laying around and a couple of LCD's that they would go nicely with... I am amazed that you had enough pins to drive the LCD and receive serial data.

would you be willing to share your schematic and code??

Thanks in advance

Mike, K8LH
- 5th December 2011, 01:44
Hi Dwight,

I attached the schematic below but I'm afraid the interface in its present form is not very PBP friendly. It was the only way I knew of at the time to control six (6) pins on an LCD with only five (5) PIC output pins. That means you have to drive the display by sending two serial bytes for each LCD byte, each serial byte containing four data bits and an RS bit.

The new design that I'm working should be done soon. It uses full eight bit bytes and recognizes the $FE character (for toggling an RS flag).

Regards...

Heckler
- 5th December 2011, 21:51
Thanks Mike,

That was quite innovative of you to use the incomming data to both talk to the PIC and control the RS line of the LCD!!

nice work.

So is your new design going to use a differend PIC with more I/O pins??

Dwight

Mike, K8LH
- 7th December 2011, 02:31
So is your new design going to use a differend PIC with more I/O pins?

I'm upgrading the interface that uses the 8 pin PIC and actually studying another two slightly more advanced designs.

If you're interested, I've attached the source (assembler) for the 12F635 backpack as well as the source (also assembler) for the 16F1823 on that prototype board. This is the old software and, as I mentioned, probably not very useful for PBP users who are used to having all those wonderful LCD output formatting capabilities.

Happy Holidays! Mike

Mike, K8LH
- 9th December 2011, 18:37
Hi Dwight (and gang),

If you're interested... I just finished testing the upgrade to the 8-pin PIC serial LCD interface and it works great. The mod involved adding an RC integrator/filter (10K + 330pF) between the GP0/D4 pin and the LCD RS pin. Now I can drive all six LCD control pins directly from the little 8-pin PIC which means I can collect serial data, analyze it, and write data to the LCD display any way I want. In short, you should be able to feed the serial interface using the DEBUG, SEROUT2 or HSEROUT commands with all of the same formatting parameters you're using now with the LCDOUT command. I'm pretty geeked (yes, I'm a nerd - LOL).

If anyone is interested, I'll start a new thread in the 'schematic' sub-forum after characterizing and testing the firmware. The only real advantages I can think of for this interface is its size (very small footprint on a project board when using the 2x5 header for a MikroE LCD Adapter (http://www.mikroe.com/eng/products/view/145/lcd-adapter-board/) board) and its ability to drive four lines of a switch matrix (one additional pin on the host can read four switches, an encoder, etc.).

Cheers, Happy Holidays, Mike

Mike, K8LH
- 13th December 2011, 04:11
Drawing of the updated backpack hardware...

BobK
- 13th December 2011, 23:16
Hi Mike,

Mind if I ask what program you are using to illustrate your drawings?

Thanks,

BobK

Mike, K8LH
- 14th December 2011, 12:04
Greetings BobK.

The drawings were made using the drawing tools in Excel...

The paper silkscreen on the Radio Shack prototyping board was a printout of the silkscreen layer from DipTrace. The paper silkscreen is laminated with plastic tape and glued onto the board.

Cheerful regards, Mike

Mike, K8LH
- 8th October 2018, 02:40
Better late than never? Here's firmware for the 12F683 version of the serial backpack.

Cheerful regards, Mike


;************************************************* *****************
; *
; 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

Archangel
- 9th October 2018, 07:26
Thanks Mike ! Always another way to get there, I like smaller, cheaper PIC too.

Ioannis
- 18th October 2018, 13:34
I admire your courage to do this in assembly!

Ioannis

sayzer
- 18th October 2018, 19:28
I admire your courage to do this in assembly!

Ioannis

Same here.

This is a very nice work and, even more, Mike shares it here.

Thanks to Mike from this part of the world.