TIMER3Interrupt
An interrupt timer using TIMER3 by Mark Rodgers
Module Notes
The code is fully commented and is written to allow me to understand exactly what it took to get the interrupt to run on TIMER3.
The routine is running on an 18F67J11, providing the register address for CCPR3L and CCPR3H is the same in all other PICs, no modification to the code will be needed(provided they have a TIMER3 that is!).
I am using this code on a project that switches the INTOSC and the PLL on and off to save power when in use on its small cell, but need the interrupt timer to test for events that could occur at any time.
This is now achievable even at 31khz using the on board very low power oscilator as the main clock for the PIC and still have a 10ms interrupt period to test for button presses and other user inputs.
Some inspiration was taken from this informative article by xor:-
http://www.sfcompiler.co.uk/wiki/pmwiki.php?n=SwordfishUser.SoftRTC
The TIMER3 Interrupt Service Routine code
{ ***************************************************************************** * Name : TIMER3_Interrupt.bas * * Author : Mark Rodgers * * Notice : Copyright (c) 2007 Mark Rodgers * * : All Rights Reserved * * Date : 10/09/2007 * * Version : 1.0 * * Notes : * * : * ***************************************************************************** } '****************************************************************************** '****************************************************************************** Module TIMER3_Interrupt_Service_Routine '****************************************************************************** '****************************************************************************** 'the address in PIC memory for the CCPR3L byte register, CCPR3H is the Next address 4019 Const CCPR3_register_address=4018 'create a word from CCPR3L and CCPR3H byte registers Dim CCPR3_register_word As Word Absolute CCPR3_register_address 'alias the interrupt flag Dim CCPR3_interrupt_flag As PIR3.0 'incremented at every interrupt Dim interrupt_clock As Word 'incremented every second, available to main program and other modules Public Dim secs As Byte '****************************************************************************** '****************************************************************************** 'TIMER3 INTERRUPT ROUTINE. 'THE VALUE FOR "CCPR3_register_word" IS TAKEN FROM THE FOLLOWING CALCULATION. 'THE TIMER STARTS AT THIS VALUE THEN COUNTS DOWN TO 0. 'AT THAT POINT THE INTERRUPT OCCURS AND THE COUNTER IS RELOADED. ' 'CRYSTAL=4MHZ 'INTERNAL CLOCK=1MHZ(PIC divides clock by 4 internally) 'SINGLE MACHINE CYCLE=1second/1,000,000=0.000001(1 microsecond) 'FOR A 1ms INTERRUPT THE RELOAD VALUE IS 1000. 'FOR A 10ms INTERRUPT THE RELOAD VALUE IS 10000. 'THE RELOAD OF THE REGISTER TAKES 1 CLOCK CYCLE, THEREFORE:- 'WITH "CCPR3_register_word = 999" THE PERIOD IS 1ms(1000Hz) 'WITH "CCPR3_register_word = 9999" THE PERIOD IS 10ms(1000Hz) ' 'WHEN USING DIFFERENT SPEED CLOCKS AND A 1ms INTERRUPT:- '32MHz, "CCPR3_register_word" IS 7999(8000-1 FOR RELOAD) '16MHz, "CCPR3_register_word" IS 3999(4000-1 For RELOAD) '8MHz, "CCPR3_register_word" IS 2999(2000-1 For RELOAD) '4MHz, "CCPR3_register_word" IS 999(1000-1 For RELOAD) '2MHz, "CCPR3_register_word" IS 499(500-1 For RELOAD) '1MHz, "CCPR3_register_word" IS 249(250-1 For RELOAD) ' 'WHEN USING THE INTERNAL 31kHz OSCILATOR 'THE INTERNAL CLOCK PERIOD IS 1/7750:- '=0.000129 OR 129us. '1ms/129=7.75 AND WE CAN ONLY HAVE INTEGERS! 'USING 7 AND RELYING ON THE RELOAD TIME OF 1 WE HAVE 'A TOTAL TIME OF 8X129=1032us. 'THIS IS 1.032ms SO CLOSE ENOUGH FOR MOST USES. '31kHz, "CCPR3_register_word" IS 7(8-1 For RELOAD) ' 'WITH ONLY 7 MACHINE CYCLES TO RUN CODE INSIDE THE INTERRUPT IT WOULD NOT REALLY 'BE PRACTICAL TO OPERATE AT 1ms, 10ms WOULD BE BETTER(AND MORE ACCURATE):- '78X129=10062us OR 10.062ms:- '31kHz, "CCPR3_register_word" IS 77(78-1 For RELOAD). '############################################################################## interrupt TIMER3_Interrupt() 'USER CODE GOES HERE ONLY!!! '################################## Inc(interrupt_clock) 'increment at every interrupt If interrupt_clock = 1000 Then '1msx1000=1second interrupt_clock = 0 'clear the interrupt counter Inc(secs) 'increment the seconds counter End If '################################## 'THIS FLAG CLEARING MUST BE THE LAST 'LINE OF THE CODE, THE NEXT INTERRUPT 'WILL NOT BE REGISTERED UNTIL CLEARED '################################## CCPR3_interrupt_flag = 0 'clear CCP3 interrupt flag '################################## End interrupt '############################################################################## '****************************************************************************** '****************************************************************************** 'INITIAL SETTINGS FOR THE TIMER3 REGISTERS AND VARIABLES '############################################################################## Sub Initialize() 'Global Interrupt Enable(GIE bit7) and Peripheral Interrupt Enable(PEIE bit6) bits of INTCON INTCON = %11000000 'TIMER3 used as source for ECCP3(bits 6and 3), no prescaler(bits5 and 4), TIMER3 is off(bit0) T3CON = %00001000 'enable special event trigger(bits 3 to 0) CCP3CON =%00001011 'set match value for 1ms at 4MHz, -1 "tick" that is taken to reset the timer count value CCPR3_register_word = 999 PIE3.0 = 1 'enable CCP3 interrupt CCPR3_interrupt_flag = 0 'clear CCP3 interrupt flag TMR3H = 0 'clear TIMER3 TMR3H register TMR3L = 0 'clear TIMER3 TMR3L register interrupt_clock=0 'clear the interrupt counter secs=0 'clear the seconds counter T3CON.0 = 1 'switch on TIMER3 Enable(TIMER3_Interrupt) 'enable TIMER3 ISR End Sub '############################################################################## '****************************************************************************** '****************************************************************************** Initialize 'run the initialisation routine '****************************************************************************** '******************************************************************************