PDA

View Full Version : Timer overflows and interrupts



barkerben
- 1st December 2004, 22:51
Hi,

I'm planning on using the hardware timer to genrate a clock, freeing up the chip to do other things.

I had been planning that whenever the timer overflowed (on a 16F768), a service routine would be called that would incremement a counter. This counter would be constantly polled in the main program, and when it reached some value, anther counter could be incremented, and the first reset (because I can only count up to 256 in one variable), and so on ...

I'm planning t generate a clock at betweeen 1Hz-->10Hz.
Does this sound reasonable?

I've come across Prescalers in some literture as well, but it is all a bit confusing - how are they used, and how can I calculate interrupt period ...?

Ingvar
- 2nd December 2004, 09:53
Hi Ben,

>>first reset (because I can only count up to 256 in one variable), and so on ...<<

Last time i checked a WORD sized variable could count up to 65535. Apart from that you're on the right track.

>>I'm planning t generate a clock at betweeen 1Hz-->10Hz.
Does this sound reasonable?<<

It sure does, 1 to 10 Hz should be no problem. Just make sure your mainprogram loops fast enough.

>>I've come across Prescalers in some literture as well, but it is all a bit confusing<<

A prescaler slows down the clocksignal to the timer. If you set the prescaler to 1:2 your timer will count at half the speed. With 1:8 it will ofcourse be 8 times slower. With no prescaler th timer will increment once evrey 1/4 of your oscillatorspeed.

I thought i'd give you some advice but i can't find a pic called 16F768. Not a big problem since the timers are very similar throughout the entire 16(and 12) series. I'll also assume that you're running it at 4MHz. Your "instructionclock" will be 4MHz/4=1MHz, this is your timebase.

Using Timer1 to get 10Hz.
Set the prescaler to 1:2 and let the timer count 50000 steps. Since the timer only count upwards you'll need to "preset" it to 65536-50000=15536. Or you could set the prescaler to 1:4 and count 25000, or prescale to 1:8 and count 12500.

Using Timer1 to get 4Hz.
Prescale to 1:4 and count 62500 steps or prescale to 1:8 and count 31250 steps.

Using Timer1 to get 2Hz.
Prescale to 1:8 and count 62500 steps.

We have now almost reached the limit of timer1. To get it even slower you'll need to use a software counter(postscaler) just like you described earlier. The actual limit of the hardwarecounter is OSC/4/8/65536, with 4MHz that equals 1.90735Hz.

You could also use Timer2 but this timer can't go lower than OSC/4/16/256/16, with 4MHz that's 15,259Hz. You quickly realize that you must use a software postscaler to get down to your 10Hz.

Timer0 can be used but i don't recomment it. It shares it's prescaler with the WDT. You could "steal" it from the WDT but then the WDT must be disabled. If you do that the pic won't be able to recover(reset) if your program hangs.

/Ingvar

barkerben
- 2nd December 2004, 23:53
Thanks for that - that's really helpful. My inability to remember a PIC number is why you couldn't find it - In fact I have a PIC 16F876

The same numbers, but in a completely different order. Oh well...!

The idea is that the counter is incremented in the service routing, and the value of the counter is polled in the loop. The whole thing is basically a variable oscillator controlled via the serial line (again using interrupts), so all the main loop needs to do is loop and constantly check if anything needs changing by comparing variables. Hopefully this will mean very low latency.

Thanks again,


Ben

barkerben
- 2nd December 2004, 23:57
Ah - just read your reply in more detail. I think I will probably go for setting the timer to a constant rate of, say, 10Hz, then
changing my effective frequency by only responding every n interrupts, where n is a value received over the serial link.

This will make it easier to change the frequency than having to recalibrate the hardware timer each time. As long as the hardware timer is >= my max desired frequency, then by setting different values for n I should be able to get any frequency below.

Thanks,


Ben

barkerben
- 3rd December 2004, 00:03
I really should get all of my replys into one post ...

Presumably to set hardware properties in the PIC via PICBasic, I just refer directly to the neccesart control registers - for instance, to set up a 1:2 prescaler on timer1 I would use the basic command:

T1CON.4=1
T1CON.5=0

And similarly for setting up interrupt registers, or in fact any control registers within the PIC...


Cheers (for the last time!)

Ben

barkerben
- 3rd December 2004, 17:03
Oops - I'm talking rubbish. I need to get a 1Hz base clock, and then count n times to get n*1Hz clock....

Doh!


Ben

Ingvar
- 3rd December 2004, 19:36
If you have a freq of 10 Hz you can divide that by using a softwarecounter(postscaler). You'll end up with 10 divided by your postscalervalue. The postscaler can only be integers. Soooo.........

10Hz / 1 = 10Hz
10Hz / 2 = 5Hz
10Hz / 3 = 3.333Hz
10Hz / 4 = 2.5Hz
10Hz / 5 = 2Hz
10Hz / 6 = 1.667Hz
and so on .......

A better way would be to use a fixed postscaler. Then change the timer reloadvalue and prescaler to get twice the frequency you want. This way you can produce very accurate frequencies in the region you want. If you use a fixed prescaler of 1:8 and a fixed postscaler of 1:2 and only change the reloadvalue you can produce ......

65536 - 6250 = 59286 ---> 10Hz
65536 - 6251 = 59285 ---> 9.9984Hz
65536 - 6252 = 59284 ---> 9.9968Hz
......
65536 - 6944 = 58592 ---> 9.0006Hz
65536 - 6945 = 58591 ---> 8.9993Hz
......
65536 - 7812 = 57724 ---> 8.0005Hz
65536 - 7813 = 57723 ---> 7.9995Hz
......
65536 - 12500 = 53036---> 5Hz
65536 - 12501 = 53035---> 4.9996Hz
......
65536 - 20833 = 44703 ---> 3.0000Hz
65536 - 20834 = 44702 ---> 2.9999Hz
......
65536 - 31250 = 34286 ---> 2Hz
65536 - 31251 = 34285 ---> 1.9999Hz
......
65536 - 62499 = 3037 ---> 1.000016Hz
65536 - 62500 = 3036 ---> 1Hz

It's fairly easy to let PBP calculate the reloadvalue for you. You could specify your frequency in mHz(milliHertz). 10 Hz would be 10000, 1 Hz would be 1000. Run it through this code to produce your timer1reloadvalue. All variables are WORD sized.

Dummy = 62500
Dummy = Dummy * 1000
TMR1Reload = DIV32 DesiredFreq
TMR1Reload = 0 - TMR1Reload

The 62500 comes from OSC/4/Prescaler/Postscaler. 4000000/4/8/2=62500. 1000 is there to make it possible to specify mHz.

There are ways to expand all of this to include variable prescalersettings to get better accuracy at higher frequencies, but that's a story for another day......

/Ingvar

barkerben
- 4th December 2004, 12:25
Thanks - I realise my 1Hz base clock was rubbish - of course I need to start at the maximum freq. and work down.

One final questio about the prescaler idea you posted:

TMR1Reload does not appear in the manual that I can see - is it a PBP command...?


Cheers,


Ben

barkerben
- 5th December 2004, 05:49
Ah - it looks like maybe I can just use:

TMR1=TMR1Reload to preset the timer. Is this correct?


Ben

Ingvar
- 6th December 2004, 19:44
Almost, you'll need to write it in two steps.

TMR1L = TMR1Reload.lowbyte
TMR1H = TMR1Reload.highbyte

I guess that you've already realized that "TMR1Reload" is a plain word sized variable, nothing else.

I also must tell you that if you need extreme accuracy you'll need an assembler interrupt. You will have some latency if you're planning on using "ON INTERRUPT". You may overcome that by adding the "TMR1Reload" to the TMR1. You'll also have to add the time it takes to do that addition, no big deal since that time will be constant. It might be better to add that when calculating the TMR1 reloadvalue, it would save you one addition in the interruptroutine. A portion of the interrupt would(could) look like .....

T1CON.0 = 0 'Stop timer1 while we're messing with it
Dummy.lowbyte = TMR1L
Dummy.highbyte = TMR1H
Dummy = Dummy + TMR1Reload ' + additionlatency if not added before
TMR1L = Dummy.lowbyte
TMR1H = Dummy.highbyte
T1CON.0 = 1 'Start timer1 again

/Ingvar

barkerben
- 18th December 2004, 02:42
Hi - thanks. Yes I realised that if I'm resetting the timer each tine it interrupts, then thyere will be some innacuracy as the service rouyting takes finite time. However, accuracy is not that important - consistency is more important - so hopefully this wil be fine.

I'm away fromn the lab at the mo, but will hope to get this implemented by the start of Jan, and ill let you know hoe it goes.

Just hoping PICBasic is up to the job - probably should have used Assembler or C, but the latter is unavailable, and the former is scary!


Cheers,


Ben