View Full Version : Using Timers
psquared
09-05-2005, 21:03
I was wondering how i would go about setting up a timer in the program. I would like a way of using a very accurate timer that can be initiated miliseconds apart. I don't want to do a loop timer and guess how long has passed based on how long it takes a loop to pass. I need a really fast and accurate timer that can notify me when a certain number of miliseconds have passed to execute a command. If you have any code suggestions as to how I can get started or any links to resources they would be greatly appreciated. And to clarify I am referring to programming the robot controller using MPLab. Thanks.
Mark McLeod
09-05-2005, 21:32
IFI published a white paper last year on how to implement timers
http://www.ifirobotics.com/docs/timers_white_paper_2004-jan-14.pdf
When the timer rolls over an interrupt is triggered, code execution is interrupted, and you can either perform your action (if it's VERY short), or set a flag your regular code can check whenever it's convenient to execute your special command.
Mark Pettit
10-05-2005, 10:17
Are you limited to programming a timer?
Hardware solutions such as the one found HERE (http://electronickits.com/kit/complete/elec/ck1614.htm) might be an option.
Sorry if I'm way off base.
CyberWolf_22
10-05-2005, 18:38
Kevin Watson also has very good examples of setting up timers using the robot controller. These can be found at kevin.org/frc I have used his examples and have had success using timers for the past two years. They are very well commented and very helpful.
tribotec_ca88
26-01-2006, 10:11
I'm not too familiar with working with interrupt-driven timers so here's a question for those of you more experienced programmers... I'm simply detailing the steps i took to set up a timer, so someone please correct me if i took a wrong turn.
OK I was thinking about using an interrupt-driven timer (Timer1 - as indicated in the PIC datasheet - to be more specific) used to keep track of time intervals during the Autonomous period.
The first thing I did was initialize it under User_Initialization (user_routines.c) with the following configurations:
T1CONbits.T1CKPS0 = 1; // 1:8 Prescale (clock=1.25MHz/each tick=800ns)
T1CONbits.T1CKPS1 = 1;
T1CONbits.TMR1CS = 0; // = 0 Timer uses internal clock
TMR1H = 0x85; // Sets most significant byte
TMRIL = 0xED; // Sets least significant byte
T1CONbits.TMR1ON = 1; // Turns on Timer1
IPR1bits.TMR1IP = 0; // Sets Timer1 as low priority
PIE1bits.TMR1IE = 1; // Enables Timer1 overflow interrupt
INTCONbits.GIEL = 1; // Enables low priority interruptions
Inside the InterruptHandlerLow () function i've got the following IF loop set up:
if (PIR1bits.TMR1IF) // In other words, has Timer1 overflowed?
{
PIR1bits.TMRI1F = 0; // Resets Timer1
timer1_flag = 1; // Variable used as a flag
}
All righty, the one thing i need to know is where exactly should i call the InterruptHandlerLow () function from? Inside the while (autonomous_mode) loop in user_routines_fast?? That way I was thinking of calling my team's customized autonomous function (known as Autonomous() in this case) from inside the while (autonomous_mode), transferring the value of timer1_flag through parameters, and using that value afterwards inside my Autonomous() function...
Example:
while (autonomous_mode) /* DO NOT CHANGE! */
{
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata);
Autonomous((int)timer1_flag);
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
Putdata(&txdata);
}
}
OK would this by any chance work at all, or have i totally lost it :eek: lol ? Any help at all would be greatly appreciated!!!
Eldarion
26-01-2006, 13:38
I'm not too familiar with working with interrupt-driven timers so here's a question for those of you more experienced programmers... I'm simply detailing the steps i took to set up a timer, so someone please correct me if i took a wrong turn.
OK I was thinking about using an interrupt-driven timer (Timer1 - as indicated in the PIC datasheet - to be more specific) used to keep track of time intervals during the Autonomous period.
The first thing I did was initialize it under User_Initialization (user_routines.c) with the following configurations:
T1CONbits.T1CKPS0 = 1; // 1:8 Prescale (clock=1.25MHz/each tick=800ns)
T1CONbits.T1CKPS1 = 1;
T1CONbits.TMR1CS = 0; // = 0 Timer uses internal clock
TMR1H = 0x85; // Sets most significant byte
TMRIL = 0xED; // Sets least significant byte
T1CONbits.TMR1ON = 1; // Turns on Timer1
IPR1bits.TMR1IP = 0; // Sets Timer1 as low priority
PIE1bits.TMR1IE = 1; // Enables Timer1 overflow interrupt
INTCONbits.GIEL = 1; // Enables low priority interruptions
Inside the InterruptHandlerLow () function i've got the following IF loop set up:
if (PIR1bits.TMR1IF) // In other words, has Timer1 overflowed?
{
PIR1bits.TMRI1F = 0; // Resets Timer1
timer1_flag = 1; // Variable used as a flag
}
All righty, the one thing i need to know is where exactly should i call the InterruptHandlerLow () function from? Inside the while (autonomous_mode) loop in user_routines_fast?? That way I was thinking of calling my team's customized autonomous function (known as Autonomous() in this case) from inside the while (autonomous_mode), transferring the value of timer1_flag through parameters, and using that value afterwards inside my Autonomous() function...
Example:
while (autonomous_mode) /* DO NOT CHANGE! */
{
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata);
Autonomous((int)timer1_flag);
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
Putdata(&txdata);
}
}
OK would this by any chance work at all, or have i totally lost it :eek: lol ? Any help at all would be greatly appreciated!!!
InterruptHandlerLow () is a system function; I.E. when an interrupt is set, this function is immediately called by IFI's interrupt handler. You do not need to call it from anywhere in your code.
Inside the InterruptHandlerLow () function i've got the following IF loop set up:
if (PIR1bits.TMR1IF) // In other words, has Timer1 overflowed?
{
PIR1bits.TMRI1F = 0; // Resets Timer1
timer1_flag = 1; // Variable used as a flag
}
I'd suggest re-reading the PIC18F manual on TMR1 and looking over Kevin's code, you're close. At least from my experience.
In the ISR for the timer you'll need to reset the value in the timer. The timer, once enabled simply counts up to 0xFFFF and upon overflowing back to 0x0000 sets the TMR1F flag indicating overflow. It sets the flag whether interrupts are enabled or not. If interrupts are enabled for this timer, then the ISR is invoked. The timer however continues to get clocked and continues to count (0x0001, 0x0002, ... etc.) until it overflows again and another interrupt will be generated since the timer is still enabled. However in this case the time interval between the 1st interrupt and 2nd is however long it takes to count from 0 to FFFF vs the first time when it counted from 0x85ED to 0xFFFF. If you want a one shot interrupt, then you should disable the timer (T1CONbits.TMR1ON = 0) in the ISR.
If you want a periodic interrupt, then you'll need to reset the value in the timer to count from. For example, something like:
// timer continued to run on after it raised the interrupt
// latency is amount of count, save last latency in drift
timer1_drift.lo = TMR1L; // 16bit mode, read L -> latches H for reading
timer1_drift.hi = TMR1H;
// NOTE:
// Drift can be larger than 256 instructions if, for example,
// the timer interrupt is raised just after we test for it in
// the ISR and then spend a lot of time in the ADC or later
// interrupts - or high priority interrupt occurs - or ...
// So, do int arithmatic to compensate for drift.
timer1_drift.wrd += (0x85ED-13); // reload counter with desired value
// Note:
// Ideally we also add in a handful of cycles it takes to get from reading
// the timer above to resetting it here. Not many cycles but we can
// easily figure them out by looking at assembler and adjusting 0x85ED
// accordingly. I counted 13 cycles to be subtracted last time I checked
TMR1H = timer1_drift.hi;
TMR1L = timer1_drift.lo;
T1CON = 0x85; // reset prescaler, lost at TMR1L write time.
NOTE: The above logic might be wrong, it is mostly a copy of our sysclock routine which has a 1:1 prescaler vs this 1:8 prescaler. Therefore the (-13) cycles is not correct and should be adjusted as required.
Its also best to check that both the interrupt is enabled AND the interrupt flag is set:
if (PIR1bits.TMR1IF && PIE1bits.TMR1IE) ...
Regards,
DCBrown
tribotec_ca88
30-01-2006, 07:09
I've included timers.h in all c files i'm using timers in...and this is what i ended up writing to initialize Timer1:
T1CONbits.T1CKPS0 = 1; // 1:8 Prescale (clock=1.25MHz/each tick=800ns)
T1CONbits.T1CKPS1 = 1;
T1CONbits.TMR1CS = 0; // Internal clock
TMR1H = 0x85; // Timer1's most significant byte
TMRIL = 0xED; // Timer1's least significant byte
T1CONbits.TMR1ON = 1; // Timer1 set as on
IPR1bits.TMR1IP = 0; // Sets interrupt as low priority
PIR1bits.TMR1IF = 0; // Overflow flag
PIE1bits.TMR1IE = 1; // Timer1 interrupt
INTCONbits.GIEL = 1; // Low priority interrupts OK
but for some reason i still get a few errors related to the TMR1H and TMR1L variables stating:
C:\NossoCodigo\Code_26Jan\user_routines.c:168:Erro r [1105] symbol 'TMRIL' has not been defined
C:\NossoCodigo\Code_26Jan\user_routines.c:168:Erro r [1101] lvalue required
I understand they haven't been defined but where exactly would I define them (and as what?!) ?
thanks, any help at all would be greatly appreciated!!
I've included timers.h in all c files i'm using timers in...and this is what i ended up writing to initialize Timer1:
T1CONbits.T1CKPS0 = 1; // 1:8 Prescale (clock=1.25MHz/each tick=800ns)
T1CONbits.T1CKPS1 = 1;
T1CONbits.TMR1CS = 0; // Internal clock
TMR1H = 0x85; // Timer1's most significant byte
TMRIL = 0xED; // Timer1's least significant byte
T1CONbits.TMR1ON = 1; // Timer1 set as on
IPR1bits.TMR1IP = 0; // Sets interrupt as low priority
PIR1bits.TMR1IF = 0; // Overflow flag
PIE1bits.TMR1IE = 1; // Timer1 interrupt
INTCONbits.GIEL = 1; // Low priority interrupts OK
but for some reason i still get a few errors related to the TMR1H and TMR1L variables stating:
C:\NossoCodigo\Code_26Jan\user_routines.c:168:Erro r [1105] symbol 'TMRIL' has not been defined
C:\NossoCodigo\Code_26Jan\user_routines.c:168:Erro r [1101] lvalue required
I understand they haven't been defined but where exactly would I define them (and as what?!) ?
thanks, any help at all would be greatly appreciated!!
it looks like you're using "TMRIL" instead of "TMR1L"?
sorry if I'm mistaken,
tribotec_ca88
30-01-2006, 10:29
it looks like you're using "TMRIL" instead of "TMR1L"?
sorry if I'm mistaken,
lol :D so very true...
thanks for the heads up!
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.