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 16F819 - Change Oscillator Frequency Problem

Status
Not open for further replies.
Hello, I'm looking for some advice please.

The following HD-44780U LCD display code (adapted from "Microcontroller Programming: The Microchip PIC", Sanchez and Canton) works perfectly at 4MHz and 8MHz, but when I reduce the frequency of the internal oscillator, the display ceases to function.

I suspect that the problem is with the delay loops (code does not check busy flag). I've tried altering these to preserve the original delay (and also tried longer ones) but with no success.

Can anyone explain the method for calculating the delays required to run the program at frequencies between 31.25KHz and 2MHz, please.

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 7   	;|- "RS" + "E" LINES IN PORT A
#define RS_line 6	;| -- 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'00000000'	;31.25KHZ INTERNAL OSCILLATOR - DOES NOT WORK
	;MOVLW	B'00010000'	;125KHZ INTERNAL OSCILLATOR  - DOES NOT WORK
	;MOVLW	B'00100000'	;250KHZ INTERNAL OSCILLATOR  - DOES NOT WORK
	;MOVLW	B'00110000'	;500KHZ INTERNAL OSCILLATOR  - DOES NOT WORK
	;MOVLW	B'01000000'	;1MHZ INTERNAL OSCILLATOR  - DOES NOT WORK
	;MOVLW	B'01010000'	;2MHZ INTERNAL OSCILLATOR  - DOES NOT WORK
	;MOVLW	B'01100000'	;4Mhz internal oscillator  - WORKS PROPERLY
	;MOVLW	B'01110000'	;8MHZ INTERNAL OSCILLATOR  - WORKS PROPERLY
	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

[COLOR="rgb(0, 0, 0)"][COLOR="Red"];=======================
;  Procedure to delay
;   125 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[/COLOR][/COLOR]

;=============================
;   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 LOW (high) nibble in port b
						; and preserve HIGH (low) nibble. ;ALTERED TO ALLOW THE USE OF LOWER NIBBLE (RB0 - RB3) TO CONNECT TO LCD D7 - D4. -PREVIOUSLY WAS B'00001111'.
	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 reproduced the delay code here:

;=======================
; Procedure to delay
; 125 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



Thanks in advance.

- Analogue.
 
Last edited:
I didn't look at everything, but just as a tip I would suggest getting a copy of PIC LOOPS and make sure you make the delays the same time period as they were on the faster clocks.
 
The display should work correctly at any frequency. The delays may get incredibly long at low frequencies but should eventually time out. I suspect it maybe your config value but I have no idea what that hex value represents. Maybe the WDT is timing out at lower frequencies. Change the config to use the Microchip supplied labels and all may become clear.

Mike.
 
The display should work correctly at any frequency. The delays may get incredibly long at low frequencies but should eventually time out. I suspect it maybe your config value but I have no idea what that hex value represents. Maybe the WDT is timing out at lower frequencies. Change the config to use the Microchip supplied labels and all may become clear.

This is excellent advice that shouldn't be ignored...
 
Last edited:
@ Mike (Pommie): thanks for the info. The config "3F10" means:

OSC: Oscillator: INTRC-RA6 is Port I/O

WDT: Watchdog Timer: Off

PUT: Power Up Timer: On

MCLRE: MCLR Select Bit: RA5 is digital I/O, MCLR tied to VDD

BODEN: Brown Out detect: Off

LVP: Low Voltage Program: Disabled

CPD: Data EE Read protect: Disabled

WRT_ENABLE: Flash Program Write: Write Protection Disabled

CCP1MUX: CCP1 Mux: RB2

CP: Code Protect: Disabled

- When you refer to "Microchip supplied labels", do you mean this style of programming:

"__CONFIG _HS_OSC & _WDT_OFF & _LVP_OFF...", etc?

I hope this isnt' a daft question: are the delays required by the display constant across all frequencies, so if some procedure takes say 20 milliseconds at 8 MHz it will still take that length of time at 31.25 KHz?
 
Last edited:
@ Mike (Pommie): thanks for the info. The config "3F01" means:

OSC: Oscillator: INTRC-RA6 is Port I/O

WDT: Watchdog Timer: Off

PUT: Power Up Timer: On

MCLRE: MCLR Select Bit: RA5 is digital I/O, MCLR tied to VDD

BODEN: Brown Out detect: Off

LVP: Low Voltage Program: Disabled

CPD: Data EE Read protect: Disabled

WRT_ENABLE: Flash Program Write: Write Protection Disabled

CCP1MUX: CCP1 Mux: RB2

CP: Code Protect: Disabled

- When you refer to "Microchip supplied labels", do you mean this style of programming:

"__CONFIG _HS_OSC & _WDT_OFF & _LVP_OFF...", etc?

I hope this isnt' a daft question: are the delays required by the display constant across all frequencies, so if some procedure takes say 20 milliseconds at 8 MHz it will still take that length of time at 31.25 KHz?
hi AR,
You have a typo.
processor 16f819 include <p16F819.inc> __config H'3F10';
 
@ Mike, K8LH: thanks for your input.

hi,
Look here on your hard drive, if you have used the Microchip default folder
C:\Program Files\Microchip\MPASM Suite\Template\Code

Look for 16F819TEMP.asm
 
Hello Eric, well spotted! Thanks for pointing out my mistake: as you say, it's meant to be "3F10". - Will edit.

- Just looked up the 16F819TEMP.asm file you mentioned: it spells out the config bits in full. - Thanks.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top