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.

Help me to calculate the interrupt time

Status
Not open for further replies.

Suraj143

Active Member
Hi I have this program which turns ON & OFF a led with a calculated time.
I want to calculate what’s the exact led ON time & led OFF time using a simulator or any other method.

I don’t know in what rate this led turns on & off.

My Oscillator = 4 MHz

Please help me to calculate this.

Code:
		List	p=16F628A
		include	<P16F628A.inc>
		errorlevel	-302
		__config	3F18h	
			
		cblock	20h
		W_Temp,S_Temp,TIME
		endc
		
#define		LED	PORTB,0

		org	0000h
		goto	Start
		
;***********
;ISR routine
;***********		
		org	0004h
		bcf	INTCON,GIE
		movwf	W_Temp
		swapf	STATUS,W
		movwf	S_Temp
		
		btfss	INTCON,T0IF
		goto	Away
		bcf	INTCON,T0IF
		
		movlw	.6
		addwf	TMR0,F
		incf	TIME,F
		movf	TIME,W
		andlw	7fh
		xorlw	.125
		btfss	STATUS,Z
		goto	Away
		btfss	TIME,7
		goto	$+4
		clrf	TIME
		bcf	LED			;turn OFF led
		goto	Away
		clrf	TIME
		bsf	TIME,7		
		bsf	LED			;turn ON led
		
Away		swapf	S_Temp,W
		movwf	STATUS
		swapf	W_Temp,F
		swapf	W_Temp,W
		bsf	INTCON,GIE
		retfie
		
;*******************************
;Initialisation -setup the ports
;*******************************
				
Start		bsf	STATUS,RP0
		clrf	TRISB
		movlw	b'00000011'		;set prescaller to 16
		movwf	OPTION_REG
		bsf	INTCON,T0IE
		bsf	INTCON,GIE
		bcf	STATUS,RP0
		clrf	PORTB
		
Hang		nop
		goto	Hang		
		
		
		end
 
You are adding 6 to Timer 0 every interrupt, you have the prescaler set to 16 and so you will get an interrupt every (256-6)*16 = 4000 cycles. You then count to 125 before toggling your LED, therefore your LED changes state every 4000*125 cycles or every ½ second.

If you use the simulator in MPLAB and set breakpoints on each write to the LED, you can then use the stopwatch to time the on/off times.

BTW, your delay is not exact as when you write to TMR0 it resets the prescaler and throws the count out slightly.

Mike.
 
Oh I see now I got it.1usX16X250X125 = 500ms.
If you use the simulator in MPLAB and set breakpoints on each write to the LED, you can then use the stopwatch to time the on/off times.

I must give a try to simulate that. If I have a 10mins time period, in the simulator do I have to wait 10mins to view the stopwatch because stopwatch increments every cycle so for 10 mins I have to wait very long?

BTW, your delay is not exact as when you write to TMR0 it resets the prescaler and throws the count out slightly.

That’s what I’m thinking too because inside ISR it has over 16 cycles so it will add 1 to TMR0 inside the ISR. Is this coding good? I’m going to make a clock from it.

Thanks Mike
 
The simulator runs at about half speed on my machine. So, for 10 mins you will have to wait about 20 mins. In reality you don't need to wait 10 mins because if your ½ second ISR is accurate then all other times will be.

If you are going to make a clock then this code is not good. A better way is to use timer 2 and set PR2 to 249.

Mike.
 
Ok thanks mike. I’ll try to add TMR2 & check.

For the time being do I have to adjust something in this coding?
 
Here is your code modified to use Timer 2. This will be very accurate as a clock. I'll let you work through the data sheet to work out what it's doing. Note that you don't need to touch GIE in the ISR.

Mike.
Code:
		List	p=16F628A
		include	<P16F628A.inc>
		errorlevel	-302

		__config	3F18h	
			
		cblock	20h
		W_Temp,S_Temp,TIME
		endc
		
#define		LED	PORTB,0

		org	0000h
		goto	Start
		
;***********
;ISR routine
;***********		
		org	0004h
	;	bcf	INTCON,GIE	<-----Not needed
		movwf	W_Temp
		swapf	STATUS,W
		movwf	S_Temp
		
		btfss	PIR1,TMR2IF
		goto	Away
		bcf	PIR1,TMR2IF
		
		incf	TIME,F
		movf	TIME,W
		andlw	7fh
		xorlw	.125
		btfss	STATUS,Z
		goto	Away
		btfss	TIME,7
		goto	$+4
		clrf	TIME
		bcf	LED			;turn OFF led
		goto	Away
		clrf	TIME
		bsf	TIME,7		
		bsf	LED			;turn ON led
		
Away		swapf	S_Temp,W
		movwf	STATUS
		swapf	W_Temp,F
		swapf	W_Temp,W
	;	bsf	INTCON,GIE	<-----Not needed
		retfie
		
;*******************************
;Initialisation -setup the ports
;*******************************
				
Start		bsf	STATUS,RP0
		clrf	TRISB
		movlw	b'0000011'		;set prescaller to 16
		movwf	OPTION_REG
		bsf	INTCON,GIE
		bcf	STATUS,RP0
		clrf	PORTB
	
		movlw	b'00000110'		;prescaler = 16
		movwf	T2CON
		bsf	STATUS,RP0
		bsf	PIE1,TMR2IE
		movlw	.249
		movwf	PR2
		bcf	STATUS,RP0
		bsf	INTCON,PEIE
	

Hang		nop
		goto	Hang		
		
		
		end
 
Oh my god you have done a great part. For sure I’m going to add your coding.
Plenty things to learn.And your previous codings worked well.Didn't give any problem.

Thank you very much mike if you are not here I’ll lost.
 
Building a clock without drift will be difficult I imagine, due to not having precise timing. I may be wrong, but you may be better off trying to interface with a RTC. There was a thread about that not too long ago. For short time periods it would work fine, but I imagine the drift would be noticeable after a few hours.
 
It should be accurate to a couple of seconds per day - worst case. For better accuracy a 32k watch crystal on timer1 should be as accurate as a RTC module. To implement a RTC using timer1 is simple and Microchip even supply the code in the 16F88 data sheet.

Mike.
 
It's relatively easy to implement a soft trim routine in the ISR to adjust the 1 second "heartbeat" with 1 Tcy (1 instruction cycle) resolution. This mechanism has provided accuracy to within about 1/2 second per month using standard 50 ppm (16/20 MHz) crystals in normal room temperatures on several of my projects.
Code:
;
;  ISR_Trim routine is used to adjust the RTC 1-second period to
;  within plus or minus 200-nsecs to make up for a crystal which
;  may be slightly off frequency.  The routine adds or subtracts
;  one 200-nsec count (1 Tcy) from Timer 2 for the first 'CCTR'
;  number of 1-msec interrupts each second. Theoretical accuracy
;  to within 6.3 secs/year, not including temperature drift and
;  crystal aging.
;
;   variables:  CCNT, correction count from EEPROM [00 to FF]
;               CVAL, correction value from EEPROM [FF or 01]
;               CCTR, correction counter reloaded from 'CCNT'
;                     variable each 1-second period
;
;       range:  ±255 200-nsec counts/second (±51.0 usecs/sec)
;
ISR_Trim
        movf    CCTR,W          ; correction counter 0?           |B0
        bz      ISR_Sw_Input    ; yes, branch, else               |B0
        decf    CCTR,f          ; decrement counter               |B0
        movf    CVAL,W          ; get correction value FF or 01   |B0
        addwf   TMR2,f          ; apply 1 Tcy timer correction    |B0
Code:
;
;  reload timer Trim correction counter (once per second)
;
        movf    CCNT,W          ; reload correction counter var   |B0
        movwf   CCTR            ;                                 |B0
;
An RTC chip and 32.768 KHz crystal isn't really any more accurate but it does have the advantage of maintaining the time while running off of a battery backup. Same thing for the special low power Timer 1 oscillator and 32.768 KHz crystal which will run in Sleep mode.
 
Last edited:
Hi thanks for the very useful replies.I'll make note on that.

I applied Mikes (Pommie) coding it worked very well.

I have a small problem to ask.In the ISR I can write only 4000 cycles.
If it exceeds 4000 cycles it will generate an interrupt.

For example if my multiplexing (SSD) routine exceeds 4000 cycles it will
generate an interrupt & goes to begining of the ISR routine so it will not
show the balance remaing digits.

Is this true?

If I place the multiplex routine in the main menu also same thing will be
happens.because its exceeding 4000 cycles.

any idea.
 
You shouldn't put any delays in your ISR. If you want to multiplex displays then update 1 display per interrupt.

For example, say you have 5 displays and you want to refresh at 50Hz, you would interrupt at 250Hz (4000 cycle - that was lucky ;) ) and update 1 display each interrupt. You would place your display code at the "Away" label and return from the interrupt.

Mike.

Your code at Away would be something like,
Code:
Away		incf	Digit,F		;inc digit counter
		movfw	Digit		;fetch it
		xorlw	.5		;reached 5?
		btfsc	STATUS,Z	;skip if not=5
		clrf	Digit		;yes, clear it
		movfw	Digit		;get value again
		addlw	0xff		;add -1
		btfsc	STATUS,Z	;reached Zero yet
		goto	DoDigit0	;yes, display this one.
		addlw	0xff		;add -1
		btfsc	STATUS,Z
		goto	DoDigit1
		addlw	0xff
		btfsc	STATUS,Z
		goto	DoDigit2
		addlw	0xff
		btfsc	STATUS,Z
		goto	DoDigit3
		addlw	0xff
		btfsc	STATUS,Z
		goto	DoDigit4

DoneDigits	swapf	S_Temp,W
The DoDigitx routines would write the digit to the SSD and set the correct digit bit and then jump to DoneDigits.

You can use indirect addressing to do this but it's probably simpler to do it this way at your stage.
 
Last edited:
Hi Mike give me time to look into your display routine it will take some days.

BTW
I’m going to use TIMER2 settings to generate the 1 sec time base as earlier suggested.

But when I was making experiments with TMR0 I wrote a new coding. In the simulator it gives me better accuracy than my first post coding in this thread.

Note that I’m not using this code I’m going to use TIMER2 coding. I just want to know whether this is good or not?

Code:
		#include <P16F628A.inc>
		errorlevel -302
		__config	3F18h
		
		cblock	70h
		W_Temp,S_Temp,COUNT
		endc

		org	0x0000
		goto	Start

		org	0x0004
interrupt	movwf	W_Temp			;2latent +1 =3
		swapf	STATUS,W		;+1 =4
		movwf	S_Temp			;+1 =5
		bcf	STATUS,RP0		;+1 =6
		bcf	STATUS,RP1		;+1 =7
		movlw	100h-d'78'		;+1 =8
		goto	$+1			;+2 =10
		goto	$+1			;+2 =14
		nop				;+1 =15
		movwf	TMR0			;+1 =16 + 78*128 = 10,000
		bcf	INTCON,T0IF		;reset int flag			
			
		decfsz	COUNT,F
		goto	$+3
		movlw	.100
		movwf	COUNT			
		movf	COUNT,W
		sublw	.50
		btfsc	STATUS,C
		bsf	PORTB,0
		btfss	STATUS,C
		bcf	PORTB,0
			
		swapf	S_Temp,W
		movwf	STATUS
		swapf	W_Temp,F		;swap to file
		swapf	W_Temp,W		;swap to work
		retfie

Start		bsf	STATUS,RP0
		clrf	TRISB						
		movlw	b'00000110'		;set prescaler to 128
		movwf	OPTION_REG			
		movlw	0a0h			;enable timer interupt 
		movwf	INTCON
		bcf	STATUS,RP0
		movlw	.100
		movwf	COUNT
		clrf	PORTB
			
hang		goto	hang

		end
 
That is a better way to use Timer0 but will still be inaccurate due to the 2 cycle instructions in the main code causing the interrupt to execute 1 cycle later. That code looks very familiar, in fact so familiar I think it maybe from an earlier post of mine. Where did you find it?

You can implement a completely accurate timer with Timer0. The secret is to never write to the TMR0 register and therefore never reset the internal prescaler. I'll leave you to try and work out how.

Mike.
 
Yes I gathered some codings from one of your earlier post I studied them & I never throw them away. They are always in my mind.

The above code also writes to TMR0 so it will also reset the Pre Scaller isn’t it?

This is the maximum accuracy that I can get with TMR0.You mean the goto hang code causing the interrupt routine.
 
Hi just a quick question.

I know that when interrupt occurred it’s going to the org 0004h statement.
To go to the interrupt routine does it needs any extra cycles?
I mean
For ex: if I in a 2 cycles instruction when Interrupt occurred does it go suddenly or after completing that 2 cycle is it going?
 
If it is executing a single cycle instruction when the IRQ occurs then it takes 2 or 3 cycles, 0 or 1 to complete the current instruction and 2 to execute the call to 0x004. If it is executing a 2 cycle instruction then it will take 3 to 4 cycles. If it is a sychronous IRQ, such as a timer, then it will take the shorter time.

Mike.
 
Hi Mike I went through your code it worked well. I understood everything except one.This code using TMR2, then whats the point of writing to TMR0 highlighted in red?

TMR2 overflows on every 16 * 249 = 3984 cycles. 16 cycles missing to 4000.

Code:
		List	p=16F628A
		include	<P16F628A.inc>
		errorlevel	-302

		__config	3F18h	
			
		cblock	20h
		W_Temp,S_Temp,TIME
		endc
		
#define		LED	PORTB,0

		org	0000h
		goto	Start
		
;***********
;ISR routine
;***********		
		org	0004h	
		movwf	W_Temp
		swapf	STATUS,W
		movwf	S_Temp
		
		btfss	PIR1,TMR2IF
		goto	Away
		bcf	PIR1,TMR2IF
		
		incf	TIME,F
		movf	TIME,W
		andlw	7fh
		xorlw	.125
		btfss	STATUS,Z
		goto	Away
		btfss	TIME,7
		goto	$+4
		clrf	TIME
		bcf	LED			;turn OFF led
		goto	Away
		clrf	TIME
		bsf	TIME,7		
		bsf	LED			;turn ON led
		
Away		swapf	S_Temp,W
		movwf	STATUS
		swapf	W_Temp,F
		swapf	W_Temp,W	
		retfie
		
;*******************************
;Initialisation -setup the ports
;*******************************
				
Start		bsf	STATUS,RP0
		clrf	TRISB
		[COLOR="Red"]movlw	b'0000011'		;set prescaller to 16
		movwf	OPTION_REG
		bsf	INTCON,GIE[/COLOR]
		bcf	STATUS,RP0
		clrf	PORTB
	
		movlw	b'00000110'		;prescaler = 16
		movwf	T2CON
		bsf	STATUS,RP0
		bsf	PIE1,TMR2IE
		movlw	.249
		movwf	PR2
		bcf	STATUS,RP0
		bsf	INTCON,PEIE
	

Hang		nop
		goto	Hang		
		
		
		end
 
There is no need to setup timer0, I left the write to option register there incase you needed the other bits that are also setup by writing to option (WPUs, WDT etc.). The write to INTCON is required so that timer2 interrupts will work.

TMR2 overflows on every 16 * 249 = 3984 cycles. 16 cycles missing to 4000.

The timer resets on the next increment after it matches PR2. So the actual time is 250*16. The sequence goes 0,1,...248,249,0,1 etc. The sequence 0 to 249 contains 250 values - think of the sequence 0 to 1 and you see that it contains 2 values.

Mike.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top