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.

16x2 Not Initializing on PIC16F887

Status
Not open for further replies.

CoreyF

New Member
I'm trying to a write a basic "Hello World" to an 16x2 LCD on an easypic5. Using the MPLAB IDE, I've written the following program:

Code:
;
;     EasyPic5 version using PIC16F877
;Character based LCD driver routines for running the Hitachi HD44780
;in 4 bit mode. This program is configured to run on the
;EasyPIC5_Board at a clock rate of 8MHz.
;This program will print on both lines of the LCD and then stop.
;The program will write "Hello" on line 1.
;and it will write "World   -   " on line 2.
;-----------------------------------------------------------------
	list		p=16f887	; list directive to define processor
	#include	<p16f887.inc>	; processor specific variable definitions
	radix		hex

	errorlevel	-302		;Disable bank warning message in error list

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The labels following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.

	__CONFIG _CONFIG1, _HS_OSC & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOR_ON & _IESO_ON & _FCMEN_ON & _LVP_OFF & _DEBUG_OFF 

	__CONFIG _CONFIG2, _BOR40V & _WRT_OFF
 
;Note: All of the CONFIG designations must be contiguous on one line for each config register
;1 & 2.   			
;-------------------------------------------------------------------
   cblock	0x20		;start of general purpose registers
		count		;used in looping routines
		nib		;used for displaying single nibbles
		currbyte	;current byte command or data being sent
		lcount		;used inside ptimer routine
		mcount		;used inside ptimer routine
		ncount		;used inside ptimer routine
		innerl		;used to send new values to ptimer routine
		midl		;used to send new values to ptimer routine
		outerl		;used to send new values to ptimer routine
		cmdstatus	;used to indicate a command or data
		
   endc
;-------------------------------------------------------------------
LCDPORT		Equ	PORTB
LCDTRIS		Equ	TRISB
RS		Equ	0x04	;LCD register select
E		Equ	0x05	;LCD enable line
RW				;not used on EasyPIC_Board
cmd_on	Equ	0x00	;bit 0 used as command / data flag

		org	0x0000
		clrf	count
		clrf	PORTB

		banksel	TRISB		;Bank1
		movlw	0x00		;outputs
		movwf	LCDTRIS
		banksel	PORTB		;Bank0

		call	delay150	;wait for LCD to settle
		call	LCDInit		;setup LCD

;		movlw	0x09
		call	LCD_Line1
		clrf	count		;set counter register to zero
Message		movf	count, w	;put counter value in W
		call	Text		;get a character from the text table
		xorlw	0x00		;is it a zero?
		btfsc	STATUS, Z
		goto	NextMessage
		call	LCD_Char
		incf	count, f
		goto	Message

NextMessage	call	LCD_Line2	;move to 2nd row, first column

		clrf	count		;set counter register to zero
Message2	movf	count, w	;put counter value in W
		call	Text2		;get a character from the text table
		xorlw	0x00		;is it a zero?
		btfsc	STATUS, Z
		goto	EndMessage
		call	LCD_Char
		incf	count, f
		goto	Message2
EndMessage

;End of commands test		
Stop		goto	Stop		;endless loop
				;Program stops executing here!
;==============================================================
	
;Testing commands here
		movlw	0x09		;address location 9 on line 1
		call	LCD_Line2W
		movlw	0xaf		;Note only uses last hex digit
		call	HEX_1		;write single digit
		movlw	0x0d
		call	HEX_1		;write another single digit

		movlw	'A'
		call	HEX_DBL

		movlw	0x06
		call	LCD_CharD





;Initialise LCD
LCDInit	movlw	0x20		;Set 4 bit mode
		call	LCD_Cmd

		movlw	0x18		;Display Cursor Shift
		call	LCD_Cmd

		movlw	0x28		;Function Set
		call	LCD_Cmd

		movlw	0x06		;Set display character mode
		call	LCD_Cmd

		movlw	0x0d		;Set display on/off and cursor command
		call	LCD_Cmd

		call	LCD_Clr		;clear display

		return


LCD_Cmd		bsf	cmdstatus,cmd_on ;set the command bit high
		goto	LCD_Char	
LCD_CharD	addlw 	0x30		;add 30 hex to decimal digits
LCD_Char	movwf	currbyte
		swapf	currbyte	;it is necessary to swap the
		movfw	currbyte	;nibble because the EasyPic5
					;uses the lower four bits for 
					;data transfer instead of the 
					;upper four bits like the 
					;EasyPic4		
		call	Snd_nibl	;send first nibble
		movf	currbyte,w	;get the other nibble
		swapf	currbyte,w	;get the other nibble
		call	Snd_nibl	;send the second nibble
		bcf	cmdstatus,cmd_on ;clear the command bit 
		call	delay3
		return


;Sends one nibble to controller / Used by commands and characters
;Will set Register select low for command if cmdstatus, bit 0 is high
;Will set Register select high for char data if cmdstatus, bit 0 is low
Snd_nibl	andlw	0x0f		  ;clear lower nibble of W
		movwf	LCDPORT
		btfss	cmdstatus,cmd_on  ;check if command or character
		goto	charnib
		bcf	LCDPORT,RS  ;RS line to 0 for command
		goto	pulse
charnib		bsf	LCDPORT,RS  ;RS line to 1 for character
pulse		call	Pulse_e		  ;Pulse the E line high
		return


LCD_Line1	movlw	0x80		;move to 1st row, first column
		call	LCD_Cmd
		return

LCD_Line2	movlw	0xC0		;move to 2nd row, first column
		call	LCD_Cmd
		return

LCD_Line1W	addlw	0x80		;move to 1st row, column W
		call	LCD_Cmd
		return

LCD_Line2W	addlw	0xC0		;move to 2nd row, column W
		call	LCD_Cmd
		return

LCD_CurOn	movlw	0x0d		;Set display on/off and cursor command
		call	LCD_Cmd
		return

LCD_CurOff	movlw	0x0c		;Set display on/off and cursor command
		call	LCD_Cmd
		return

LCD_Clr		movlw	0x01		;Clear display
		call	LCD_Cmd
		return

HEX_1		movwf	nib	;displays a nibble in a single hex char
		goto	singl
HEX_DBL		movwf	nib	;displays a byte in two hex chars
		swapf	nib,w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
singl		movf	nib,w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		return

Pulse_e		bsf	LCDPORT,E	;Pulse the Enable line
		nop
		bcf	LCDPORT,E
		return
;end of LCD routines

HEX_Table  	ADDWF   PCL, f
		DT "0123456789ABCDEF"

Text		addwf	PCL, f
		DT "Hello", 0h 
		
Text2		ADDWF   PCL, f
            	DT "World  -  ", 0h
;-------------------------------------------
;routine to load 150msec delay into ptimer
;values based on 8MHz clock rate
delay150	movlw	0xFE
		movwf	innerl
		movlw	0xC4
		movwf	midl
		movlw	0x02
		movwf	outerl
		call	ptimer
		return
;routine to load 3msec delay into ptimer
;values based on 8MHz clock rate
delay3		movlw	0xFF
		movwf	innerl
		movlw	0x08
		movwf	midl
		movlw	0x01
		movwf	outerl
		call	ptimer
		return
;=====================================================================
;ptimer is a 3 loop counter. Adjust time delay by loading values into
;lcount, mcount, and ncount from the calling routine
;--------------OUTER LOOP---------------------------------------->>>
ptimer		movf	outerl,w ;loaded from calling routine	
		movwf	lcount 	  		  	
;--------------MIDDLE LOOP--------------------------------->>	
loadm		movf	midl,w	;loaded fro calling routine
		movwf	mcount       	    			     	  
;-----------INNER MOST LOOP----------------------------->
loadn		movf	innerl,w ;loaded from calling routine
		movwf	ncount			 	   	 
decn		decfsz	ncount,f ;decrement N          	         
		goto	decn	;again thru inner loop N	 
;-------------------------------------------------------<
		decfsz	mcount,f ;decrement M 		   	    
		goto	loadn	;again thru middle loop M  	   
;---------------------------------------------------------<<
		decfsz	lcount,f ;decrement L				  
		goto	loadm	;again thru outer loop L		  
;---------------------------------------------------------------<<<
		return		;done
;=====================================================================
		end
;-------------------------------------------------

I've been scratching my head for a couple of hours, and have looked online for solutions, but everything I find is in the "C" programming language. I'm not able to initialize my LCD, and I don't know why.
 
Try increasing the delay150 to 500. If that works, incrementally decrease till it doesn't work, the bump it back up 50-100msec.
Most of the LCD initialization problems I have had have been due too short of an initial delay prior to the initialization string.
 
Isn't the delay mentioned in the protocol for initialization?
 
Last edited:
You've got to init the LCD in 8bit mode first because they always default to that.

What you're doing in LCDinit is starting with a 2 nibble command. That de-synchs the 44780 so every byte you send after that is 1 nibble out.

First send a single nibble to init in 4bit mode.

After that you must send every command and character as 2 nibbles.

And check your E pulse, the 44780 latches the new data on the \ edge of the E pulse. The / edge is ignored.
 
Last edited:
Hi All..
I have had the same problem..
Remember that the pic16f887 has analog pins on port b
make port b pins digital and it works!
all the best from OZ1LQB
 
@mfisch2001 - I increased the time but to no avail. The timing should be fine.
@Mike, K8LH - No

@Wp100 - I compiled some of Nigel's examples, switching the ports where necessary, and I couldn't get his examples to initialize the LCD either. This isn't good.

@Mr RB, @oz1lqb - I'll get back with you.

One of my classmates who tried this out for me was able to run this just fine on an EasyPic3 with the same code. I forgot if he was using the 887 or the 877A though. Neither of us could diagnose the problem on my board & code in particular, so I'm looking into @Mr RB's and @oz1lqb's solutions in the meantime.
 
Last edited:
The delay needs to come AFTER you call LCD_Init. The LCD needs 100uS to stabilize!!! You are attacking it right away :)

Give that a shot :p

Also, check your connections, its probably not that at this point though.
And just to be sure, through in (While in Bank1 ) "CLRF ANSELH"
 
Last edited:
My guess is that you LCDs are different makes and the problem will swap over if you swap LCDs. Some of the newer LCDs are not as fussy about the initialization sequence as the older ones. I've attached the required initialization sequence. As you can see (and as pointed out by RB) only 4 bits should be sent until initialization is over. Also note the required delays.

Mike.
 

Attachments

  • LCD init.png
    LCD init.png
    21.1 KB · Views: 694
Last edited:
No problem.

Edit, may as well attach the data sheet.

Mike.
 

Attachments

  • LCD init.png
    LCD init.png
    33.5 KB · Views: 668
  • LCD Module data sheet.pdf
    0 bytes · Views: 25
Last edited:
You should really get the datasheet for the Hitachi 44780 too (that's the LCD driver chip inside the display). The init sequence shown in RS datasheet that Pommie posted is not exactly the same as the example in the 44780 datsasheet but like Pommie said most of the LCDs are not that fussy.

Occasionally you'll get an old LCD with a slow 44780 clock speed that needs longer delays in the init code. I've pulled a couple of 16x1 from old 1980's fax machines that were like that.
 
Hi. I had a EZPIC3. Greatest thing since sliced bread, development wise. Then I got the EZPIC4 and things stopped working. I think this included the LCD. I checked the forums and discovered some of the circuits changed to accomodate hardware debug (fuzzy memory here). This meant old LCD code no longer worked for that reason on later EXPIC boards. Do a search on the MikroE site and check me on that. In other words, you have to use the new libraries for later versions of the compiler designed to work with EZPIC4 and beyond. I haven't used these units in almost two years, but that's what happened back then.
Take care.
kenjj
 
Hi. I had an EZPIC3. Greatest thing since sliced bread, development wise. Then I got the EZPIC4 and things stopped working. I think this included the LCD. I checked the forums and discovered some of the circuits changed to accomodate hardware debug (fuzzy memory here). This meant old LCD code no longer worked for that reason on later EZPIC boards. Do a search on the MikroE site and check me on that. In other words, you have to use the new libraries for later versions of the compiler designed to work with EZPIC4 and beyond. I haven't used these units in almost two years, but that's what happened back then.
Take care.
kenjj
 
Hey guys, don't mean to bump this thread (I've been out of town for the last little while).

I played around with it last night, and this solution worked:

Code:
;===============================================================================
;         EasyPic5 version with PIC16F887
;Character based LCD driver routines for running the Hitachi HD44780
;in 4 bit mode. This program is configured to run on the
;EasyPIC5_Board at a clock rate of 8MHz.
;
;This program will write 'X' on the first line
;
;-------------------------------------------------------------------------------
	list		p=16f887	; list directive to define processor
	#include	<p16f887.inc>	; processor specific variable definitions
	__CONFIG _CONFIG1,_CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _MCLRE_ON 
	;__config 0x3f32
	radix	hex			
;-------------------------------------------------------------------
   cblock	0x20	;start of general purpose registers
	count		;used in looping routines
	nib		;used for displaying single nibbles
	currbyte	;current byte command or data being sent
	lcount		;used inside ptimer routine
	mcount		;used inside ptimer routine
	ncount		;used inside ptimer routine
	innerl		;used to send new values to ptimer routine
	midl		;used to send new values to ptimer routine
	outerl		;used to send new values to ptimer routine
	cmdstatus	;used to indicate a command or data
   endc

LCDPORT		Equ	PORTB
LCDTRIS		Equ	TRISB
RS		Equ	0x04	;LCD register select
E		Equ	0x05	;LCD enable line
RW				;not used on EasyPIC_Board
cmd_on		Equ	0x00	;bit 0 used as command / data flag
;-------------------------------------------------------------------

		org	0x0000
		clrf	count
		clrf	PORTB

		banksel	ANSEL	;Must set PORTS A, B, (E-1,2,3) to Digital
		clrf 	ANSEL	;digital I/O PORTA
		clrf	ANSELH	;digital I/O PORTB

		banksel	TRISB		;Bank1
		movlw	0x00		;outputs
		movwf	LCDTRIS
		banksel	PORTB		;Bank0

		call	delay150	;wait for LCD to settle
		call	LCDInit		;setup LCD
		call	LCD_Clr		;clear both lines
		
; ===== Init Complete - Start Code Here =========================

		movlw	0x00		;address location 0 on line 1
		call	LCD_Line1W
		movlw	'X'
		call	LCD_Char

Stop		goto	Stop		;endless loop


;===============================================================================
;Initialise LCD
;-------------------------------------------------------------------------------
LCDInit	movlw	0x20		;Set 4 bit mode
		call	LCD_Cmd

		movlw	0x18		;Display Cursor Shift
		call	LCD_Cmd

		movlw	0x28		;Function Set
		call	LCD_Cmd

		movlw	0x06		;Set display character mode
		call	LCD_Cmd

		movlw	0x0d		;Set display on/off and cursor command
		call	LCD_Cmd

		call	LCD_Clr		;clear display

		return

;===============================================================================
;-------------------------------------------------------------------------------
LCD_Cmd		bsf	cmdstatus,cmd_on ;set the command bit high
		goto	LCD_Char	
LCD_CharD	addlw 	0x30		;add 30 hex to decimal digits
LCD_Char	movwf	currbyte	;it is necessay to swap nibbles
		swapf	currbyte	;because on EasyPIC5 the lower
					;4 bits are used instead of the
					;upper 4 bits like the EasyPic4
		movfw	currbyte		
		call	Snd_nibl	;send first nibble
		movf	currbyte,w	;get the other nibble
		swapf	currbyte,w	;get the other nibble
		call	Snd_nibl	;send the second nibble
		bcf	cmdstatus,cmd_on ;clear the command bit 
		call	delay3
		return

;===============================================================================
;Sends one nibble to controller / Used by commands and characters
;Will set Register select low for command if cmdstatus, bit 0 is high
;Will set Register select high for char data if cmdstatus, bit 0 is low
;-------------------------------------------------------------------------------
Snd_nibl	andlw	0x0f		;clear upper nibble of W
		movwf	LCDPORT
		btfss	cmdstatus,cmd_on  ;check if command or character
		goto	charnib
		bcf	LCDPORT,RS  ;RS line to 0 for command
		goto	pulse
charnib		bsf	LCDPORT,RS  ;RS line to 1 for character
pulse		call	Pulse_e		  ;Pulse the E line high
		return


;===============================================================================
; LCD Routines
;-------------------------------------------------------------------------------
LCD_Line1	movlw	0x80		;move to 1st row, first column
		call	LCD_Cmd
		return

LCD_Line2	movlw	0xC0		;move to 2nd row, first column
		call	LCD_Cmd
		return

LCD_Line1W	addlw	0x80		;move to 1st row, column W
		call	LCD_Cmd
		return

LCD_Line2W	addlw	0xC0		;move to 2nd row, column W
		call	LCD_Cmd
		return

LCD_CurOn	movlw	0x0d		;Set display on/off and cursor command
		call	LCD_Cmd
		return

LCD_CurOff	movlw	0x0c		;Set display on/off and cursor command
		call	LCD_Cmd
		return

LCD_Clr		movlw	0x01		;Clear display
		call	LCD_Cmd
		return

HEX_1		movwf	nib	;displays a nibble in a single hex char
		goto	singl
HEX_DBL		movwf	nib	;displays a byte in two hex chars
		swapf	nib,w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
singl		movf	nib,w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		return

Pulse_e		bsf	LCDPORT,E	;Pulse the Enable line
		nop
		bcf	LCDPORT,E
		return

;end of LCD routines

;===============================================================================
; Tables
;-------------------------------------------------------------------------------
HEX_Table  	ADDWF   PCL, f
		DT "0123456789ABCDEF"

Text		addwf	PCL, f
		DT "Hello", 0h 
		
Text2		ADDWF   PCL, f
            	DT "World  -  ", 0h

;===============================================================================
;routine to load 150msec delay into ptimer
;values based on 8MHz clock rate
;-------------------------------------------------------------------------------
delay150	movlw	0xFE
		movwf	innerl
		movlw	0xC4
		movwf	midl
		movlw	0x02
		movwf	outerl
		call	ptimer
		return

;===============================================================================
;routine to load 3msec delay into ptimer
;values based on 8MHz clock rate
;-------------------------------------------------------------------------------
delay3		movlw	0xFF
		movwf	innerl
		movlw	0x08
		movwf	midl
		movlw	0x01
		movwf	outerl
		call	ptimer
		return
		
;===============================================================================
;ptimer is a 3 loop counter. Adjust time delay by loading values into
;lcount, mcount, and ncount from the calling routine
;-------------------------------------------------------------------------------
;--------------OUTER LOOP---------------------------------------->>>
ptimer		movf	outerl,w ;loaded from calling routine	
		movwf	lcount 	  		  	
;--------------MIDDLE LOOP--------------------------------->>	
loadm		movf	midl,w	;loaded fro calling routine
		movwf	mcount       	    			     	  
;-----------INNER MOST LOOP----------------------------->
loadn		movf	innerl,w ;loaded from calling routine
		movwf	ncount			 	   	 
decn		decfsz	ncount,f ;decrement N          	         
		goto	decn	;again thru inner loop N	 
;-------------------------------------------------------<
		decfsz	mcount,f ;decrement M 		   	    
		goto	loadn	;again thru middle loop M  	   
;---------------------------------------------------------<<
		decfsz	lcount,f ;decrement L				  
		goto	loadm	;again thru outer loop L		  
;---------------------------------------------------------------<<<
		return		;done
;=====================================================================
		end
;-------------------------------------------------

Thanks for the help guys!

Doesn't those dev boards come with sample code? Try it to make sure LCD works 100%

They do, but I don't know C or know how to use a C Compiler.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top