Help: how To Display RTC on 16x2LCD with PIC18F2520

Status
Not open for further replies.

Boomslang

Member
Hi all

I am a beginner, trying to build a Temp controller that will keep the stats like temp at hour intervals for the last month etc. The temp controller will have one heating and one cooling output. Setting up the menus and outputs is not that hard, but I know reading the thermistor (ADC) and this RTC part will be the hardest. I am stuck on the RTC for now... I almost know the 2520 data sheets by hart by now, but that did not help me enough... In my code I just tried to display one digit of the secs for testing (must still figure out how to display the second digit), but it's not counting up...
Any help or info will be appreciated...

Code:
;******************************************************************************
;                                                                             *
;    Filename:  Temperature Controller based on PIC18F2520         	          *
;	 =====================================================    				  *
;																			  *
;   																		  *
;	 							                                              *
;	 Program written by D, Jordaan 											  *
;	 																		  *		
;	 V1.00  Aug 2007  Initial menu											  *
;																			  *
;******************************************************************************
;
;	Processor Type
;	==============										
;
	LIST P=18F2520,r=hex,n=80,x=off,st=off
	errorlevel -302		; no bank warnings

	#include <P18F2520.INC>	

; 	DELAY PARAMETERS FOR 4MEG CRYSTAL

clock	equ	4000000		; my crystal frequency
dusec	equ	1000		; required delay (1 mSec)
   #include <timer.inc>	; note, include must be after these two definitions

;******************************************************************************
; 
;	Configuration bits 
;	==================
; specified here are changes to the .inc file defaults

 CONFIG OSC=INTIO67, PWRT=ON, BOREN=OFF, WDT=OFF, MCLRE=OFF, LPT1OSC=OFF, PBADEN=OFF
 CONFIG LVP=OFF, XINST=OFF, DEBUG=OFF

;******************************************************************************
;
;	Variable definitions
;	====================

;	Bank1 variables 0x100 to 0x1FF

	cblock	0x100		; BANK1			
	pntr
	offset
	dval
	lcd_flags		
	lcd_temp
	t0
	t1
	t2
	t3
	t4
	t5
	t6
	t7	
	t8			
	t9	
	t10
	t11
	t12		
	t13					
	t14
	t15
	t16
	t17
	t18
	t19
	t20	
	c0			
	c1
	c2
	c3	
	c4
	c5
	c6
	c7		
	c8				
	c9	
	c10
	c11
	c12
	c13
	c14
	c15
	c16
	c17
	c18
	c19							;40
	c20
	RB0CP
	secs
	mins
	hours
	endc							; last address entered   max FF
				

LEDPORT1	Equ	PORTA			;set constants for output ports
LEDPORT_1	Equ	2
LEDPORT2	Equ	PORTA
LEDPORT_2	Equ	1
LEDPORT3	Equ	PORTC
LEDPORT_3	Equ	3
LEDPORT4	Equ	PORTB
LEDPORT_4	Equ	0
LEDPORT5	Equ	PORTC		
LEDPORT_5	Equ	4
LEDPORT6	Equ	PORTC
LEDPORT_6	Equ	5
LEDPORT7	Equ	PORTC
LEDPORT_7	Equ	6
LEDPORT8	Equ	PORTC
LEDPORT_8	Equ	7

SWPORT1		Equ	PORTA			;set constants for input ports
SWPORT_1	Equ	5
SWPORT2		Equ	PORTA
SWPORT_2	Equ	4
SWPORT3		Equ	PORTE
SWPORT_3	Equ	3
SWPORT4		Equ	PORTA
SWPORT_4	Equ	3
SWPORT5		Equ	PORTC
SWPORT_5	Equ	2



;******************************************************************************
;
;	Reset vector
;	============

		ORG	0x0000

bootup	goto	Main		;go to start of main code

		ORG 0008h  ; an interrupt redirects the program to here

 RTCisr 									; Start ISR here
										; Insert the next 4 lines of code when TMR1
										; can not be reliably updated before clock pulse goes low
;		BTFSC 	TMR1L,0 				; wait for TMR1L<0> to become clear
;		BRA 	$-2 					; (may already be clear)
;		BTFSS 	TMR1L,0 				; wait for TMR1L<0> to become set
;		BRA 	$-2 					; TMR1 has just incremented
										; If TMR1 update can be completed before clock pulse goes low
		BSF 	TMR1H, 7 				; Preload for 1 sec overflow
		BCF 	PIR1, TMR1IF 			; Clear interrupt flag
		INCF 	secs, F 				; Increment seconds
		MOVLW 	.59 					; 60 seconds elapsed?
		CPFSGT 	secs
		RETFIE ;RETURN 							; No, done
		CLRF 	secs 					; Clear seconds
		INCF 	mins, F					; Increment minutes
		MOVLW 	.59 					; 60 minutes elapsed?
		CPFSGT 	mins
		RETFIE; RETURN 							; No, done
		CLRF 	mins					; clear minutes
		INCF 	hours, F 				; Increment hours
		MOVLW 	.23 					; 24 hours elapsed?
		CPFSGT 	hours
		RETFIE  ;RETURN 							; No, done
		CLRF 	hours					; Reset hours
		RETFIE  ;RETURN 							; Done 



;******************************************************************************
;******************************************************************************
;
;	Start of main program
;	=====================

; initialisation of system, clear RAM , setup i/o ports



Main	movlb	D'1'			; define bank1, so it and bank 0/15 (access) 
								; can be addressed without banking
 		clrf 	INTCON			; clear interupts
 		clrf	STATUS			; reset to bank 0
 

clearam	clrf	FSR1H			; FSR routine to clear ram banks 0 -4 only
		clrf	FSR1L		
clrram	clrf	POSTINC1		; clear location and inc
 		movlw	0x05			; now in bank5 ?
 		subwf	FSR1H,W
 		bnz		clrram			; carry on clearing if not at bank5



; *****************************************************************************
;
; Port Allocation - Standard Multi Controller on 2520 chip
;
;
; PortA  ra0	AI	NTC1			PortB  	rb0		OUT  TIMER3		
;		 ra1	OUT HEATER				 	rb1		lcd e1				
;	     ra2	OUT COOLER1				  	rb2		lcd rs		
;		 ra3	IN  SW3					  	rb3		lcd rw		
;        ra4	IN	KEY A		   			rb4		lcd	d4		
;		 ra5	IN 	KEY B		  		 	rb5		lcd d5				
;        ra7	IN  Unalloc				   	rb6		lcd	d6		
;		 ra6	IN  Unalloc				   	rb7		lcd d7			


; PortC	rc0		timer1 xtal         PortE	re3		IN  EXT ALARM
;		rc1		timer1 xtal1				( set by config )
;	    rc2		IN	SW4
;		rc3		OUT  COOLER2
;       rc4   	OUT	 LIGHT1
;		rc5		OUT  LIGHT2
;      	rc6 	OUT  TIMER4
;		rc7		OUT	 ALARM

ports	clrf	PORTA
		clrf	PORTB
		clrf	PORTC
		
		movlw	b'00001110'		; set portA,0 as adc input bit 7 rjust
		movwf	ADCON1			; by loading value to adcon1 reg
		movlw	b'00111001'		; set trisa direction is input
		movwf	TRISA			; bit0 adc, bit1,2 DO, bit3,4,5 DI , bit7,6 DO

		movlw	b'00000000'		; set portB as low outputs
		movwf	TRISB

		movlw	b'00000100'		; set portC low outputs,  except rc2 DI
		movwf	TRISC
	
; ***************************************************************************
;
;	Start Timers
;	============

; Timer0 as base for Delay 1ms

		movlw	b'11010000' | PRESCL
		movwf	T0CON
;		movlw	b'00000001'
;		movwf	PIE1
;		movlw	b'00000001'
;		movwf	IPR1
RTCinit
		MOVLW 	80h 					; Preload TMR1 register pair
		MOVWF 	TMR1H 					; for 1 second overflow
		CLRF 	TMR1L
		MOVLW 	b'00001111' 			; Configure for external clock,
		MOVWF 	T1CON 					; Asynchronous operation, external oscillator
		CLRF 	secs 					; Initialize timekeeping registers
		CLRF 	mins 					;
		MOVLW 	.12
		MOVWF 	hours
		BSF 	PIE1, TMR1IE 			; Enable Timer1 interrupt
;		RETURN
		
; ***************************************************************************
;
;	Init LCD Display 
;   ================

; eedata routines inserted in middle of initlcd routine
; needed to come after the setemps which restore eprom

		call	lcd_init				; initialise the LCD driver
	
; ***************************************************************************
;
;	Running Program Starts Here 
;   ===========================

loop	call	dataone
		call 	datatwo

		call	sendone
		call	sendtwo

MainMen	btfss	SWPORT1,	SWPORT_1		;enter menu if SW1 pushed
		goto	LED1ON

		goto	loop

;===============================================================================
;
;   SUBROUTINES
;
;===============================================================================

;*************************************************************************
;Real-time Clock
;*************************************************************************

;*************************************************************************
; Main Menu
;*************************************************************************

LED1ON	bsf		LEDPORT1,	LEDPORT_1		;turn LED1 on
		call	DataLed1					
		call	sendone						;Send Led 1 on message
		call	DoDelay30					;wait a bit
		goto 	LED1_2

LED1_2	btfss	SWPORT1,	SWPORT_1		;check if switch pushed again
		goto 	LED2ON						;yes, goto switch led2 on
		goto 	LED1_2						;no, loop and check again

LED2ON	bcf		LEDPORT1,	LEDPORT_1		;turn LED 1 off
		bsf		LEDPORT2,	LEDPORT_2		;turn LED2 on
		call	DataLed2
		call	sendone						;send LED 2 on message
		call	DoDelay30					;wait a bit
		goto	LED2_2

LED2_2	btfss	SWPORT1,	SWPORT_1		;is SW1 pushed?
		call 	ClearPorts					;yes, turn all LED's off and exit menu
		goto	LED2_2						;no, loop and check again
	
ClearPorts
		bcf		LEDPORT1,	LEDPORT_1		;Switch off led's
		bcf		LEDPORT2,	LEDPORT_2
		call 	DoDelay30
		goto 	loop

; ***************************************************************************
;
;   Delay Routine for LCD 
;	=====================

; using the internal timer, will delay for W times the value of 
; "dusec" in microseconds. (used by lcd routine)

delay	movwf	dval
dy1		clrf	TMR0L
		bcf		INTCON,T0IF
		movlw	TMRVAL			; set timer
		movwf	TMR0L
dy2		btfss	INTCON,T0IF		; timer overflow yet?
		goto	dy2				; no
		decfsz	dval,f			; yes, all cycles?
		goto	dy1				; no
		return					; yes, delay finished

; ***************************************************************************
;
;   Macros for LCD routine
;	======================


dotris	macro arg1, arg2
	movlw	arg1
	movwf	arg2
	endm

dodelay	macro arg1
	movlw	arg1
	call	delay
	endm

DoDelay30
	dodelay 30
	return
;****************************************************************************
;
;    Routines to display on a 2x16 character LCD    Standard 7 bit version
;	 ===========================================    ======================

;
; LcdInit - call this subroutine before using the display. It uses
;           bits 7-1 of PORTB, leaving bit-0 free (although it will
;           be configured as an output).
;
; Lcd_C -   Sends the byte in W as a command to the display. Checks
;           if busy first. 
;
; Lcd_D -   Sends the byte in W as data. Checks for busy first.
;
; Assumes it can call a routine called "delay" with a required
; time delay in mSecs in W. 
; Uses an additional three (3) levels of the stack.
;
; Address of first line on the LCD is 0
; Address of second line is 64
;
; by Ron Kreymborg
;
;******************************************************************

lcd_com	macro	arg1
	movlw	arg1
	call	lcd_c
	endm
	
; Flags -
lcd_Bflg	equ	0
lcd_RSflg	equ	1

; I/O portB - 
lcd_BUSY	equ	7		; input - LCD is busy (0x80)
lcd_R_W		equ	3		; output - LCD Read/Write (0x08)
lcd_RS		equ	2		; output - Register Select (0x04)
lcd_E		equ	1		; output - LCD Enable (0x02)



lcd_init
	clrf	PORTB
	dotris	b'00000000',PORTB	; all outputs and low to start
	bcf	lcd_flags,lcd_RSflg
	dodelay	15					; 15mSec power up delay		
	movlw	b'00110000'			; 8-bit mode
	movwf	PORTB
	call	lcd_clk
	dodelay	4					; 4mSec wait
	movlw	b'00110000'			; 8-bit mode
	movwf	PORTB
	call	lcd_clk
	dodelay	1					; 1 mSec wait
	movlw	b'00110000'			; 8-bit mode
	movwf	PORTB	
	call	lcd_clk
	dodelay	4					; 4mSec wait
	movlw	b'00100000'			; set for 4-bit
	movwf	PORTB
	call	lcd_clk

; Reset sequence is done - initialise for us

	lcd_com	b'00101000'			; 4-bits, 2-lines, 5x7
	lcd_com	b'00001000'			; display off, cursor off, blink off
	lcd_com	b'00001100'			; display on
	lcd_com	b'00000001'			; clear display
	lcd_com	b'00000110'			; increment, no display shift

	return

	
	
; Check whether the LCD is busy. Loop until it isn't. When
; it's free, output the byte passed in W, MS nibble first.

lcd_d	bsf	lcd_flags,lcd_RSflg		; set RS flag for data
		goto	lcd_o1
lcd_c	bcf	lcd_flags,lcd_RSflg		; clear RS flag for commands
lcd_o1	movwf	lcd_temp			; save control word
		dotris	b'11110000',PORTB	; RB7-4 as inputs for busy
		movlw	1 << lcd_R_W
		movwf	PORTB				; set up for read
	
lcd_o2	bcf	lcd_flags,lcd_Bflg		; assume not busy
		bsf	PORTB,lcd_E				; clock high
		nop							; little wait
		btfsc	PORTB,lcd_BUSY		; busy set?
		bsf	lcd_flags,lcd_Bflg		; yes
		bcf	PORTB,lcd_E				; clock low
		nop							; little wait
		nop
		call	lcd_clk				; get low bits but ignore (for now)
		btfsc	lcd_flags,lcd_Bflg	; was it busy?
		goto	lcd_o2				; yes
		dotris	b'00000000',PORTB	; RB7-4 outputs again

		movf	lcd_temp,w			; get word to send
		call	lcd_o3				; send high nibble
		swapf	lcd_temp,w			; get word again
lcd_o3	andlw	0xf0				; just high bits (clears all control bits)
		movwf	PORTB
		btfsc	lcd_flags,lcd_RSflg	; was lcd_RS set?
		bsf		PORTB,lcd_RS		; yes
		call	lcd_clk				; write current nibble

		return
	

lcd_clk	bsf	PORTB,lcd_E				; pulse E line high
		nop
		bcf	PORTB,lcd_E

		return


;****************************************************************************

; ***************************************************************************
;
; 	SR	SEND LCD DISPLAY LINE 1
;	===========================


sendone 
	movf	c0,w			; get 1st ram 
	iorlw	0x80			; add address for command line	
	call    lcd_c			; for line of lcd
	movf	c1,w
	call	lcd_d
	movf	c2,w
	call	lcd_d
	movf	c3,w
	call	lcd_d
	movf	c4,w
	call	lcd_d
	movf	c5,w
	call	lcd_d
	movf	c6,w
	call	lcd_d
	movf	c7,w
	call	lcd_d
	movf	c8,w
	call	lcd_d
	movf	c9,w
	call	lcd_d
	movf	c10,w
	call	lcd_d
	movf	c11,w
	call	lcd_d
	movf	c12,w
	call	lcd_d
	movf	c13,w
	call	lcd_d
	movf	c14,w
	call	lcd_d
	movf	c15,w
	call	lcd_d
	movf	c16,w
	call	lcd_d
	movf	c17,w
	call	lcd_d
	movf	c18,w
	call	lcd_d
	movf	c19,w
	call	lcd_d
	movf	c20,w
	call	lcd_d
	
	return	


; ***************************************************************************
;
;   SR	SEND LCD DISPLAY LINE 2
;	===========================


sendtwo 
	movf	t0,w			; get 1st ram 
	iorlw	0x80			; add address for command line	
	call    lcd_c			; for line2 of lcd
	movf	t1,w
	call	lcd_d
	movf	t2,w
	call	lcd_d
	movf	t3,w
	call	lcd_d
	movf	t4,w
	call	lcd_d
	movf	t5,w
	call	lcd_d
	movf	t6,w
	call	lcd_d
	movf	t7,w
	call	lcd_d
	movf	t8,w
	call	lcd_d
	movf	t9,w
	call	lcd_d
	movf	t10,w
	call	lcd_d
	movf	t11,w
	call	lcd_d
	movf	t12,w
	call	lcd_d
	movf	t13,w
	call	lcd_d
	movf	t14,w
	call	lcd_d
	movf	t15,w
	call	lcd_d
	movf	t16,w
	call	lcd_d
	movf	t17,w
	call	lcd_d
	movf	t18,w
	call	lcd_d
	movf	t19,w
	call	lcd_d
	movf	t20,w
	call	lcd_d

	
	return


; ***************************************************************************
;
;	SR	LCD DATA MESSAGES
;   ====================


dataone movlw	0x00	; lcd line1 ram message	
	movwf	c0		
	movlw	'T'			
	movwf	c1			
	movlw	'I'
	movwf	c2
	movlw	secs		;'M'
	movwf	c3	
	movlw	'E'
	movwf	c4
	movlw	' '
	movwf	c5
	movlw	'2'
	movwf 	c6
	movlw	'3'
	movwf	c7
	movlw 	':'
	movwf	c8
	movlw 	'0'
	movwf	c9
	movlw   '0'
	movwf	c10
	movlw	' '
	movwf	c11
	movlw 	' '
	movwf	c12
	movlw 	' '
	movwf	c13
	movlw	' '
	movwf	c14
	movlw 	' '
	movwf	c15
	movlw 	' '
	movwf	c16
	movlw	' '
	movwf	c17
	movlw 	' '
	movwf	c18
	movlw 	' '
	movwf	c19
	movlw 	' '
	movwf	c20

	return



datatwo	movlw	0x40	; lcd line2 ram message	
	movwf	t0		
	movlw	'T'			
	movwf	t1			
	movlw	'E'
	movwf	t2
	movlw	'M'
	movwf	t3	
	movlw	'P'
	movwf	t4
	movlw	' '
	movwf	t5
	movlw	'C'
	movwf 	t6
	movlw	'O'
	movwf	t7
	movlw 	'N'
	movwf	t8
	movlw	'T'
	movwf	t9
	movlw	'R'
	movwf	t10
	movlw	'O'
	movwf	t11
	movlw	'L'
	movwf	t12
	movlw	'L'
	movwf	t13
	movlw	'E'
	movwf	t14
	movlw	'R'
	movwf	t15
	movlw	' '
	movwf	t16
	movlw	' '
	movwf	t17
	movlw	' '
	movwf	t18
	movlw	' '
	movwf	t19
	movlw	' '
	movwf	t20	

	return

DataLed1 
	movlw	0x00	; lcd line1 ram message	
	movwf	c0		
	movlw	'L'			
	movwf	c1			
	movlw	'E'
	movwf	c2
	movlw	'D'
	movwf	c3	
	movlw	' '
	movwf	c4
	movlw	'O'
	movwf	c5
	movlw	'N'
	movwf 	c6
	movlw	'E'
	movwf	c7
	movlw 	' '
	movwf	c8
	movlw 	'O'
	movwf	c9
	movlw   'N'
	movwf	c10
	movlw	' '
	movwf	c11
	movlw 	' '
	movwf	c12
	movlw 	' '
	movwf	c13
	movlw	' '
	movwf	c14
	movlw 	' '
	movwf	c15
	movlw 	' '
	movwf	c16
	movlw	' '
	movwf	c17
	movlw 	' '
	movwf	c18
	movlw 	' '
	movwf	c19
	movlw 	' '
	movwf	c20

	return

DataLed2 
	movlw	0x00	; lcd line1 ram message	
	movwf	c0		
	movlw	'L'			
	movwf	c1			
	movlw	'E'
	movwf	c2
	movlw	'D'
	movwf	c3	
	movlw	' '
	movwf	c4
	movlw	'T'
	movwf	c5
	movlw	'W'
	movwf 	c6
	movlw	'O'
	movwf	c7
	movlw 	' '
	movwf	c8
	movlw 	'O'
	movwf	c9
	movlw   'N'
	movwf	c10
	movlw	' '
	movwf	c11
	movlw 	' '
	movwf	c12
	movlw 	' '
	movwf	c13
	movlw	' '
	movwf	c14
	movlw 	' '
	movwf	c15
	movlw 	' '
	movwf	c16
	movlw	' '
	movwf	c17
	movlw 	' '
	movwf	c18
	movlw 	' '
	movwf	c19
	movlw 	' '
	movwf	c20

	return

	END

and the timer.inc file needed for the lcd:

Code:
; PRESCL and TIMER computation
	nolist
; Take the processor clock frequency in Hz (clock), and
; the required time delay in uSecs (dusec), and compute
; a value for the prescaler (PRESCL) and another for
; TMR0 (TIMER).

_cycle	equ	clock >> 2
_dfreq	equ	1000000 / dusec
_divr	equ	_cycle / _dfreq
	if (_divr < 512)
	error "Delay time too short. Assign PSA to WDT."
	endif
_test	set	_divr / 256
_testB	equ	_divr % 256
	if (_testB > 0)
_test	set	_test + 1
	endif
	if (_test > 1)
_temp	set	2
PRESCL	set	0
	endif
	if (_test > 2)
_temp	set	4
PRESCL	set	1
	endif
	if (_test > 4)
_temp	set	8
PRESCL	set	2
	endif
	if (_test > 8)
_temp	set	16
PRESCL	set	3
	endif
	if (_test > 16)
_temp	set	32
PRESCL	set	4
	endif
	if (_test > 32)
_temp	set	64
PRESCL	set	5
	endif
	if (_test > 64)
_temp	set	128
PRESCL	set	6
	endif
	if (_test > 128)
	error "Timer requirement is outside range"
	endif
TMRVAL	equ	256 - (_cycle / _temp / _dfreq)
	list

Thanks again...
 
well...

I've not worked much on RTC.. but i can give some suggestions:

1. there are number of RTC's available.. which RTC you are using.. mention that... is it DS1307..?

2. for betterment of yours.. i ask you to follow C-language , JAVA or BASIC for programming of microcontrollers.. Specially when your code is as big as this...

3. i hope you understand I2C communication.. till you get a good reply.. try searhing in this forum on the name RTC and I2C..

regards,

simran..
 
I am using the internal timer1 with a 32.768 khz external oscilator, from the datasheet it looks like it will be accurate enough...
 
Boomslang said:
I am using the internal timer1 with a 32.768 khz external oscilator, from the datasheet it looks like it will be accurate enough...

Yes, that's what it's designed to do.
 
The only part I am worried to get working now is TMRisr, but I am not sure if I am correct with using org 0008h, and if I set the interrupt enable bits correct... I set a break point at the start of TMRisr, but it's never called when run in mplab sim..
 
Do you need to set the PEIE (Peripheral interrupt enable) bit and the GIE (Global Interrupt Enable) bit?

Mike.
 
Last edited:
I don't know, I tried setting everying in every way I could think, but nothing helped..., I think it should be on otherwise TMRisr will not be called to incf every 1 sec when tmr1 overflows...
 
Last edited:
Have you tried it in an actual circuit?, simulators aren't the real world and often don't work as expected - MPLAB is well known for it's limitations.
 
Yes, I tried it on my dev board, it just stays on zero, my inputs are still working OK, its just as if no interrupt is sent, or it did not enable all the right stuff......... fun and games....
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…