View previous topic :: View next topic |
Author |
Message |
chrismdube
Joined: 30 Dec 2011 Posts: 20 Location: UK
|
Timers |
Posted: Tue Jan 24, 2012 2:28 pm |
|
|
Hello once again. I wonder, am I able to use different timers for different tasks in a project or am I restricted to one? If yes, do I declare the other timer(s) at start of code or within the concerned blocks? Within these blocks do I specify which timer to use such as
delay_timer_0( 100)?
My code executes PWM and other functions which need different time delays. I'm looking at the many forum posts but I don't seem to find a pointer. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Multiple timers |
Posted: Tue Jan 24, 2012 4:22 pm |
|
|
I'm not too sure exactly what it is you're after. The simple answer is yes, you can use different timers for separate tasks. Unless you clock a timer from an external source all the internal timers in a PIC run at essentially the same rate since they're clocked by the same crystal. The pre and post scalers will give you a wide range of time intervals.
You can get loads of different timers to work from one source.
Here's one way of doing it for ms delays :-
I avoid using constructs of the delay_ms() variety. I use one of the PIC timers to generate an interrupt at 1ms intervals (i.e. a 1ms tick). I have as many task timers as needed, task_1_timer, task_2_timer......... In the ISR, all the timers are decremented and either set a flag or are clamped when they reach zero. When a delay is needed, main() sets task_n_timer to the required delay, it is then polled, along with the others, until main() detects that the required time has passed, job done. In this way each timer is independent of the others except that they all clock at the same time.
Mike |
|
|
chrismdube
Joined: 30 Dec 2011 Posts: 20 Location: UK
|
timers |
Posted: Tue Jan 24, 2012 5:57 pm |
|
|
Thanks for your reply Mike. I can't say I understood though. If you don't mind can I have a sample code please. These ISRs make my heard spin. I have a book here but it doesn't help much.
I am trying to separate my sequences from the PWM timer, that's why I need at least another independent timer. Even a reference to read would be much appreciated. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Tue Jan 24, 2012 6:18 pm |
|
|
My apologies to whomever I stole this from, but this is a good example of how to run many software timers in a program:
Your approach will work, but I would make it into a more general solution because you are likely to have a wish for more timers. What I often do is to create a timer interrupt that is always running and triggered every 100ms, then inside this interrupt I create as many 'Software Timers' as I want. These timers work by the main routine setting a value, and then in the interrupt the value is decremented every 100ms until it reaches zero where it stops. In main I will test for the timer to have reached zero and then perform the timer based action and/or set a new value.
Example:
Code: |
//-------------------------------------------------------------
// Timer0 interrupt, triggers every 100 miliseconds.
// Used for multiple software based timers.
//-------------------------------------------------------------
#int_timer0
void timer0_isr()
{
// Many software count down timers...
if (GprsStateTimer) GprsStateTimer--;
if (LocalTimer) LocalTimer--; // General purpose timer for temporary local use
if (SignOfLiveTimer) SignOfLiveTimer--;
if (GprsTxDelayTimer) GprsTxDelayTimer--;
if (LedOnTimer)
{
LedOnTimer--; // Count down till 0
if (!LedOnTimer) // Switch LED off on time out.
output_low(LED);
}
|
Now, if in the Main routine I need to do some processing where a maximum timeout is defined I can do it like this:
Code: |
#define TIMER_EXPIRED 0 // Value of the software timers when expired.
// Initialize MMC memory card
LocalTimer = 5; // According to the MMC specs a max. of 500ms.
do
{
Result = MMC_SendCmd(SEND_OP_COND);
}
while ((Result != R1_OK) && (LocalTimer != TIMER_EXPIRED));
|
The LED timer was a piece of code where I needed a LED to be on for a defined moment of time. So in the main routine I would set:
Code: |
output_high(LED);
LedOnTimer = ONE_SECOND; // Switch LED off after 1000ms
|
And then the main program would continue with the interrupt routine taking care of the LED to switch of after 1 second.
The main difference with your approach is that I never enable/disable the timer interrupt allowing for many software timers into this single hardware timer. You only have to disable/enable the timer interrupt when the counter variable is larger than an int8, then the action of setting the value will no longer be an atomic operation (a single assembly instruction). _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
chrismdube
Joined: 30 Dec 2011 Posts: 20 Location: UK
|
timers |
Posted: Tue Jan 24, 2012 6:49 pm |
|
|
Wow! This is too much to take on first feet. Thanks again guys but isn't there a way I could use the hardware timers without getting too deep. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Multiple timers |
Posted: Wed Jan 25, 2012 7:45 am |
|
|
You asked.
Quote: |
I wonder, am I able to use different timers for different tasks in a project or am I restricted to one?
|
What kind of delay software do you have in mind?
In the CCS examples you will find software of the delay_ms() variety. The big problem is that you can only run one of these delays at a time since each of them grabs all the processor time. What SherpaDoug and I are offering is a means to use either one (or more) of the hardware timers to achieve multiple effectively simultaneous timers. If you use different hardware timers for each function you will very rapidly run out of resources.
To SherpaDoug
I do not disable my timer, it simply runs continuously. The main difference between my approach and yours is that I have more of the action in main(). You start your timer in main() and end it in the ISR. I have start and stop actions in main(). Our systems are very similar.
For chrismdube's benefit, here's a short complete compilable for a PIC16F877A. The program flashes LEDs on RB0 & RB1 at slightly different rates around 2Hz. The LEDs start in step then flash in and out of step with each other every 13s.
Code: |
#include <18F458.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)
signed int16 rb0_led_timer; //
signed int16 rb1_led_timer;
void main()
{
setup_timer_2(T2_DIV_BY_4, 249, 1); // Generates 1ms tick
enable_interrupts(int_timer2);
enable_interrupts(global);
rb0_led_timer = rb1_led_timer = 0; // clears timers
output_high(pin_b0); // forces defined state
output_high(pin_b1); // "
while( TRUE )
{
if (rb0_led_timer<=0) // Tests for time out
{ rb0_led_timer = 250; // Restarts timer
if (input(pin_b0)) // Test b0
{ output_low(pin_b0); } // Clears if set
else
{ output_high(pin_b0);} // Sets if clear
}
if (rb1_led_timer<=0) // Tests for time out
{ rb1_led_timer = 260; // Restarts timer
if (input(pin_b1)) // Tests state of b1
{ output_low(pin_b1); } // Clears if set
else
{ output_high(pin_b1);} // Sets if clear
}
}
}
#int_timer2
void update_timers()
{
rb0_led_timer--;
rb1_led_timer--;
}
|
If you make the timer intervals quite short (say 2ms & 3ms respectively) you can watch the action on your oscilloscope. The whole thing then repeats every 12ms.
Mike
Last edited by Mike Walne on Sat Jan 28, 2012 4:27 am; edited 2 times in total |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Separate hardware timers |
Posted: Wed Jan 25, 2012 4:45 pm |
|
|
Quote: |
Wow! This is too much to take on first feet. Thanks again guys but isn't there a way I could use the hardware timers without getting too deep
|
Yes, you can use something based on either SherpaDoug's or my method. You will gain most by doing most of the work yourself. I think we have given you enough.
Mike |
|
|
|