PIC Timer Interrupts
Here’s a very basic program to use TMR0 and an interrupt for TMR0 to do something every second.
I’m using a 4Mhz clock.
We are setting up the PIC so that everytime TMR0 reaches it’s max value(this is configurable), a Timer Interrupt occurs.
---------------------------------------------------------------------------------------- 'Works w/ 18Fxx2 - James Tu 06/01/2004 'This program sets up a TMR0 interrupt 'The interrupt happens every 1 sec! 'I timed it...it's pretty precise 'It changes the state of an LED every second. led var PORTB.4 ledstate VAR BIT ledstate = 1 INTCON2.7 = 0 'Enable PORTB pullups...18Fxx2 'setup TIMER0 'set the high and low bytes of TMR0... 'we'll be using it in 16-bit mode 'This is equal to 65535 - 62500 = 3035... 'Calculated to give us 1 sec interrupts with 1:16 prescalar TMR0H = $0B TMR0L = $DB 'Enables TMR0, set to 16-bit 'Enable Pre-scalar 'Set prescalar value 1:16 T0CON = %10000011 On Interrupt Goto myint ' Define interrupt handler 'Enable Timer0 Interrupt 'Turn on INTCON.7(GIE) and INTCON.5 (TMR0IE) INTCON = %10100000 TRISB.4 = 0 loop: led = ledstate Goto loop ' Do it forever ' Interrupt Service Routine Disable ' No interrupts past this point myint: if ledstate == 1 THEN ledstate = 0 ELSE ledstate = 1 ENDIF INTCON.2 = 0 ' Clear TMR0 interrupt flag TMR0H = $0B ' put 3035 in TMR0 for 1 sec interrupts TMR0L = $DB Resume ' Return to main program Enable ----------------------------------------------------------------------------------------
Instead of changing the state of the LED, you can increment a variable…If have you have a variable called
SECONDS, you can add 1 to SECONDS when this timer interrupt occurs. This will allow you to keep time…for time event driven processing.
TMR0 can hold a 16-bit value or an 8-bit value
TMR0 has a pre-scalar that can be set to either 2,4,8,16,32,64,128, or 256.
(What the pre-scalar do is that it slows down the counting of TMR0. If the pre-scalar is set to 32, TMR0 increments by 1 every 32 PIC clock “ticks”)
Here’s the math…
- 4Mhz crystal means an internal clock of 1Mhz
- 1Mhz means there’s an internal clock “tick” every .000001 sec.
- TMR0 can hold either a 16-bit(65536) or an 8-bit(256) value…I chose 16 (therefore TMR0 can count from 0 to 65535)
- If we just left it like this, TMR0 counts from 0 to 65535 and the TMR0 Interrupt will happen every 0.065536 sec (65536 * 0.000001) .
- We want TMR0 to interrupt every 1 sec.
- If we set the pre-scalar to 16, TMR0 will interrupt every…0.065536 * 16 = 1.048576 sec…pretty close to 1 sec.
- If you want you can leave it at this. If you want really precise timing, you have to do the following…you have to fill TMR0 with a starting value.(TMR0 is just a register so you can set it to any value.)
- We want the solution to the equation:
- value * 0.000001 * pre-scalar = 1.0 sec
- value = 1.0/(0.000001 * 16) = 62500
- So we want TMR0 to count 62500 not 65536. What we can do is to set TMR0 to 65535-62500 = 3035. So it actually counts from 3035 to 65535 which is 62500! We do this at the beginning of the program and every time an interrupt happens.
- TMR0 is a 16-bit register in my example, so we have to write two bytes…one is written to TMR0H (high byte) and TMR0L (low byte).
That’s it!
The table below shows the interrupt intervals you can expect from a 4Mhz clock, and a 16-bit TMR0.
| prescalar | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 |
| TMR0 INT happens every (sec) | 0.131 | 0.262 | 0.524 | 1.05 | 2.09 | 4.19 | 8.38 | 16.77 |