Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

LCD 2x16 Demo for the Unicorn (18F4550)

Status
Not open for further replies.

blueroomelectronics

Well-Known Member
Here's working code that was designed for the Unicorn in LCD mode (it also works with Oshonsofts 18F & LCD simulator) It will be part of the Unicorn assembly manual.

PS anyone have any decent asm formatters for posting?

**broken link removed**

Code:
    list    p=18F4550
    include <p18F4550.inc>
        CONFIG  FOSC = INTOSC_HS, WDT = OFF, LVP = OFF, PBADEN = OFF
#define LCD_E   LATE,2
#define LCD_RS  LATE,0
#define LCD_RW  LATE,1
#define LCD_BL  LATB,3
delay    equ    0
temp    equ    1
        org     0x000
        movlw    HIGH LCD_CC    ; high byte    
        movwf    TBLPTRH         ; pointer to table high order byte
        setf    ADCON1        ; all I/O digital
        bcf    TRISB, 3    ; LCD backlight control
        clrf    TRISD           ; LCD data output
        clrf    PORTE           ; LCD control
        clrf    TRISE
        clrf    LATE            ; zero output on E
        movlw   0x02        ; use internal osc
        movwf   OSCCON          ; 31.25KHz internal clock
; LCD soft reset (ignores/enables busy flag polling)
        movlw   .3              ; repeat sending 0x38 to reset LCD
        movwf    temp            ; loop counter
_init3  movlw   .131         ; 50ms delay
        movwf   delay           ; enter with delay in ms via W
        decfsz  delay
        bra     $-2        
        bsf     LCD_E           ; LCD enable bit high
        movlw   0x38            ; send 0x38 four times
        movwf   LATD            ; LCD = 0x38 (8 bit mode x 2 line)
        bcf     LCD_E           ; latches on High to Low transition
        decfsz  temp
        bra     _init3          ; repeat 3 times
        bsf     LCD_BL          ; turn on backlight
; load special charaters into LCD RAM using LCD busy flag
        movlw   b'01000000'     ; set LCD CG address to 00
        rcall   LCD_Ins         ; relative call
        clrf    temp
        movlw   LOW LCD_CC    ; pointer to custom charater table
        movwf   TBLPTRL
_nextcc tblrd*+                 ; get in-line string character
        movf    TABLAT,W        ; last character
        rcall   LCD_Chr         ; send the character into LCD RAM
        incf    temp
        btfss   temp, 6         ; 64 bytes total
        bra     _nextcc
; clear & enable LCD DRAM, no visible cursor
        movlw   0x0C            ; display on, cursor off
        rcall   LCD_Ins
; display top 16 characters
        movlw   0x01            ; clear display, home cursor
        rcall   LCD_Ins
        movlw   .16
        movwf   temp
        movlw   LOW Text_    ; low byte pointer
        movwf   TBLPTRL        ; point to first line of text
_top    tblrd*+                 ; get in-line string character
        movf    TABLAT,W        ; last character
        rcall   LCD_Chr
        decfsz  temp
        bra     _top
; display bottom 16 characters        
    movlw   0xC0        ; set cursor to second line
        rcall   LCD_Ins
        movlw   .16
        movwf   temp
_bot    tblrd*+                 ; get in-line string character
        movf    TABLAT,W        ; last character
        rcall   LCD_Chr
        decfsz  temp
        bra     _bot
        bra    $        ; endless loop done
; LCD entry routines watches busy flag
LCD_Chr bsf     LCD_RS          ; enable Charater mode
LCD_Ins bsf     LCD_E
        clrf    TRISD           ; make PORTD an output
        movwf   LATD        ; put data on LCD port
        bcf     LCD_E           ; latch byte to LCD
        bcf     LCD_RS
        setf       TRISD           ; make LCD port input
        bsf     LCD_RW          ; enter read mode
        bsf     LCD_E           ; enable LCD
_BusyFl btfsc   PORTD,7         ; wait for bit 7 to be pulled low
        bra     _BusyFl
        bcf     LCD_RW          ; return to Instruction mode
        return
; text to display
        org    0x0800
Text_   db      "blueroom      ",.0,.1
        db      "electronics   ",.2,.3
; *** 2x2 blueroomelectronics logo (house)
LCD_CC  db      .128,.128,.129,.131,.135,.143,.159,.159
        db      .128,.128,.128,.144,.152,.156,.158,.130
        db      .159,.159,.159,.145,.145,.145,.159,.128
        db      .130,.130,.158,.130,.130,.130,.158,.128
    END
 
Last edited:
Do you still have Just BASIC installed on your system? If so, I'll send you a "formatter" program I wrote that inputs an ASM file or a C file and outputs it to a console window with space characters in place of the tab characters. Just select and copy text from the console window and paste it between code tags in your posts.

Here's "before" and "after" examples;

Code:
;******************************************************************
;*                                  *
;*  ScanPad, 4x4 Keypad              Mike McLaren, K8LH, Nov'07  *
;*                                  *
;*      RB3 RB2 RB1 RB0         <> requires PORTB weak pull-ups      *
;*  RB4 [0] [1] [2] [3]         <> returns Z=0 for a "new" key only  *
;*  RB5 [4] [5] [6] [7]         <> returns Z=1 when no keys pressed  *
;*  RB6 [8] [9] [A] [b]         or if same key is still pressed   *
;*  RB7 [C] [D] [E] [F]         <> isochronous (77 cycles)          *
;*                                  *
;*  the Keylat key state latch contains pressed key value 80..8F  *
;*  or 0 (no key pressed).  clear Keylat after getting a new key  *
;*  from ScanPad for "repeat key" operation (see example).      *
;*                                  *
;*  26 words, 77 instruction cycles (isochronous)          *
;*                                  *
ScanPad
    movlw    TRISB        ; address of TRISB in bank 1      |B0
    movwf    FSR        ; setup indirect access          |B0
    movlw    b'11110111'    ; setup column 0 (RB3) as output  |B0
    movwf    INDF        ; pseudo "movwf TRISB"          |B0
    clrf    Column        ; set keypad column offset = 0      |B0
    movlw    0        ; clear W              |B0
    setc            ; must shift 1 bits into TRISB      |B0
Code:
;******************************************************************
;*                                                                *
;*  ScanPad, 4x4 Keypad               Mike McLaren, K8LH, Nov'07  *
;*                                                                *
;*      RB3 RB2 RB1 RB0      <> requires PORTB weak pull-ups      *
;*  RB4 [0] [1] [2] [3]      <> returns Z=0 for a "new" key only  *
;*  RB5 [4] [5] [6] [7]      <> returns Z=1 when no keys pressed  *
;*  RB6 [8] [9] [A] [b]         or if same key is still pressed   *
;*  RB7 [C] [D] [E] [F]      <> isochronous (77 cycles)           *
;*                                                                *
;*  the Keylat key state latch contains pressed key value 80..8F  *
;*  or 0 (no key pressed).  clear Keylat after getting a new key  *
;*  from ScanPad for "repeat key" operation (see example).        *
;*                                                                *
;*  26 words, 77 instruction cycles (isochronous)                 *
;*                                                                *
ScanPad
        movlw   TRISB           ; address of TRISB in bank 1      |B0
        movwf   FSR             ; setup indirect access           |B0
        movlw   b'11110111'     ; setup column 0 (RB3) as output  |B0
        movwf   INDF            ; pseudo "movwf TRISB"            |B0
        clrf    Column          ; set keypad column offset = 0    |B0
        movlw   0               ; clear W                         |B0
        setc                    ; must shift 1 bits into TRISB    |B0
 
Last edited:
Here's the "Forum Code-Tag-Fix" program that I mentioned in the previous post for those who may be interested. It's written in Just BASIC, a free BASIC interpreter...

Code:
'
'  Forum Code-Tag-Fix v1.1 by Mike McLaren, K8LH
'
'  replaces <tab> characters with spaces (tabs = 8).  adds
'  an additional space character to lines beginning with a
'  space for Microchip Forum.  does not alter source file.
'
'  Instructions
'
'  1 - select your source file from the File Dialog
'  2 - select output text displayed in console window
'  3 - copy to clipboard using <ctrl-C> or <edit> <copy>
'  4 - paste between code tags in your Forum post
'
'  JustBASIC v1.01
'
   tabs = 8       ' 8 (assembly) or 4 (C)
   postmode = 0   ' 1, replace tabs, add leading space
                  ' 0, replace tabs only

   filedialog "Source File?", "*.asm", fileName$

   if fileName$ <> "" then
     open fileName$ for input as #f
     while eof(#f) > -1
       line input #f, aLine$ : hpos=1
       if postmode then
         if (left$(aLine$,1)=" ") then print " ";
         if (left$(aLine$,1)=chr$(9)) then print " ";
       end if
       for x = 1 to len(aLine$)
         if (mid$(aLine$,x,1)<>chr$(9)) then
           print mid$(aLine$,x,1); : hpos=hpos+1
         else
           while hpos MOD tabs <> 0
             print " "; : hpos=hpos+1
           wend
           print " "; : hpos=hpos+1
         end if
       next x
       print
     wend
     close #f
   end if
   end
 
Last edited:
blueroomelectronics said:
Here's working code that was designed for the Unicorn in LCD mode (it also works with Oshonsofts 18F & LCD simulator) It will be part of the Unicorn assembly manual.
Hey Bill. I wanna buy a second Unicorn (and some other stuff). How's Creatron's online order site coming along?
 
blueroomelectronics said:
Thanks Mike, I still have JustBASIC.

I think I'll just open an ebay store.

Now your talkin', time to join the 21 century :)

Lefty
 
Edit, I tried to upload a code tidier but I couldn't get the setup to work. Will try again later.

Mike.
 
Last edited:
Hi Bill,

I have a unicorn kit with me which I use with the inchworm+. Both the kits are working fine together.

I got myself an LCD recently and wanted to interface with the unicorn kit.

I compiled the asm from this thread and tested the LCD. Only the backlight comes on and nothing got displayed on the LCD.

The LCD spec is here; https://www.electro-tech-online.com/custompdfs/2008/02/char-comm.pdf

How should I go about tracing the problem?

Thanks!

Regards,
Thiruselvam
 
If it helps, here are pictures showing how mine is connected.

Mike.
Edit, that data sheet hasn't got the pinout. I do have one display where the connector is at the bottom. It might be wise to use a battery and resistor to find the backlight.
 
Last edited:
If you get the backlight that's a good start, make sure it's in the right way around as the + & gnd pins are mirrored so an upsidedown LCD will still light the backlight. Pin 1 on the LCD should have a #1 near.
Also you need the small jumper installed (J1) for your LCD, a GLCD you take off the jumper. Lastly try to adjust the contrast so you see a row of dark squares on the first display row.
 
That pinout is the same as mine and so you should place it the same. Have you checked the jumper as mentioned by Bill.

Mike.
 
That's a standard 20x4 LCD, you should adjust contrast till you see some dark squares on lines 1&2. You do need the jumper on J1.

**broken link removed**
 
Last edited:
I got it working!

I think it was because of the jumper and the contrast pot. Pot has to be fully turned clockwise.

Thanks guys!
 
Works also for me :) What I did after that: Replaced the PIC in Unicorn with 16F887 and modified the code to make it work again. (Configuration Junebug + Unicorn with PIC16F887 running on the 20MHz crystal). I can post the source if someone is interested.
What was tricky is the fact that when reading from the program memory on PIC16F887 it is necessary to insert 2 NOPs after setting the RD bit in EECON1 otherwise it does not work mysteriously but when debugging (single-stepping through the code) it does work correctly ...

Petr
 
Hi Bill,
actually the problem with NOPs is described in the datasheet. As you can see I have modified your source code, this is the last version and the one that actually works :) - if you have PIC16F887 you can try yourself.
I am designing a frequency counter and I'd like to use PIC16F886 and 16x2 LCD display so Unicorn with PIC16F887 seems as a good starting point to me.
Petr
Code:
;UNICORN LCD test, jumper on J1VEB, 8 bit mode with full handshaking
		list p=16F887
		include <p16F887.inc>
		__CONFIG	_CONFIG1, _HS_OSC & _WDT_OFF & _LVP_OFF & _DEBUG_ON	
;		CONFIG FOSC = INTOSC_HS, WDT = OFF, LVP = OFF, PBADEN = OFF
        errorlevel      -302,-305       

#define LCD_E 	PORTE,2
#define LCD_RS 	PORTE,0
#define LCD_RW 	PORTE,1
#define LCD_BL 	PORTB,3
#define LED_N	PORTC,1

                cblock  0x20
		msdelay:2 	
		delay
		temp 	
		endc

		org 	0

		banksel	ANSEL			; select BANK 3
		clrf	ANSEL
		clrf	ANSELH
		movlw	0x80			; prepare to read FLASH
		movwf	EECON1
		bcf		STATUS,RP0		; select BANK 3 -> BANK 2
		movlw	HIGH LCD_CC
		movwf	EEADRH
		banksel	TRISB			; select BANK 1
		bcf 	TRISB,3 		; LCD backlight control
		clrf 	TRISD 			; LCD data output
		clrf 	TRISE 			; LCD control outputs
		bcf		TRISC,1
		clrf	PSTRCON
		bcf		STATUS,RP0		; select BANK 0
		clrf 	PORTE 			; LCD E, RS, RW
		bsf		LED_N

; LCD soft reset (ignores/enables busy flag polling)
		movlw 	.4 				; repeat sending 0x38 to reset LCD
		movwf 	temp 			; loop counter
init3:	       movlw 	.50 			; delay > 50 ms
		movwf 	delay 			; enter with delay in ms via W
dec01:	      call	mswait		; wait 1 ms
		decfsz 	delay 			; decrement delay and skip when zero
		goto 	dec01 			; branch backwards one instruction
		bsf 	LCD_E 			; LCD enable bit high
		nop
		nop
		nop
		nop
		movlw 	0x38 			; send 0x38 four times
		movwf 	PORTD 			; LCD = 0x38 (8 bit mode x 2 line)
		nop
		nop
		nop
		nop
		nop
		nop
		bcf 	LCD_E 			; latches on High to Low transition
		decfsz 	temp
		goto 	init3 			; repeat 3 times
		bsf 	LCD_BL 			; turn on backlight

		call	mswait

; load special charaters into LCD RAM using LCD busy flag
		movlw 	b'01000000' 	; set LCD CG address to 00
		call 	LCD_Ins 		; relative call
		clrf 	temp
		movlw 	LOW LCD_CC 		; pointer to custom character table
		bsf		STATUS,RP1		; BANK0 -> BANK2
		movwf 	EEADR
nextcc:	      call	rdflash
		call 	LCD_Chr 		; send the character into LCD RAM
		incf 	temp
		btfss 	temp, 6 		; 64 bytes total
		goto 	nextcc

; clear & enable LCD DRAM, no visible cursor
		movlw 	0x0C 			; display on, cursor off
		call 	LCD_Ins

; display top 16 characters
		movlw 	0x01 			; clear display, home cursor
		call 	LCD_Ins
		movlw 	.16
		movwf 	temp
		bsf		STATUS,RP1		; BANK0 -> BANK2
		movlw 	LOW Text_ 		; low byte pointer
		movwf 	EEADR
top: 	        call	rdflash
		call 	LCD_Chr
		decfsz 	temp
		goto	top

; display bottom 16 characters
		movlw 	0xC0 			; set cursor to second line
		call 	LCD_Ins 		; LCD instruction mode
		movlw 	.16
		movwf 	temp
bottom:	      call	rdflash		
		call 	LCD_Chr 		; LCD character mode
		decfsz 	temp
		goto 	bottom
		nop
		nop
		bcf		LED_N
		goto 	$ 					; endless loop done

; wait approx 1 ms
mswait	        movlw	4
		movwf	msdelay+1
msd		movlw	.250
		movwf	msdelay
msdl	        nop
		decfsz	msdelay
		goto	msdl
		decfsz	msdelay+1
		goto	msd
		return

; read one byte from program flash, increment EEADDR
rdflash:        bsf	      STATUS,RP0		; BANK3
		bsf		STATUS,RP1		; BANK3
		bsf		EECON1,EEPGD
		bsf		EECON1,RD		; 2 NOPs MUST (!) follow after reading program FLASH
		nop
		nop
		bcf		STATUS,RP0		; BANK3 -> BANK2
		incf	    EEADR
		movf	  EEDAT,W
		bcf		STATUS,RP1		; BANK2 -> BANK0		
		return

; LCD entry routines watches busy flag
LCD_Chr       bsf 	LCD_RS 			; enable character mode
LCD_Ins        bsf		STATUS,RP0	; -> BANK1
		clrf 	TRISD 			; make PORTD an output
		bcf		STATUS,RP0  ; -> BANK0
		movwf 	PORTD 			; put data on LCD port
		bcf 	LCD_RW 
		nop
		bsf 	LCD_E
		nop
		nop
		nop
		nop
		bcf 	LCD_E 			; latch byte to LCD
		nop
		bcf 	LCD_RS
		bsf		STATUS,RP0	; -> BANK1
		movlw	0xff
		movwf 	TRISD 			; make LCD port input
		bcf		STATUS,RP0  ; -> BANK0
		bsf 	LCD_RW 			; enter read mode		
		bsf 	LCD_E 			; enable LCD
BusyF	btfsc 	PORTD,7 		; wait for bit 7 to be pulled low
		goto 	BusyF
		bcf		LCD_E
		bcf 	LCD_RW 			; return to instruction mode
		return

; text to display (Table with two bytes per word)
		org 	0x0400
Text_	       dt 	      "blueroom      ",.0,.1
		dt 		"electronics   ",.2,.3

; *** 2x2 blueroomelectronics logo (house)
LCD_CC	    dt 		.128,.128,.129,.131,.135,.143,.159,.159
		dt 		.128,.128,.128,.144,.152,.156,.158,.130
		dt 		.159,.159,.159,.145,.145,.145,.159,.128
		dt 		.130,.130,.158,.130,.130,.130,.158,.128
		END
 
Unicorn & LCD - Test/Demo Program

I have created a module or program errrrrrrrrrr maybe i'll just call it a file over the last couple of days since receiving my Unicorn & 2 line LCD display.

I wrote this with the MPLAB C18 C compiler. Thanks to a lot of the conversation & examples i found here + other places i was able to get enough of the callable routines put together that I can now get on with working on my little application. I used the Junebug between MPLAB and the UNICORN.

There's a lot of documentation in the "C" source file - almost everything i found & learned i put into either the comments or in the #define MACROS.

20 years ago when i made a living as a "C" programmer we weren't allowed to put literals in our code - if it's a good habit - then good habits are hard to break!

I've got a compile conditional near the top of the file that can be changed and the entire thing recompiled for either 4 bit or 8 bit data access.


As a final test before posting it i tried transferring each of the hex files to the Unicorn via PicKit2 instead of MPLAB - and noticed that my delay's during the 'demo' are quite long. Maybe someone knows of a way i can put logic in my code to know whether or not i'm running under MPLAB?

The .zip file contains the C source file plus two .hex files - one was compiled for 4 bit and the other for 8 bit.

I spent most of my time getting the 'soft character' loading thing to work - DOH - i was trying to send the bitmaps via the control port instead of the data port!

This is my first PIC program - so you may have to cut me some slack! If you see anything in my source code that needs to be tweaked please let me know - i'm learning!

I have a couple of questions that i can't find answers to - if there are any of you that might be kind enough to help me with:

1) On the UNICORN I can read switches 1 & 2 reliably - switch 3 is flaky and switch 4 i can't read at all. I removed the CPU and checked the switch with an ohm meter - it's not the switch. I noticed there are not any pullups on Switch 3 or 4 which puzzles me - can anyone shed any light on this? I would like to use all four switches if possible.

2) I need to monitor some 12v (DC) signals - is it okay to connect the UNICORN inputs directly to 12v DC signals or is there some more 'electronic glue' required? (I'm a quart or two low in the EE department :p).

3) Anyone have any pointers on switch de-bouncing? What works, what doesn't?

4) Anyone have any good examples of working interrupt code in "C" that's triggered from switch closure AND that's triggered from one of the input pins changing state?

It's 3:15am - i think i better go to bed! Amazing how time flies when you are having fun!

Thanks & thanks for all the help so far!

David / W9GF

w9gf@arrl.net
 

Attachments

  • W9GF.Unicorn.LCD.v1.0.08Apr2008.zip
    13.6 KB · Views: 306
Ahh is this the thread? I'll look at it, you have to enable weak pullups on port B for the pushbuttons to function. I'll look at the code shortly.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top