Simple Timer 1 interrupt example for the dsPIC30F4011

This is a minimal example of a Timer 1 interrupt in a dsPIC30F4011 program. I compiled it with Microchip’s C30 compiler. The main loop of the program simply flashes an LED on RD0 (pin23) at approximately 2 Hz. Meanwhile, Timer 1 triggers an interrupt every 500 ms which toggles a second LED on RD1 (pin 18).

To change how often the Timer 1 interrrupt service routine (ISR) gets called, you can either modify the value in the Timer 1 period register, PR1, or you can alter the Timer 1 prescaler value , T1CONbits.TCKPS (the main clock can be divided by 1, 8, 64 or 256).

In this example, the following line specifies that the internal fast RC oscillator should be used and that the PLL multiplier should be used to scale it up to 16 times its normal value.

_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16 x 7.5MHz = 120MHz

Since the dsPIC performs one instruction every four clock cycles, when Fosc is 120 Mhz, the chip is running at 30 MIPS (million instructions per second) and, most importantly, the instruction cycle, Tcy = 33.33 ns.

In this example, the Timer 1 prescaler is set to 256, which means that the timebase TMR1 increments (increases by 1) every 256 x Tcy seconds.

Timer 1 “tick” = 256 x 33.33ns = 8.533 us

PR1 then needs to be set to the number of ticks between interrupts.

Interrupt interval = PR1 x prescaler x Tcy = 58594 x 256 x 33.33 ns = 500 ms

That’s pretty much it, so here’s the source code.

// Simple Timer 1 interrupt example for dsPIC30F4011
// Written by Ted Burke - Last updated 12-4-2012

#include <libpic30.h>
#include <p30f4011.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

// Function prototype for timer 1 ISR
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void);

int main()
	// Configure RD0 and RD1 as outputs
	TRISD = 0b1100;

	// Configure Timer 1.
	// PR1 and TCKPS are set to call interrupt every 500ms.
	// Period = PR1 * prescaler * Tcy = 58594 * 256 * 33.33ns = 500ms
	T1CON = 0;            // Clear Timer 1 configuration
	T1CONbits.TCKPS = 3;  // Set timer 1 prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
	PR1 = 58594;          // Set Timer 1 period (max value is 65535)
	_T1IP = 1;            // Set Timer 1 interrupt priority
	_T1IF = 0;            // Clear Timer 1 interrupt flag
	_T1IE = 1;            // Enable Timer 1 interrupt
	T1CONbits.TON = 1;    // Turn on Timer 1

	// Main loop just flashes LED on RD0 at approx 2Hz.
	// Meanwhile, Timer 1 ISR flashes LED on RD1 at 1Hz.
		_LATD0 = 1;
		_LATD0 = 0;

	return 0;

// Timer 1 interrupt service routine toggles LED on RD1
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
	// Clear Timer 1 interrupt flag
	_T1IF = 0;

	// Toggle LED on RD1
	_LATD1 = 1 - _LATD1;
This entry was posted in Uncategorized. Bookmark the permalink.

11 Responses to Simple Timer 1 interrupt example for the dsPIC30F4011

  1. Johnny says:

    Wouldn’t you clear the timer 1 flag in the interrupt code after you toggle the LED on RD1? Why did you do it before? I thought clearing the flag should be the last step in the interrupt…?

    • batchloaf says:

      Hi Johnny. I suppose it might make more sense to clear the flag at the end of the interrupt service routine. However, in this case the ISR is so short (just toggle _LATD1) that it will certainly have completed long before the interrupt is triggered again. My understanding is that the ISR can’t be triggered again until the flag is reset, so on thatt basis perhaps it would make more sense to clear it at the end. Did you try running it both ways? I suspect you won’t see any difference in this case since the ISR is very short.

  2. Jerico says:

    In the example above, clearing the flag before or after doesn’t matter because the interrupt flag would always be cleared at the exact same location every time it is serviced, thus the time period of each toggle is not affected. Only the phase would be affected, such that if you clear the flag after the _LATD1, then the port will toogle sooner than when you clear the flag before the _LAD1.

    • batchloaf says:

      Hi Jerico,
      Supposing the ISR was much longer – so long in fact that a second interrupt (from the same timer) could occur before the ISR had completed – would it make a difference then whether the flag had been reset or not. My own guess is that if the flag is reset at the start of the ISR an interrupt occurs while the ISR is still executing, the same ISR will be called a second time immediately after it finishes the first time. However, if the flag is reset at the end of the ISR, the second interrupt would have no effect.

  3. Pingback: Aplikasi Timer 1 Interrupt Menggunakan dsPIC30F2020: Stopwatch Sederhana | Magatrika

  4. Mike Brewer says:

    THANK YOU!!!
    You saved me a lot of grief looking for a ***simple*** interrupt setup.

  5. Pingback: Aplikasi Timer1 Interrupt Menggunakan dsPIC30F4012: Simple Stopwatch for Busy Dummies | Beyond Sharing

  6. Don says:

    How would you use an interrupt on the ADC?

  7. Avi says:

    Thanks very much for this! This saved me lots of hours.
    The pre-scaler was my issue.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s