![]() |
![]() |
![]() |
|
|
|||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
|
|
Thread Tools | Display Modes |
|
|
(permalink) |
|
Hi guys,
I just hooked up a 44780 type LCD to a PIC for the first time a few days ago. No big deal, right? Well, I haven't worked with a 44780 type LCD in about 10 years (on a 68HC12 project) so it was pretty exciting for me when it came to life on the first try (grin). I'm sure all of you know that feeling. Anyway, I was wondering if anyone was interested in my approach for the 44780 subsystem code (in assembler)? The subsystem is relatively small and includes a PutLCD macro with 'type' and 'data' parameters, an InitLCD subroutine to reset the LCD and place it in 4 bit interface mode, and a low level driver. I'm also using my little 12 word DelayCy() subsystem for LCD write delays because it's easy to setup for almost any clock frequency. The PutLCD macro only supports five different 'type' parameters at the moment (more to come) but I'm very pleased with it's capabilities so far. The macro automatically sets the LCD 'RS' line before calling the low level driver and it also selects the appropriate LCD write time delay after a write operation (it knows to use a 1.53 msec delay after a Clear or Home command, for example). Here's an example to illustrate how I'm using the macro and subsystem; What do you think? Mike Code:
;
; 44780 "function set" bit masks
;
m8bits equ b'00110000' ; select 8 bit interface
m4bits equ b'00100000' ; select 4 bit interface
m1line equ b'00100000' ; select 1 line display
m2line equ b'00101000' ; select 2 line display
fon5x7 equ b'00100000' ; select 5x7 font
;******************************************************************
; *
; init 2x16 LCD using the 44780 procedure for a 4 bit interface *
; *
InitLCD
DelayMS(15) ; wait 15 msecs after power up |B0
PutLCD nyb, m8bits ; step 1, 8 bit reset (160 usec) |B0
DelayMS(4) ; wait 4.1 msecs total, then |B0
PutLCD nyb, m8bits ; step 2, 8 bit reset (160 usec) |B0
PutLCD nyb, m8bits ; step 3, 8 bit reset (160 usec) |B0
PutLCD nyb, m4bits ; set 4 bit mode from 8 bit mode |B0
PutLCD cmd, m4bits|m2line|fon5x7 ; "function set" |B0
PutLCD cmd, DispOff ; display, cursor, blink all off |B0
PutLCD cmd, Clear ; clear display (1.53 msecs) |B0
PutLCD cmd, CursInc ; cursor inc, shift off |B0
PutLCD cmd, DispOn ; display on, leave cursor off |B0
PutLCD pwm, 100 ; set 100% backlight brightness |B0
return ; |B0
Code:
;******************************************************************
; *
Main
call InitLCD ; initialize LCD subsystem |B0
PutLCD cmd, line1+0 ; line 1, tab 0 |B0
PutLCD str, "K8LH Photo Timer"
PutLCD cmd, line2+0 ; line 2, tab 0 |B0
PutLCD str, "Off 00:00:23.750"
|
|
|
|
|
|
|
(permalink) |
|
I bought the same one, to display a 5 digit number.
Leaving me room for another 5 digit below the first one. That's my next project. |
|
|
|
|
|
|
(permalink) |
|
New development..... K8LH 12F635 Serial 1-Pin 44780 LCD Interface
Late tonight I got an 8 pin 12F635 device working as a Serial 1 Pin 44780 LCD Interface at 19200 baud. The host was a 16F690 device. As far as I know, no one has used an 8 pin PIC with only 5 outputs to drive a 44780 type LCD which needs six signals, so I'm pretty geeked. Basically, I tied the serial Rx line to the PIC and to the 'RS' line on the LCD. The LCD ignores the signals on any of its control lines until it receives an 'E' strobe so I simply latch the D7..D4 data bits onto the PIC outputs as they arrive in the serial bit stream and I provide the 'E' pulse to the LCD during the middle of the 'RS' bit as it arrives in the serial bit stream. I should mention that I send each 8 bit data byte as two separate serial bytes so I use a custom low level driver on the 16F690 host device. I've attached the 12F635 source file for those who may be interested and I'll follow up with an example host side low level driver in a couple days. Have fun. Mike |
|
|
|
|
|
|
(permalink) | |
|
Quote:
__________________
========================= Futz's Microcontrollers & Robotics ========================= |
||
|
|
|
|
|
(permalink) |
|
Hi Mike,
Re your initial post about your parallel Lcd code, I for one would be interested to see more of your code, the PutLcd macro and Low Level Driver ? - sound very interesting. I'm always looking for a more compact lcd code than the one I've always used from Ron Kreymborg thanks Richard |
|
|
|
|
|
|
(permalink) |
|
Hi Richard,
Thank you for expressing an interest. I'm not sure my subsystem code will be more compact than what you're using now. I modified the low-level driver last night so it's a bit messy. It now supports an LCD connected either directly with 6 pins or connected via the serial port to that little 12F635 serial LCD interface. This is what it looks like at the moment; Code:
;******************************************************************
; K8LH low level 44780 LCD driver (LCD in 4 bit interface mode) *
; *
; this driver supports either the "K8LH Serial 1-Pin Interface" *
; using the serial port or "direct" connection to the LCD using *
; using six lines. the "direct" connection requires LCD D7..D4 *
; lines connected to either the 7..4 bits or the 3..0 bits on a *
; port. the LCD RS and E lines can be connected to a different *
; port or the same port. *
; *
;******************************************************************
;
; driver type definitions
;
LoBits equ 0 ; D7..D4 lines on port pins 3..0
HiBits equ 1 ; D7..D4 lines on port pins 7..4
Serial equ 2 ; K8LH 1-Pin Serial Interface
;
; user must specify driver type from the selections above
;
drvtype equ Serial ; specify driver type from list
;
; the following defines are required when not using the "Serial"
; driver type
;
#define LCD_RS PORTC,4 ; RC4 -----> LCD RS
#define LCD_E PORTC,7 ; RC7 -----> LCD E
#define LCD_Dat PORTC ; RC3..RC0 > LCD D7..D4
;
; WREG contains byte to be written to LCD
;
PutCmd ; entry point for "cmd" data
clrc ; RS = 0 (command) |B0
skpnc ; |B0
;
; WREG contains byte to be written to LCD
;
PutDat ; entry point for "dat" data
setc ; RS = 1 (data) |B0
movwf Temp ; save WREG data byte |B0
if drvtype != Serial ; if 'HiBits' or 'LoBits' driver
if drvtype == HiBits ; if 'HiBits' driver
call PutNyb ; send left nybble |B0
swapf Temp,W ; swap nybbles in W |B0
call PutNyb ; send right nybble |B0
else ; if 'LoBits' driver
swapf Temp,W ; swap nybbles in W |B0
call PutNyb ; send left nybble |B0
movf Temp,W ; |B0
call PutNyb ; send right nybble |B0
endif
DelayCy(tDef) ; default 40 usec delay |B0
return ; |B0
else ; if 'Serial' driver
swapf Temp,W ; |B0
call PutNyb ; send left nybble |B0
movf Temp,W ; send right nybble |B0
endif
PutNyb
if drvtype == Serial ; if K8LH 1-Pin Serial Interface
andlw 0x0F ; mask off left nybble |B0
skpnc ; RS = 0? yes, skip, else |B0
iorlw b'10000000' ; set RS bit to '1' |B0
btfss PIR1,TXIF ; UART transmit buffer empty? |B0
goto $-1 ; no, branch and wait, else |B0
movwf TXREG ; send it |B0
return ; |B0
else ; 'LoBits' or 'HiBits' driver
bcf LCD_RS ; clr LCD RS line (RS = 0) |B0
if drvtype == LoBits ; if 'LoBits' driver
andlw 0x0F ; mask off left nybble |B0
else ; if 'HiBits' driver
andlw 0xF0 ; mask off right nybble |B0
endif
movwf LCD_Dat ; setup LCD D7..D4 lines |B0
skpnc ; RS = 0? yes, skip, else |B0
bsf LCD_RS ; set LCD RS line (RS = 1) |B0
bsf LCD_E ; strobe LCD E line |B0
nop ; |B0
bcf LCD_E ; |B0
return ; |B0
endif
The "nyb" type is a special case and is used only in during LCD initialization to send a 4 bit nybble while the LCD is still in an 8-bit interface mode. I need to add a preprocessor directive to correctly format the data for both the Hi and Lo 'direct' interfaces. Anyway, the PutLCD macro needs much more work. It also needs some new "types" to support literal constant numbers and variable numbers and some simple conversions; bin2dec, bcd2dec, etc. This code is definately a work-in-progress and is provided simply to give you some food for thought. Caveat! Code:
;******************************************************************
; *
; PutLCD cmd, data ' send literal const data byte, RS = 0 *
; PutLCD dat, data ' send literal const data byte, RS = 1 *
; PutLCD dec, file ' future *
; PutLCD hex, file ' future *
; PutLCD bin, file ' future *
; PutLCD str, data ' send inline const string data, RS = 1 *
; PutLCD nyb, data ' send const b7..b4, 8 bit mode, RS = 0 *
; PutLCD pwm, 0..100 ' LCD backlight, 0..100% brightness *
; *
cmd equ 1 ; 1 byte command/control type
dat equ 2 ; 1 byte character/data type
dec equ 3 ; future
hex equ 4 ; future
bin equ 5 ; future
str equ 6 ; multi-byte string character
nyb equ 7 ; d7..d4 nybble in 8 bit mode
pwm equ 8 ; future
tab equ cmd ;
tClr equ 1530*usecs ; 1.53 msecs -> "clear" command
tHome equ 1530*usecs ; 1.53 msecs -> "home" command
tNyb equ 160*usecs ; 160 usecs --> for Nybble ops
tDef equ 40*usecs ; 40 usecs ---> all others
PutLCD macro pType,pData
if pType == cmd ;
movlw pData ; W = literal const pData |
call PutCmd ; send to RS = 0 + tDef delay |
if (pData) == Clear ; if "clear" command
DelayCy(tClr-tDef) ; use 1.53 msec delay |
endif ;
if (pData) == Home ; if "home" command
DelayCy(tHome-tDef) ; use 1.53 msec delay |
endif ;
endif
if pType == dat ;
movlw pData ; W = literal const pdata
call PutDat ; send with RS=1
endif
if pType == dec ;
movf pData,W ; Wreg = variable
iorlw '0' ; 0..9 -> ASCII "0..9"
call PutDat ; send with RS=1
endif
if pType == str ;
local string,doit
goto doit
string dt pData,0 ; null terminated string table
doit movlw low(string) ;
movwf PtrL ;
movlw high(string) ;
movwf PtrH ;
call PutStr ;
endif
if pType == nyb ; ** note to self: fix this code **
clrc ; RS = 0 (command)
movlw pData>>4 ; put b7..b4 bits in b3..b0
call PutNyb ; send nybble from 8 bit mode
DelayCy(tNyb) ; delay 160 usecs
endif
if pType == pwm ;
nop ; future
endif
endm
;******************************************************************
; *
; LCD PutStr subroutine *
; *
PutStr
call GetTable ; get a table character |B0
andlw b'11111111' ; |B0
skpnz ; 00 byte, last character? |B0
return ; yes, return, else |B0
call PutDat ; output character |B0
incf PtrL,F ; increment pointer |B0
skpnz ; |B0
incf PtrH,F ; |B0
goto PutStr ; |B0
GetTable
movf PtrH,W ; |B0
movwf PCLATH ; |B0
movf PtrL,W ; |B0
movwf PCL ; |B0
You're welcome to send me a PM if you'd like updates as the code evolves. Regards, Mike |
|
|
|
|
|
|
(permalink) |
|
Hi Mike,
Thanks for sharing the code - sure looks some fancy coding in there ! I will copy it over a give it a try on my own little dev board and let you know how it goes. ( my existing delays should modify to match your code ok) thanks again Richard |
|
|
|
|
|
|
(permalink) |
|
Richard,
You're welcome. Let me know if you find anything useful in that mess? Mike ------------- BTW, here's a hard coded low level driver for the "12F635 Serial LCD Interface". This would be the code produced from the conditional assembly instructions in that previous listing when you use the "Serial" option. Hopefully this code is a little easier to analyze for those people interested in playing with the interface. Code:
;******************************************************************
; K8LH low level 44780 LCD driver (12F635 Serial LCD Interface) *
;******************************************************************
PutCmd ; entry point for "cmd" data
clrc ; RS = 0 (command) |B0
skpnc ; |B0
PutDat ; entry point for "dat" data
setc ; RS = 1 (data) |B0
movwf Temp ; save WREG data byte |B0
swapf Temp,W ; |B0
call PutNyb ; send left nybble |B0
movf Temp,W ; send right nybble |B0
PutNyb
andlw 0x0F ; mask off left nybble |B0
skpnc ; RS = 0? yes, skip, else |B0
iorlw b'10000000' ; set RS bit to '1' |B0
btfss PIR1,TXIF ; UART transmit buffer empty? |B0
goto $-1 ; no, branch and wait, else |B0
movwf TXREG ; send it |B0
return ; |B0
;******************************************************************
Last edited by Mike, K8LH; 23rd May 2008 at 03:43 AM. |
|
|
|
|
|
|
(permalink) |
|
My novelty 12F635 Serial LCD Interface is now working at 57600 baud.
It didn't come up on the first try but then I realized I had a 3.68% bit rate error when I setup the host 16F690 for 57600 baud using BRGH=1 and BRG16=0. There's also that 1% tolerance of the INTOSC to consider. The interface did come right up however after switching to BRGH=1 and BRG16=1 on the 16F690. That configuration produces a much more tolerable 0.8% bit rate error. Here's a picture of my LCD test board with 16F690 host driving the 12F635 interface at 57600 baud. Mike |
|
|
|
|