Paul B. Webster VK2BZC

There are *THREE* ways to achieve this functionality on a PIC with timer and interrupts, *two* on one with timer and no interrupts (16C5xx, 12c5xx). The three ways are: 1} Isosynchronous code - loops performing all functions take a measured time to cycle. Very tedious, virtually impossible in "C".

2} Interrupt-driven. On interrupt, counters are incremented/ decremented and overflow to other counters. The main routine can "peek" at these counters and determine when to perform the necessary task which it does outside of "interrupt time", thus avoiding problems with interrupts overlapping.

To resolve whether the task has been performed at each required interval however, the interrupt routine can set a (series of) flag(s) on certain overflows e.g., each hour. The mainline code then checks if the flag is set *and* the hour is right, if so clears the flag (so it doesn't perform the task twice) and performs the action.

Hint: These flags are all bit flags within a byte; the interrupt routine sets the whole byte. Easier if worked the other way - it clears all the bits at once.

Along this line, it simplifies things a bit if the interrupt routine only deals with say, seconds, setting a flag each second which the main routine uses to advance the second count and count minutes, hours, days etc. But this does lead to the next proposal:

3} Timer-polling. This is the simplest and easiest to code, and can be done on the 12-bit core devices without interrupt hardware. That makes it a very *mature* approach!

The basis is to set up the timer and prescaler so that the timer overflows every so many thousand clock cycles, more than enough to perform either the whole of the "other" functions, or a substantial module of those functions. After performing a function group known to take such a time, you wait polling for the overflow, perform the timing count when it happens and go on to the next function group. Thus for one function:

 While TRUE Do
 main_function
 wait_for_rollover
 timer_count
 Loop

and for multiple parts of code each taking less *on average* than the overflow time:

 While TRUE Do
 main_function1
 wait_for_rollover
 timer_count
 main_function2
 wait_for_rollover
 timer_count
 main_function3
 wait_for_rollover
 timer_count
 main_function4
 wait_for_rollover
 timer_count
 Loop

For example, function 1 can take 1½ times the overflow time while function 2 is very short, the first overflow is serviced before another overflow occurs, and the short second function brings the next overflow in on time. You can even cut it slightly finer than that.

The "rollover" code (should be a subroutine) on the devices with an interrupt flag (T0IF) consists of polling for that flag *and clearing it when found*, but note: no interrupt, specific or global is enabled. (Other interrupts can however be enabled as long as they will not make the mainline code modules run significantly over-time as above.)

The timing cycles are each of the form:

timer macro unit,unit_max,end_time
 decfsz unit
 goto end_time
 movlw unit_max
 movwf unit
 endm
;e.g., for seconds, minutes
 decfsz seconds
 goto done_time
 movlw 60
 movwf seconds
 decfsz minutes
 goto done_time
 movlw 60
 movwf minutes
;could be macro coded as:
 timer seconds,60,done_time
 timer minutes,60,done_time
; ..more timers..
; ..payload; i.e. what you do at the end..
done_time

Further hint on using interrupts and timer in general: IMNSHO don't even *think* of setting/ re-setting/ altering the timer value within the interrupt or poll routine. Always let it count un-impeded, use "nice" numbers. *Far* less heartache that way. KISS!

Øyvind Kaurstad was having a problem with jitter in his timing routine and said:

Immediately after I read TMR0 I also clear it, and this will prevent a new overflow for some time.

But Nikolai warns:

There is a slim chance that TMR0 overflows in the same instruction when you read it. As I understand from datasheets, read is made in the beginning of instruction cycle, and write - in the end. So actually, there is still some room for error. I don't know if this can matter. Best way is compare with this (INTF part of your routine):

Øyvind Kaurstad responded:

I actually discovered this myself yesterday. If I read 0xFF from TMR0 the INTF flag is already set, and my check of the INTF-flag will actually generate a big jitter.

I solved it by checking if my TIMER_STR (copy of TMR0) is 0xFF. If it is, I just skip the INTF-test.

Like this:

movf TMR0,0 ;Read TMR0
clrf TMR0
movwf TIMER_STR ;Store it in TIMER_STR
comf TIMER_STR,0 ;Complementing it, store in W
skpnz ;If it was 0xFF the Z flag will be set
goto $+3 ;and the goto will be performed
btfss INTCON,T0IF ;These two instructions will be skipped
incf TIMER_STR+1,1 ;only if TIMER_STR == 0xFF

This solved my problem! Thanks for all help.

William J. Kitchen says

Make a subroutine that adds the contents of the RTCC to several registers then resets the RTCC. The subroutine has to be called often enough to keep the RTCC from overflowing. This means including a call to it inside all loops. The tricky part is accounting for the time it takes for the subroutine to execute. Here's an example that creates a 24 bit timer:
TIMER
; add RTCC contents to 24 bit value (RTIMEL, RTIMEM, RTIMEH)
; This strange looking addition is designed to execute in exactly
; the same number of cycles regardless of the number of carries.
 movfw RTCC ;
 addwf RTIMEL,F ;
 btfss STATUS,C ;
 goto $+2 ;
 incfsz RTIMEM,F ;
 goto $+2 ;
 incf RTIMEH,F ;
			 ;* reinitialize RTCC
 movlw $+3-TIMER ; this the number of instruction cycles between
 ; the time that the RTCC is read and the time when
 ; it is written, plus 2 more to adjust for the
 ; time that is required for the RTCC to restart
 ; after being written
 movwf RTCC ;
		 ;* return
 retlw 0 ;

This routine will always take exactly the same time to execute.

Unfortunately, using a prescaler with this technique will introduce error because subroutine can be called at varying times relative to the prescaler's interval.

I've used this with great success to generate long and accurate timers on PICS without interrupts. It can also be used to get very high resolution (as fine as 0.2 microsecond with a 20mhz pic) measurement of external events on PICS that do have interrupts, while still maintaining long counts.

Scott Dattalo says:

A slightly easier to read (IMO) and slightly faster, yet still isochronous is:
 movfw RTCC
 addwf RTIMEL,F
 rlf known_zero,W
 addwf RTIMEM,F
 rlf known_zero,W
 addwf RTIMEH,F
 ;followed by the RTCC fix-up code

where known_zero is a variable that has been initialized to zero.

A slighty more obscure version that doesn't require the known_zero:

 incf RTIMEH,F
 movfw RTCC
 addwf RTIMEL,F
 skpnc
 incfsz RTIMEM,F
 decf RTIMEH,F

I'm not sure if this one is more obscure or not:

 movfw RTCC
 addwf RTIMEL,F
 skpnc
 incf RTIMEM,F
 skpz
 incf RTIMEH,F

On the 18cxxx you could do this:

 movf RTCC,w ;or whatever the tmr register is called...
 addwf RTIMEL,F
 clrf wreg
 addwfc RTIMEM,F
 addwfc RTIMEH,F

But on the 18cxxx parts, tmr0 can be 16bits wide. So there maybe other tricks to try there...

See:

Comments:

See also:


file: /Techref/microchip/timenint.htm, 10KB, , updated: 2010年10月2日 13:23, local time: 2025年9月26日 05:11,
40.74.122.252:LOG IN

©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://techref.massmind.org/Techref/microchip/timenint.htm"> PIC long term timers without interrupts</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here:
if you want a response, please enter your email address:
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?

Welcome to massmind.org!

Welcome to techref.massmind.org!

.

AltStyle によって変換されたページ (->オリジナル) /