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 Code - Can I Use the Lower 4 Bits?

Status
Not open for further replies.
Hello.

I am using a 16F819 with a HD4470U-type LCD in 4-bit mode.

The LCD code I have now works when I connect LCD D4 - D7 to 16F819 RB4 - RB7. I have no trouble moving RS and E from bit to bit and across ports.

Here are my problems:

1) Is it possible to connect LCD D4 - D7 to RB0 - RB3 instead so I can use the higher PORTB bits for other purposes? I've tried tinkering with the code (altering the masking in the bit merging routine), with no success so far.

2) Is possible to transfer the LCD D4 - D7 to PORT A, without using RA0? (- I need the analogue input).

- If anyone needs to inspect my LCD code I can try to post it.

Thanks.

- Analogue.
 
As far as the LCD is concerned it does not care what is driving the data lines, as long as the signal timing is correct. (I've even heard of people driving the lines with switches just to test that things are working OK!)

From the uController's perspective, again what the port lines are connected to does not matter as long as the code is correctly setting the lines to the correct value at the right time.

If using RB4-RB7 works but RB0-RB3 doesn't (assuming that the wiring to the LCD has been suitably altered) and the port configurations are correct (set out digital and output etc) then I would suggest that you check the software to make sure that it is driving the port bits correctly.

Susan
 
Hello.

I am using a 16F819 with a HD4470U-type LCD in 4-bit mode.

The LCD code I have now works when I connect LCD D4 - D7 to 16F819 RB4 - RB7. I have no trouble moving RS and E from bit to bit and across ports.

Here are my problems:

1) Is it possible to connect LCD D4 - D7 to RB0 - RB3 instead so I can use the higher PORTB bits for other purposes? I've tried tinkering with the code (altering the masking in the bit merging routine), with no success so far.
Yes, its OK to use the upper or lower nibble of a PORT
2) Is possible to transfer the LCD D4 - D7 to PORT A, without using RA0? (- I need the analogue input).
Yes, thats OK, watch out for for PORTA.5 lack of internal pull up, also its an INPUT only.
- If anyone needs to inspect my LCD code I can try to post it.

Thanks.

- Analogue.

hi,
Post ALL your code listing so we can see the pin usage.
 
Last edited:
@ Aussie Susan: thanks for the information + advice. I was starting to wonder whether I was barking up the wrong tree completely.

@ Thanks again, Eric. - I'm going to try to post the code using code tags.

Current connections:

RS > RA7
E > RA6
D4 > RB4
D5 > RB5
D6 > RB6
D7 > RB7
RW = not used - code works off delays and doesn't check busy flag.


Code:
; File name:
; Date:
; Author: 
; Processor: 16F84A - Adapted to 16F819
;
; Description:
; Program to exercises 4-bit PIC-to-LCD interface.
; Code assumes that LCD is driven by Hitachi HD44780
; controller and that the display supports two lines
; each one with 16 characters. The wiring and base
; address of each display line is stored in #define
; statements. These statements can be edited to
; accomodate a different set-up.
; Program uses delay loops for interface timing.
; WARNING:
; Code assumes 4Mhz clock. Internal oscillator.
;Delay routines must be edited for faster clock
;
; Displays: Minnesota State, Mankato
;
;===========================
;        switches
;===========================
; Switches used in __config directive:
;  
; |
; |_____ * indicates setup values presently selected

;=========================
; setup and configuration
;=========================
	processor 16f819
	include	  <p16F819.inc>
	__config  H'3F10';



;=====================================================
;                 constant definitions
;  for PIC-to-LCD pin wiring and LCD line addresses
;=====================================================
#define E_line 6   	;|- "RS" + "E" LINES IN PORT A
#define RS_line 7	;| -- from wiring diagram 
;#define RW_line 3	;|
; LCD line addresses (from LCD data sheet)
#define LCD_1 0x80	; First LCD line constant
#define LCD_2 0xc0	; Second LCD line constant
; Note: The constant that define the LCD display line
;       addresses have the high-order bit set in
;       order to faciliate the controller command 
;
;=====================================================
;              variables in PIC RAM
;=====================================================
; Reserve 16 bytes for string buffer
	cblock	0x20 ;CHANGED FROM  0x0c 
	strData
	endc
; Leave 16 bytes and Continue with local variables
	cblock	0x32		; Start of block ;CHANGED FROM 0x1d 
	count1		; Counter # 1
	count2		; Counter # 2
	count3		; Counter # 3
	pic_ad		; Storage for start of text area
				; (labeled strData) in PIC RAM
	J			; counter J
	K			; counter K
	index		; Index into text table (also used
				; for auxiliary storage)
	store1		; Local temporary storage 
	store2		; Storage # 2
	endc

;=========================================================
;                           program
;=========================================================
		org		0	  ; start at address 
		goto	main
; Space for interrupt handlers
	org		0x08
main:


	movlw	b'00100001' ; 
	tris	PORTA		; 

	movlw	b'00001110'	;
	movwf	ADCON1		;

	movlw	b'00000000' ; 	
	tris	PORTB		; 
	BANKSEL	OSCCON		;
	MOVLW	B'01100000'	;4Mhz internal oscillator
	MOVWF	OSCCON					
	BCF		STATUS,5	;
	BCF		STATUS,6	;
	movlw	b'00000000' ; 
	movwf	PORTA
	movwf	PORTB

; Wait and initialize HD44780
	call	delay_5		; Allow LCD time to initialize
						; itself
	call	delay_5
	call	initLCD		; Then do forced initialization
	call	delay_5		; Wait again
; Store base address of text buffer in PIC RAM

	movlw	0x20		; Start address for buffer
	movwf	pic_ad		; to local variable
;======================
;   first LCD line
;======================
; Store 16 blanks in PIC RAM, starting at address stored
; in variable pic_ad
	call	blank16
; Call procedure to store ASCII characters for message
; in text buffer
	movlw	d'3'		; Offset into buffer
	call	storeMSU
; Set DDRAM address to start of first line
	call 	line1
; Call procedure to display 16 characters in LCD
	call	display16
;========================
;   second LCD line
;========================
	call	delay_5		; Wait for termination
	call	blank16		; Blank buffer
; Call procedure to store ASCII characters for message
; in text buffer
	movlw	d'1'		; Offset into buffer
	call	storeUniv
	call	line2		; DDRAM address of LCD line 2
	call	display16
;=======================
;       done!
;=======================
loopHere:
	goto    loopHere  ;done

;============================================================
;                initialize LCD for 4-bit mode 
;============================================================
initLCD:
; Initialization for Densitron LCD module as follows:
;	4-bit interface
;   2 display lines of 16 characters each
;   cursor on
;   left-to-right increment
;   cursor shift right
;   no display shift
;=======================|
;   set command mode    |
;=======================|
	bcf		PORTA,E_line	; E line low
	bcf		PORTA,RS_line	; RS line low
	;bcf		PORTA,RW_line	; Write mode
	call	delay_125		; delay 125 microseconds
;***********************|
;     FUNCTION SET      |
;***********************|
	movlw	0x28	; 0 0 1 0 1 0 0 0 (FUNCTION SET)
					;     | | | |__ font select:
					;     | | |    1 = 5x10 in 1/8 or 1/11 dc
					;     | | |    0 = 1/16 dc
					;     | | |___ Duty cycle select
					;     | |      0 = 1/8 or 1/11
					;     | |      1 = 1/16 (multiple lines)
					;     | |___ Interface width
					;     |      0 = 4 bits
					;     |      1 = 8 bits
					;     |___ FUNCTION SET COMMAND 
	call	send8	; 4-bit send routine

; Set 4-bit mode command must be repeated
	movlw	0x28
	call 	send8

;***********************|
; DISPLAY AND CURSOR ON |
;***********************|
	movlw	0x0e	; 0 0 0 0 1 1 1 0 (DISPLAY ON/OFF)
					;         | | | |___ Blink character at cursor
					;         | | |      1 = on, 0 = off
					;         | | |___ Curson on/off
					;         | |      1 = on, 0 = off
					;         | |____ Display on/off
					;         |       1 = on, 0 = off
					;         |____ COMMAND BIT
	call	send8
;***********************|
;   set entry mode      |
;***********************|
	movlw	0x06	; 0 0 0 0 0 1 1 0 (ENTRY MODE SET)
					;           | | |___ display shift
					;           | |      1 = shift
					;           | |      0 = no shift
					;           | |____ cursor increment mode
					;           |       1 = left-to-right
					;           |       0 = right-to-left
					;           |___ COMMAND BIT
	call	send8

;***********************|
; cursor/display shift  |
;***********************|
	movlw	0x14	; 0 0 0 1 0 1 0 0 (CURSOR/DISPLAY SHIFT)
   					;       | | | |_|___ don't care
					;       | |_|__ cursor/display shift
					;       |       00 = cursor shift left
					;       |       01 = cursor shift right
					;       |       10 = cursor and display
					;       |            shifted left
					;       |       11 = cursor and display
					;       |            shifted right
					;       |___ COMMAND BIT
	call	send8
;***********************|
;    clear display      |
;***********************|
	movlw	0x01	; 0 0 0 0 0 0 0 1 (CLEAR DISPLAY)
					;               |___ COMMAND BIT
	call	send8
; Per documentation
	call	delay_5	; Test for busy
	return

;=======================
;  Procedure to delay
;   42 microseconds
;=======================
delay_125
	movlw	D'42'			; Repeat 42 machine cycles
	movwf	count1			; Store value in counter
repeat
	decfsz	count1,f   		; Decrement counter
	goto	repeat			; Continue if not 0
	return					; End of delay	

;=======================
;  Procedure to delay
;   5 milliseconds
;=======================
delay_5
	movlw	D'41'			; Counter = 41
	movwf	count2			; Store in variable
delay
	call	delay_125		; Delay
	decfsz	count2,f    	; 40 times = 5 milliseconds
	goto	delay
	return				; End of delay
;========================
;     pulse E line 
;========================
pulseE
	bsf		PORTA,E_line	; Pulse E line
	nop
	bcf		PORTA,E_line
	return

;=============================
;   long delay sub-routine
;     (for debugging)
;=============================
long_delay
		movlw	D'200'	; w = 200 decimal
		movwf	J		; J = w
jloop:	movwf	K		; K = w
kloop:	decfsz	K,f		; K = K-1, skip next if zero
		goto 	kloop
		decfsz	J,f		; J = J-1, skip next if zero
		goto	jloop
		return
;=============================
;   LCD display procedure
;=============================
; Sends 16 characters from PIC buffer with address stored
; in variable pic_ad to LCD line previously selected
display16
	call	delay_5			; Make sure not busy
; Set up for data
	bcf		PORTA,E_line	; E line low
	bsf		PORTA,RS_line	; RS line high for data
; Set up counter for 16 characters
	movlw	D'16'			; Counter = 16
	movwf	count3	
; Get display address from local variable pic_ad
	movf	pic_ad,w		; First display RAM address to W
	movwf	FSR				; W to FSR
getchar
	movf	INDF,w			; get character from display RAM
							; location pointed to by file select
							; register
	call	send8			; 4-bit interface routine
; Test for 16 characters displayed
	decfsz	count3,f  		; Decrement counter
	goto	nextchar		; Skipped if done
	return
nextchar:
	incf	FSR,f			; Bump pointer
	goto	getchar

;========================
;   send 2 nibbles in
;     4-bit mode
;========================
; Procedure to send two 4-bit values to port B lines
; 7, 6, 5, and 4. High-order nibble is sent first
; ON ENTRY:
;         w register holds 8-bit value to send
send8:
	movwf	store1		; Save original value
	call	merge4		; Merge with port B
; Now w has merged byte
	movwf	PORTB		; w to port B
	call	pulseE		; Send data to LCD
; High nibble is sent
	movf	store1,w	; Recover byte into w
	swapf	store1,w	; Swap nibbles in w
	call	merge4
	movwf	PORTB
	call	pulseE		; Send data to LCD
	call	delay_125 
	return
;=================
;  merge bits
;=================
; Routine to merge the 4 high-order bits of the
; value to send with the contents of port B
; so as to preserve the 4 low-bits in port B
; Logic:
;      AND value with 1111 0000 mask
;      AND port B with 0000 1111 mask
;      Now low nibble in value and high nibble in
;      port B are al 0 bits:
;          value = vvvv 0000
;         port B = 0000 bbbb
;      OR value and port B resulting in:
;                  vvvv bbbb 
; ON ENTRY:
;      w contain value bits
; ON EXIT:
;      w contains merged bits
merge4:
	andlw	b'11110000'	; ANDing with 0 clears the
						; bit. ANDing with 1 preserves
						; the original value
	movwf	store2		; Save result in variable
	movf	PORTB,w		; port B to w register
	andlw	b'00001111' ; Clear high nibble in port b
						; and preserve low nibble
	iorwf	store2,w	; OR two operands in w
	return

;========================
;     blank buffer
;========================
; Procedure to store 16 blank characters in PIC RAM
; buffer starting at address stored in the variable
; pic_ad
blank16
	movlw	D'16'		; Setup counter
	movwf	count1
	movf	pic_ad,w	; First PIC RAM address
	movwf	FSR			; Indexed addressing
	movlw	0x20		; ASCII space character
storeit
	movwf	INDF		; Store blank character in PIC RAM
						; buffer using FSR register
	decfsz	count1,f  	; Done?
	goto	incfsr		; no
	return				; yes
incfsr
	incf	FSR,f		; Bump FSR to next buffer space
	goto	storeit

;========================
; Set address register
;    to LCD line 1
;========================
; ON ENTRY:
;         Address of LCD line 1 in constant LCD_1 
line1:
	bcf		PORTA,E_line 	; E line low
	bcf		PORTA,RS_line	; RS line low, set up for control
	call	delay_5		; busy?
; Set to second display line
	movlw	LCD_1			; Address and command bit
	call	send8			; 4-bit routine
; Set RS line for data
	bsf		PORTA,RS_line	; Setup for data
	call	delay_5			; Busy?
	return
;========================
; Set address register
;    to LCD line 2
;========================
; ON ENTRY:
;         Address of LCD line 2 in constant LCD_2 
line2:
	bcf		PORTA,E_line	; E line low
	bcf		PORTA,RS_line	; RS line low, setup for control
	call	delay_5		; Busy?
; Set to second display line
	movlw	LCD_2			; Address with high-bit set
	call	send8
; Set RS line for data
	bsf		PORTA,RS_line	; RS = 1 for data
	call	delay_5			; Busy?
	return

;===============================
;  first text string procedure
;===============================
storeMSU:
; Procedure to store in PIC RAM buffer the message
; contained in the code area labeled msg1
; ON ENTRY:
;         variable pic_ad holds address of text buffer
;         in PIC RAM
;         w register hold offset into storage area
;         msg1 is routine that returns the string characters
;         an a zero terminator
;         index is local variable that hold offset into
;         text table. This variable is also used for
;         temporary storage of offset into buffer 
; ON EXIT:
;         Text message stored in buffer
;
; Store offset into text buffer (passed in the w register)
; in temporary variable 
	movwf	index		; Store w in index
; Store base address of text buffer in FSR
	movf	pic_ad,w	; first display RAM address to W
	addwf	index,w		; Add offset to address
	movwf	FSR			; W to FSR
; Initialize index for text string access
	movlw	0			; Start at 0
	movwf	index		; Store index in variable
; w still = 0
get_msg_char:
	call	msg1		; Get character from table
; Test for zero terminator
	andlw	0x0ff
	btfsc	STATUS,Z	; Test zero flag
	goto	endstr1		; End of string
; ASSERT: valid string character in w
;         store character in text buffer (by FSR)
	movwf	INDF		; store in buffer by FSR
	incf	FSR,f		; increment buffer pointer
; Restore table character counter from variable
	movf	index,w		; Get value into w
	addlw	1			; Bump to next character
	movwf	index		; Store table index in variable
	goto	get_msg_char	; Continue	
endstr1:
	return

; Routine for returning message stored in program area
msg1:
	addwf	PCL,f		; Access table
	retlw	'M'
	retlw	'i'
	retlw	'n'
	retlw	'n'
	retlw	'e'
	retlw	's'
	retlw	'o'
	retlw	't'
	retlw	'a'
	retlw	0

;=================================
;   second text string procedure
;=================================
storeUniv:
; Processing identical to procedure StoreMSU
	movwf	index		; Store w in index
; Store base address of text buffer in FSR
	movf	pic_ad,0	; first display RAM address to W
	addwf	index,0		; Add offset to address
	movwf	FSR			; W to FSR
; Initialize index for text string access
	movlw	0			; Start at 0
	movwf	index		; Store index in variable
; w still = 0
get_msg_char2:
	call	msg2		; Get character from table
; Test for zero terminator
	andlw	0x0ff
	btfsc	STATUS,Z	; Test zero flag
	goto	endstr2		; End of string
; ASSERT: valid string character in w
;         store character in text buffer (by FSR)
	movwf	INDF		; Store in buffer by FSR
	incf	FSR,f		; Increment buffer pointer
; Restore table character counter from variable
	movf	index,w		; Get value into w
	addlw	1			; Bump to next character
	movwf	index		; Store table index in variable
	goto	get_msg_char2	; Continue	
endstr2:
	return

; Routine for returning message stored in program area
msg2:
	addwf	PCL,f		; Access table
	retlw	'S'
	retlw	't'
	retlw	'a'
	retlw	't'
	retlw	'e'
	retlw	','
	retlw	0x20
	retlw	'M'
	retlw	'a'
	retlw	'n'
	retlw	'k'
	retlw	'a'
	retlw	't'
	retlw	'o'
	retlw	0

	end

- I've adapted this code for use in the 16F819. It is based on one written by Sanchez and Canton in "Microcontroller Programming the Microchip PIC". Their original version was written for the 16F84A.

The only significant changes I've made were to use the internal oscillator and move the RS and E lines, the rest is pretty much as they wrote it including their explanatory comments.


Analogue.
 
hi,
Runs OK in the Oshonsoft simulator.
 

Attachments

  • AAesp01.gif
    AAesp01.gif
    9.1 KB · Views: 181
Hello Eric. Thanks. - It works fine with the current connections, but when I try to use RB0 - RB3 to connect to D4 - D7, instead of the PORT B higher 4 bits, the message doesn't display at all.

- Any ideas as to what might be going wrong, please?

Analogue.
 
Your code (and Eric's simulation) both use the upper 4 bits of PortB which you state is working OK.

Just a couple of sanity checks:
1) you are changing the wiring from the LCD to the micro-controller to connect to the RB0-RB3 pins
2) you are modifying your code (especially the "merge4" routine) to manipulate the lower nibble (rather than the upper one)

I have not studied you code carefully but I get the impression that there are lots of places where there is an "assumption" that the upper nibble will be used. You seem to have the control line bits in Port A referenced via #define's but not the data bits. Are you sure that you have changed EVERY literal constant that is involved?

Susan
 
As Susan states, the bit that needs changing is the merge4 routine.

Try,
Code:
merge4:
		andlw	b'11110000'	; ANDing with 0 clears the
					; bit. ANDing with 1 preserves 
					; the original value 
		movwf	store2		; Save result in variable
		[COLOR="red"]swapf	store2,f	; swap nibbles[/COLOR]
		movf	PORTB,w		; port B to w register
		andlw	b'[COLOR="red"]11110000[/COLOR]'	; Clear [COLOR="red"]low[/COLOR] nibble in port b
					; and preserve [COLOR="red"]high[/COLOR] nibble 
		iorwf	store2,w	; OR two operands in w
		return

Mike.
 
Just my two cents, but he still wants to use the upper 4 bits of the LCD:
1) Is it possible to connect

LCD D4 - D7 to RB0 - RB3

instead so I can use the higher PORTB bits for other purposes?
He just wants to change the pins on the PIC.

Edit: Yes, Mike, now I see what you are doing.:eek: Should have read more closely.
 
Last edited:
@ Susan: yes, I've definitely moved the LCD connections to the lower four bits of PORTB, and I've been focused largely on trying to alter the merge4 routine.
You're right that only the RS and E lines were defined: I searched through the code trying to find a place where they did the same for the other LCD lines, but it's nowhere to be found.

Out of interest, if I wanted to define LCD D4 - D7 would I do it in the same way as for RS and E: #define D4_LINE 0

#define D5_LINE 1, etc?

@ Mike: I tried your suggestion and it worked: everything displays properly now. Thanks very much. - I was concentrating on trying to change the masks - didn't realize that a second swapf was also needed.

Thanks again to all who helped out.

- Analogue.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top