GPIO Interrupt Example

The first example we’ll do uses the Port 1 interrupts; this code is easily changed for any port number used in your particular device.This code will show how to do the DCO example we did in

Tutorial08-b

, which demonstrates changing the DCO, using interrupts.

First, we need to configure the port to use interrupts.The LaunchPad button is on P1.3, so all of our concern will be on that pin.The pin needs to be configured as an input.Since the default state of the pin is logic 1, a high-low transition (a drop from 1 to 0) should be used to signal the interrupt.We can code this using:

P1IES |= BIT3;// high -> low is selected with IES.x = 1.
P1IFG &= ~BIT3;// To prevent an immediate interrupt, clear the flag for
// P1.3 before enabling the interrupt.
P1IE |= BIT3;// Enable interrupts for P1.3

We’ve enabled the interrupt for P1 now, and a high-low transition caused by the button press will set the interrupt flag in P1IFG.The processor, however, isn’t set to recognize maskable interrupts like P1IFG.We can turn on the interrupts with:

_BIS_SR(GIE);

or equivalently:

_enable_interrupt();// Note the singular name here!It’s not interrupts.

The first method parallels the

bis.w

instruction in assembly used for this command, and can be used to configure the SR in one step with other options, such as low power modes.The second method is a little more human readable, and works well enough if you don’t need to enable any LPM’s.

Next we need to write the ISR.Something like this will work:

#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void) {
switch(P1IFG&BIT3) {
case BIT3:
P1IFG &= ~BIT3;// clear the interrupt flag
BCSCTL1 = bcs_vals[i];
DCOCTL = dco_vals[i];
if (++i == 3)
i = 0;
return;
default:
P1IFG = 0;// probably unnecessary, but if another flag occurs
// in P1, this will clear it.No error handling is
// provided this way, though.
return;
}
} // P1_ISR

The port interrupts can be sourced from 8 port pins, and so the ISR needs to decide what to do with each possible interrupt.The switch statement in C is ideal for this task, and is used here to single out a BIT3 flag.If, for some reason, the MSP430 is flagged with a different Port 1 interrupt, it simply clears the flag and moves on.Since none of the other flags are enabled, this should never happen, but it’s good coding practice to include something like this.Error handling would be ideal, but it’s not done here.

Note that since the P1 interrupt has 8 sources and individual flags, you need to clear the flag manually.Don’t forget to do this, or your code will continually keep interrupting!This code makes use of three pre-stored values for BCSCTL1 and DCOCTL and increments through them each time the interrupt is called.These values, as well as the counter

i

, need to be global for the ISR to see them, and so they are declared outside of the

main()

function.See the whole code put together in

interrupted-1_G2211.c

.

Timer_A Example

As a second example, we’ll do something similar to a project I’m working on and turn a light on and off using a relay switch.I’ve coded this using a switch on P1.6 so that you can observe its behavior on a LaunchPad using the green LED instead of the actual relay.If you have a relay, be sure to

connect it correctly

to prevent too much current draw from your MSP430.Using the 1 MHz calibrated DCO divided by 8, Timer_A will count up to 62,500 in 0.5 s.In my actual application, I’d like to turn the light on for a few hours, then turn it off for a few hours.That’s easier to do with a slower clock, and an ideal application for the LFXT1 clock source.But, since we haven’t covered that yet and many people likely do not have the crystal soldered to their LaunchPad’s, we’ll do more frequent on/off cycles to simulate the actual process.We’ll use the DCO to turn the light on and off in 1 minute intervals.To do this, we’ll make use of the Timer_A up mode and interrupt using the CCR0 registers.(Yes, this is essentially a fancy version of blinky.Turns out “Hello, world!” is actually useful in microcontrollers!)

We configure the timer with the following:

TACCR0 = 62500 – 1;// a period of 62,500 cycles is 0 to 62,499.
TACCTL0 = CCIE;// Enable interrupts for CCR0.
TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR;

The long string of assignments to TACTL are, in order, select SMCLK as the clock for Timer_A (runs off the DCO by default), select input divider of 8 (1 MHz SMCLK becomes 125 kHz), select up mode, and clear the count in TAR.These values are defined in the device header file so that you don’t have to constantly manipulate bits by hand.The mnemonics are easier to use most of the time.(For other configuration options, see the Timer_A section in your device’s header file.)

The ISR may look something like this:

#pragma vector = TIMERA0_VECTOR
__interrupt void CCR0_ISR(void) {
// no flag clearing necessary; CCR0 has only one source, so it’s automatic.
if (++i == 120) {
P1OUT ^= RLY1;
i = 0;
}
} // CCR0_ISR

Again, we’re using a global variable

i

as a counter, and presumably have defined

RLY1

to be

BIT6

in the program header.Every time a flag occurs (twice a second) the counter is incremented.If we’ve reached 120 (60 s at 2 Hz) the relay control is toggled and the counter resets.

The complete code for this example is in

interrupted-2_G2211.c

.For you impatient folks, feel free to adjust the timer period to whatever value preserves your sanity.

These two examples should get you started with interrupts.As always, feel free to ask questions or suggest other helpful tips!

[via: http://mspsci.blogspot.com]

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
   
© 2011 Geko Geek This is a news aggregator website. Articles and images are copyrighted to their original source authors. Gekogeek takes no responsibility about the articles content Suffusion theme by Sayontan Sinha