CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

Timers - what you should know
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
newguy



Joined: 24 Jun 2004
Posts: 1439
Location: Edmonton, Alberta

View user's profile Send private message

Timers - what you should know
PostPosted: Wed Apr 06, 2005 9:25 am     Reply with quote

Reposted from the other forum.... I figured it would be useful to have it here too.

Hopefully this helps to clear up some of the confusion regarding timers. I will use an example that is driven by the internal (system) clock.

Whatever the master crystal frequency is, the internal (system) clock is always the crystal frequency divided by 4.

Example:

Crystal: 4 MHz
System clock: 1 MHz (1 microsecond period)

The system clock is what drives the timer modules (if set up to use the internal clock.) However, there is a prescaler which can also be set. A prescaler is a programmable "divide by N" block where N is the number of input clock cycles it takes to get one output cycle out of the prescaler.

Example:

Let's assume that you want to use timer 0. Timer 0's prescaler can be set to 1 (no divide at all), 2, 4, 8, ....., all the way up to 256. If it was set to 256, then it would take 256 system clock cycles to get one cycle out of the prescaler. Therefore timer 0 would then count up at a rate of one count every 1 microsecond (system clock) x 256 (prescaler setting) = 256 microseconds/count.

Note that some timers can also have postscalers.

A timer will generate an interrupt every time it overflows, and if its' interrupt is enabled. Timer 0 can be set to either 8 bit mode or 16. In 8 bit mode, it overflows every 256 counts. It would take 65,536 counts in 16 bit mode.

To completely set up timer 0 in 8 bit mode with the system clock as its source and with a prescaler of 256, you would code:

Code:
Code:
setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);


The constants used in this function, and the functions for the other timers are found in the device's header file. For instance, 18F452.h. Look for it in the PICC\devices directory.

Extending our example:

In 8 bit mode, timer 0 would overflow (interrupt) every 256 microseconds/count x 256 counts/overflow = 65,536 microseconds = 65.536 milliseconds.
In 16 bit mode, timer 0 would overflow (interrupt) every 256 microseconds/count x 65,536 counts/overflow = 16,777,216 microseconds = 16.777216 seconds.

So, with all this in mind, it's up to you to choose
a) the clock source,
b) whether you need an 8 or 16 bit counter, and
c) the prescaler value.

So, as a starting point, if I had to create a 1 ms "tick" and my crystal frequency was 4 MHz, I would do it this way (again as a starting point; greater accuracy may require different values).

Timer 0: 8 bit mode, driven by the internal clock. Now the (harder) part: choosing the prescale value.

If the prescaler was set to 1, I'd get an interrupt every 256 us. This is probably too fast - I wouldn't want to tie up the processor with all of the interrupt services this would take - about 4 per millisecond.

If the prescaler was set to 2, there would be an interrupt every 512 us. Again, probably too fast.

If the prescaler was set to 4, there would be an interrupt every 1,024 us = 1.024 ms. Bingo. If timing isn't absolutely critical, I'd just let timer 0 free run. If timing is critical, then you'll need to tweak this just a bit.

With the prescaler set to 4, timer 0 counts up once every 4 us. So how many 4 us clicks are in 1 ms? 0.001s/0.000004s = 250. This is the number of counts of timer 0 in 1 ms (note that 250 is 6 less than 256 - this will be important later). Aha. Now we have everything we need.

Timer 0's ISR:

Code:
Code:
#byte timer0low = 0xfd6

#int_RTCC
void RTCC_isr(void) {
   timer0low = timer0low + 6;
   one_millisecond = TRUE;
}


All you look for in the main routine is for one_millisecond to be set. There's your 1ms tick.

The reason why I directly add 6 to whatever timer 0's count is at is because 6 is the number of ticks I need to skip in order for timer 0 to count 250 times before it rolls over. If used:

Code:
Code:
set_timer0(6);



instead, the accuracy of the 1 ms tick would be very poor. That is because it takes quite a long time for the processor to stop what it is doing and service the interrupt. With a 4 MHz clock, this may be 60 - 80 us or more. By the time that the processor gets around to servicing the interrupt, timer 0 will have counted up to 15 - 20 already; by setting it back to 6, what we think is our 1 ms tick will be way too slow.

And the location of timer 0's register is found in the PIC's data sheet. Look in the memory organization section for the special function registers. You'll find all of their memory addresses there.

Lastly, EXPERIMENT FOR GOD'S SAKE!!!! It is so annoying seeing weekly pleas for help to get a certain clock tick. EXPERIMENT!!!! How do you think that the experienced people here got that way? Hook up an led and flash the stupid thing at an easily measurable/discernable rate so you can confirm your calculations. Setting up a timer isn't rocket science.

Edit: Bernd (bb) has helpfully provided the following information.

Quote:

Mid-Range MCU Family Reference Manual:
Quote:

Any write to the TMR0 register will cause a 2 instruction cycle (2TCY) inhibit. That is, after the
TMR0 register has been written with the new value, TMR0 will not be incremented until the third
instruction cycle later (Figure 11-2). When the prescaler is assigned to the Timer0 module, any
write to the TMR0 register will immediately update the TMR0 register and clear the prescaler. The
incrementing of Timer0 (TMR0 and Prescaler) will also be inhibited 2 instruction cycles (TCY). So
if the prescaler is configured as 2, then after a write to the TMR0 register TMR0 will not increment
for 4 Timer0 clocks.


PIC18 Reference manual:
Quote:

Writes to TMR0H do not clear the Timer0 prescaler in 16-bit mode, because a write to TMR0H
only modifies the Timer0 latch and does not change the contents of Timer0. The prescaler is only
cleared on writes to TMR0L.

Any write to the TMR0 register will cause a 2 instruction cycle (2TCY) inhibit. That is, after the
TMR0 register has been written with the new value, TMR0 will not be incremented until the third
instruction cycle later (Figure 13-6). When the prescaler is assigned to the Timer0 module, any
write to the TMR0 register will immediately update the TMR0 register and clear the prescaler.
The incrementing of Timer0 (TMR0 and Prescaler) will also be inhibited 2 instruction cycles
(TCY). So if the prescaler is configured as 2, then after a write to the TMR0 register, TMR0 will
not increment for 4 Timer0 clocks (Figure 13-7). After that, TMR0 will increment every prescaler
number of clocks later.


Best regards,
Bernd
nucloid



Joined: 30 Apr 2005
Posts: 1

View user's profile Send private message

PostPosted: Sat Apr 30, 2005 10:40 am     Reply with quote

Thank you for the informative post -- a very nice tutorial for us newbies.

I very much appreciate it.


cheers


(now I am looking for "interrupts and interrupt driven routines for the first timer") Smile
asmboy



Joined: 20 Nov 2007
Posts: 2116
Location: albany ny

View user's profile Send private message AIM Address

one other helpful timer thing
PostPosted: Tue Nov 20, 2007 4:56 pm     Reply with quote

before starting to code with CCS -c i did a lot in pure ASM - one aspect of dealing with timers in a NON interrupt fashion is to set a prescaler value early in the program for a 16 bit timer to get a useful 'tick' increment - then set the timer count to a value that will give your timeout on overflow and then poll said timer's overflow bit to see if the time limit has been exceded - since READING the bit is the only reset - no matter how many times the timer may have rolled over beyond the MINIMUM timeout you set - you still know - that by - checking for a '1' in the overflow bit tells you are sure your time is Up. for timer1 it is the TMR1IF bit in the PIR1 register- for example on the 16f887 - all the other major timers have the same kind of flag- BEWARE that some VERY low end pics DO NOT - but talking really low end like 16c5xx and so on. hope you can use this tidbit
smiles



Joined: 20 Feb 2008
Posts: 33

View user's profile Send private message

Re: Timers - what you should know
PostPosted: Tue Feb 26, 2008 8:12 am     Reply with quote

newguy wrote:


Code:
Code:

#byte timer0low = 0xfd6

#int_RTCC
void RTCC_isr(void) {
   timer0low = timer0low + 6;
   one_millisecond = TRUE;
}


All you look for in the main routine is for one_millisecond to be set.


I read the post till this code and I don't understand, could you explain me more about this code
for e.g your main() is

Code:
void main()   {
   int i;
   setup_timer_0(RTCC_INTERNAL|RTTC_8_BIT|RTCC_DIV_4);
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);
   ...
   i=0;
   while(TRUE);                              // loop forever
}

As far as I know, the interrupt happens after 1024us (crystal 4MHz, PIC16f877) then it will jump to your RTTC_isr(), so I don't understand the line timer0low = timer0low + 6;
Could anyone tell me where I am wrong ?
Thanks !
newguy



Joined: 24 Jun 2004
Posts: 1439
Location: Edmonton, Alberta

View user's profile Send private message

PostPosted: Tue Feb 26, 2008 9:43 am     Reply with quote

It's all in the original post, but I'll restate it slightly differently.

A timer never stops unless your program stops it. It's always ticking away, regardless of what your code is having the processor do.

An interrupt is just that - it causes the processor to "interrupt" whatever it is doing at the moment the interrupt occurs. Sort of like your doorbell. When your doorbell rings, are you able to instantaneously answer the door? No. You may be sitting down reading a book or standing in the [spam] cooking. Whatever you're doing, you must first set whatever you're doing aside in a 'safe' manner so that you can return to that task at some point in the future and pick up where you left off. If you're reading a book, you'll use a bookmark to save your place, and if you're cooking, you may turn down the stove so that whatever you're cooking won't burn.

So, with this in mind, let's mentally tackle a timer interrupt. A timer interrupt 'fires', and the processor begins the rather long task of setting everything aside so that it can attend to the interrupt. While it is doing this - saving work (data/registers), then determining which interrupt(s) require attention, and finally jumping into the ISR which needs to be performed - the timer is still ticking away.

Exactly what the 'count' of the timer actually is when your interrupt gets around to servicing it is unknown. There is no way of knowing what it will be if you have a program with interrupts other than the timer itself. So, if an accurate timer-derived clock is necessary, you must somehow work around this uncertainty. That's where the 6 in the equation in the original post came about.

In that example, 250 'ticks' = 1ms. However, that timer only fires when it rolls over from 255 to 0 (which is 256 'ticks'). To get the timer to skip 6 'ticks', your ISR must read the current value of the timer's count, add 6 to it, and then replace this higher value in the timer's count register.

Clear?
smiles



Joined: 20 Feb 2008
Posts: 33

View user's profile Send private message

PostPosted: Wed Feb 27, 2008 1:54 am     Reply with quote

Yes, I understand why we must skip 6
So
void main() {
int i;
setup_timer_0(RTCC_INTERNAL|RTTC_8_BIT|RTCC_DIV_4);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
...
i=0;
...
while(TRUE); // loop forever
}
When it receives command enable_interrupts(GLOBAL), it must finish declaring i=0, then go to RTCC_isr(), add the value of timer resistor to 6, then the timer starts and it back to void main() ?
is that right ?
if right, then when the timer value transit between 255 and 0, one_millisecond will be TRUE ?
it also mean
void RTCC_isr(void) {
timer0low = timer0low + 6; // the timer active here
one_millisecond = TRUE; //ignore this command and turn back to main program until timer value transit between 255 and 0 ?
}
Hope you answer me, thanks so much !
newguy



Joined: 24 Jun 2004
Posts: 1439
Location: Edmonton, Alberta

View user's profile Send private message

PostPosted: Wed Feb 27, 2008 8:53 am     Reply with quote

smiles wrote:
Yes, I understand why we must skip 6
So
Code:
void main()   {
   int i;
   setup_timer_0(RTCC_INTERNAL|RTTC_8_BIT|RTCC_DIV_4);
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);
   ...
   i=0;
   ...
   while(TRUE);                              // loop forever
}

When it receives command enable_interrupts(GLOBAL), it must finish declaring i=0, then go to RTCC_isr(), add the value of timer resistor to 6, then the timer starts and it back to void main() ?
is that right ?


The code sets up timer 0, enables timer 0's interrupt, then enables interrupts globally. Then i is initialized to 0. THEN the main loop will be entered. It takes 1 ms for timer 0's interrupt to fire, and the various setup code will take far less time to perform. Less than 1 ms for sure. The processor will be in the main loop when the interrupt occurs the first time. However, it doesn't matter when an interrupt occurs - the processor will drop what it is currently doing, service the interrupt, and resume right where it left off.

Quote:
if right, then when the timer value transit between 255 and 0, one_millisecond will be TRUE ?


Yes.

Quote:
it also mean
Code:
void RTCC_isr(void) {
   timer0low = timer0low + 6; // the timer active here [b][u]correction the timer WAS active before this - when the setup_timer_0() line was executed[/u][/b]
   one_millisecond = TRUE;  //ignore this command and turn back to main program until timer value transit between 255 and 0 ?  [b][u]Yes[/u][/b]
}

Hope you answer me, thanks so much !
smiles



Joined: 20 Feb 2008
Posts: 33

View user's profile Send private message

PostPosted: Wed Feb 27, 2008 9:57 am     Reply with quote

Thanks so much Smile
hayee



Joined: 05 Sep 2007
Posts: 252

View user's profile Send private message

PostPosted: Wed May 28, 2008 2:03 am     Reply with quote

Thanks everyone for this timer0 tutorial. I have learnt lot of things from that. I have a simple question regarding this. Maybe this is a stupid question. I want to know that what this line means or what is the function of this line?
Code:
#byte timer0low = 0xfd6

Thanks in advance.
U guys are really doing well.
Best Wishes
newguy



Joined: 24 Jun 2004
Posts: 1439
Location: Edmonton, Alberta

View user's profile Send private message

PostPosted: Wed May 28, 2008 8:00 am     Reply with quote

That address, 0xfd6, is the address of the low byte of timer 0 in that PIC's memory. You can find this information in the PIC's data sheet in the memory organization - special function registers - section and in the timer 0 section itself. That line of code assigns a variable, timer0low, to fall at that address. So a read/write of that variable directly reads/writes the low byte of timer 0 itself.
vinceykw



Joined: 16 Dec 2008
Posts: 3

View user's profile Send private message

PostPosted: Thu Dec 18, 2008 2:48 am     Reply with quote

may i know where is the 4us come from...
Quote:

With the prescaler set to 4, timer 0 counts up once every 4 us. So how many 4 us clicks are in 1 ms? 0.001s/0.000004s = 250. This is the number of counts of timer 0 in 1 ms (note that 250 is 6 less than 256 - this will be important later). Aha. Now we have everything we need
PCM programmer



Joined: 06 Sep 2003
Posts: 20096

View user's profile Send private message

PostPosted: Fri Dec 19, 2008 9:01 pm     Reply with quote

Read the first part of his explanation:
Quote:
Whatever the master crystal frequency is, the internal (system) clock is always the crystal frequency divided by 4.

Example:

Crystal: 4 MHz
System clock: 1 MHz (1 microsecond period)

If you use a pre-scaler of 4, the 1 MHz clock used by the Timer is divided
by 4. In the same way, the 1 usec period divided by 4 becomes 4 usec.
asmallri



Joined: 12 Aug 2004
Posts: 1536
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sat Dec 20, 2008 1:55 pm     Reply with quote

Quote:
Whatever the master crystal frequency is, the internal (system) clock is always the crystal frequency divided by 4.


This post was written back in 2005. The above statement is no longer true for the 16 or 32 bit controllers.
_________________
Regards, Andrew

http://www.brushelectronics.com/index.php?page=software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
harshanahnd



Joined: 22 Nov 2008
Posts: 11

View user's profile Send private message

PostPosted: Sat Jan 03, 2009 8:43 am     Reply with quote

Hi,

How to setup timer0 in 16 bit mode? What is the keyword that we should use in setup_timer_0 function?

Thanks
rhaguiuda



Joined: 05 Sep 2007
Posts: 46
Location: Londrina - Brazil

View user's profile Send private message

PostPosted: Tue Jan 13, 2009 1:59 pm     Reply with quote

Quote:

How to setup timer0 in 16 bit mode? What is the keyword that we should use in setup_timer_0 function?



That's simple. You just have to use:


Code:
setup_timer_0(RTCC_INTERNAL|RTCC_16_BIT|RTCC_DIV_256)

_________________
Give a man a fish and you'll feed him for a day. Teach a man to fish, and you'll feed him for a lifetime.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group