View previous topic :: View next topic |
Author |
Message |
djsb
Joined: 29 Jan 2011 Posts: 41
|
set_timer0 confusion |
Posted: Sat Oct 24, 2015 11:14 am |
|
|
Hi,
I'm just trying to understand how the set_timer0 statement works in the code below
Code: |
//Program to produce a 20 ms pulse state change by interrupt
#include <16F819.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,MCLR,NOBROWNOUT
#use delay(clock=4M) //Set clock speed
#INT_TIMER0 //Timer1 Interrupt Label
void TIMER0_ISR(){ //Interrupt Service Request handling function
output_toggle(PIN_B1); //Toggle Pin B1
set_timer0(100); //Rollover every 20 mS (256-156 = 100)
} //Might have to adjust this value using a scope
//to compensate for command execution time
// 2 added to count (156) (please refer to page 178 (Design Tips)
// of http://ww1.microchip.com/downloads/en/DeviceDoc/33023a.pdf
void main(){
setup_timer_0(T0_INTERNAL|T0_DIV_128); //Setup timer 0 with a 1/128 pre-scaler
enable_interrupts(INT_TIMER0); //Enable Timer interrupt
enable_interrupts(GLOBAL); //Enable selected interrupts
while(1){ //Loop forever
//and do nothing
} //processor is free...
}
// Results with above settings are
// Period: 40.046mS
// Pulse width; 20.023mS
// Freq: 24.971 Hz
|
As mentioned in the comment above I get a square wave output with a frequency of 24.97 Hz.
This is how I worked out
Timer rollover with 256 loaded = 32.768 mS
Each timer tick = 128uS
The required timing period is 20mS
So,
20E-3/128E-6 =156.25 (nearest integer value 156)
So I have worked on the assumption that the value of 156 is subtracted from 256 to give a value of 100. This value of 100 is pre-loaded into the TMR0 register using SET_TIMER0(100);
156 X 128E-6 = 0.019968 so that seems to make sense.
The results on my Oscilloscope verify this. However I do not understand one very simple thing. Why is it that I have to subtract the value I have worked out (156) from 256 to get the 100 that I must put into the above SET_TIMER0() statement. This seems counter intuitive. I do not understand how the figure of 100 relates to the actual timer count.
Could someone please explain this to me? Thanks.
PS Also what is the best and most accurate way of measuring any latency so that I can fine tune the code? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Oct 24, 2015 11:17 am |
|
|
why ?
because the timer counts UP to the overflow point and rollover.
it does NOT subtract from the value you calc'd as the 'register count.
latency from WHAT execution point??
You can easily toggle a pin inside the INT and see how much jitter you get when triggering on Fosc, using delayed sweep to hit the edge of the square wave produced against the master ( Fosc) clock reference ...
only if
Quote: |
using an external clock.. like crystal or oscillator unit
|
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat Oct 24, 2015 2:06 pm |
|
|
A short note on the 'latency'.
Whenever the interrupt is triggered it takes some time before your interrupt routine is entered. Most of this time is used by code inserted by the CCS compiler for saving many PIC registers and for determining which interrupt was triggered. The number of registers to be saved, and restored on interrupt exit, depends on the actual chip model you are using. I don't know for the v5 compiler, but in the past it used to be something like 40 instructions for the PIC16 and close to 100 for the PIC18.
This latency varies with compiler version and the actual chip you are using.
When you have multiple interrupts active it becomes a bit more complicated. When another interrupt is active when your timer interrupt triggers, the timer interrupt will have to wait for the first interrupt to finish. There is no way you can determine this delay beforehand.
The best, and actually easiest way to handle this is not doing any calculations yourself but have the PIC sort it out for you: Code: | #define MS20 (256-156) // Rollover every 20 mS: 20ms/128us per tick = 156
#define LED PIN_B1
// Timer0 Interrupt Service Request handling function
// Is triggered every 20ms.
#INT_TIMER0
void TIMER0_ISR() {
set_timer0(MS20 - get_timer0()); //Rollover every 20 mS
output_toggle(LED);
} | Reading the timer value to adjust your offset value will correct for any latency value, even when the latency is variable.
Also note how I removed a lot of your comments and added a few defines, now the code is 'self documenting'. This saves you work and prevents the common error where code doesn't match the comments. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Sat Oct 24, 2015 3:56 pm |
|
|
an 'also'....
Whenever using the internal clock be aware that the timing may not be precise or accurate when compared to an external crystal and 2 caps.
Each PIC will be slightly different so you might have to adjust the counter to get exactly 20ms( or whatever time you want).
It's a tradeoff, cheaper to use the internal but you need to tweak the software.
Jay |
|
|
|