1

After reading the text about five times and googling I've decided to reach out for help. I'm currently in the process of using Timer_A interrupt to turn on/off two LEDS in intervals of 1 second/10 seconds/1 minute one at a time. The default program will turn on/off the LEDS every second but I cannot find a way to turn them off after 10 seconds and a minute. I can use __delay_cycles(xxxx) to achieve this but apparently doing so would defeat the purpose of the timer. This is my code.

#include <msp430.h>

#define RedLED BIT0
#define GreenLED BIT6

#define RedLEDToggle (P1OUT ^= RedLED)
#define GreenLEDToggle (P1OUT ^= GreenLED)

unsigned int counter = 0;


void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;
    //WDTCTL = WDT_MDLY_32;

    P1DIR = RedLED | GreenLED;
    P1OUT = RedLED | GreenLED;

    TACTL = TASSEL_2 | ID_3 | MC_3 | TAIE;

    TACCR0 = 62500;

    _enable_interrupts();


    LPM1;
}

#pragma vector=TIMER0_A1_VECTOR

__interrupt void Timer_A(void)
{

if ( counter == 10)
{
switch (TAIV)
    {
    case 0x02: break;
    case 0x04: break;
    case 0x0A: RedLEDToggle | GreenLEDToggle;
        break;
    }
}
else
{
counter ++;
}       
}
TheJr
  • 51
  • 7

3 Answers3

1

it is quite simple,\

You have a 1 second timer, that causes an interrupt every 1 second.

Your other times are multiples of that 1 second.

So, at the start of your program set a 10second counter to 0 and set a 1minute counter to 0.

At each 1 second interrupt, increment both counters.

Each time the 10 second counter steps from 9 to 10

  1. reset that counter to 0
  2. process the 10 second activity

Each time the 1 minute counter steps from 59 to 60

  1. reset that counter to 0
  2. process the 1 minute activity
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Thanks for the reply! After reading your post I did this. Set two unsigned ints in the beginning to zero. Then adder a counter at my one-second interrupt to count each second. However, when I add 10Second++ under switch(taiv){ , I get an error "statement is unreachable". – TheJr Jul 18 '16 at 04:50
  • Please post an edit to your question, (including the modified code), be sure to mark the new posted code as an edit. Then place a comment here indicating that you have made the edit. – user3629249 Jul 18 '16 at 15:36
1

The header defines symbols for the TAIV values; use them.

The XxxLEDToggle defines are complete statements; you should not treat them as expressions by combining them with |.

The interrupt handler can be called from multiple sources. At the moment, your program does not enable any others, but this is likely to change, so you should run your TAIFG-specific code only when TAIFG actually was set.

Once you have reached the limit, you need to reset the counter back to zero.

When you have multiple timer intervals, you need multiple counters. Otherwise, the first reset will reset the counting for all intervals.

You need something like this:

static unsigned int counter_10 = 0;
static unsigned int counter_60 = 0;

#pragma vector=TIMER0_A1_VECTOR
static __interrupt void Timer_A0(void)
{
    switch (TA0IV) {
    case TA0IV_TACCR1: break;
    case TA0IV_TACCR2: break;
    case TA0IV_TAIFG:
        if (++counter_10 >= 10) {
            counter_10 = 0;
            RedLEDToggle;
        }
        if (++counter_60 >= 60) {
            counter_60 = 0;
            GreenLEDToggle;
        }
        break;
    }
}
CL.
  • 173,858
  • 17
  • 217
  • 259
0

To achieve 10 second interrupt interval, you need to apply input divider to the timer. It is not possible to achieve 1 minute without peripheral support (see the other answers on how to implement that with a software counter).

The problem is that msp430 microcontrollers have 16-bit registers, not capable of holding numerical values larger than 65535. Using low-frequency oscillator running at 32768 Hz (as is typical - you don't provide any details about the hardware clock sources of your system, if they have a different frequency, please mention that) the register overflows once every 2 seconds unless an input divider is applied. The maximum value of input divider on MSP430x2xxx family MCUs is 8, so it's not possible to set a hardware timer more than 8 * 2 = 16 seconds in the future. Refer to MSP430x2xxx family user's guide for further details.

This code calls the interrupt once 10 seconds:

#include <msp430.h>

#define RedLED BIT0
#define GreenLED BIT6

#define RedLEDToggle (P1OUT ^= RedLED)
#define GreenLEDToggle (P1OUT ^= GreenLED)

// 10 seconds, assuming 32768 Hz ACLK source and divider 8
#define TIMER_PERIOD (10u * (32768 / 8))

void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;

    P1DIR = RedLED | GreenLED;
    P1OUT = RedLED | GreenLED;

    // reset timer A config (not strictly needed)
    TACTL = TACLR;

    // ACLK as clock source, divider 8, continuous mode, interrupt enabled
    TACTL = TASSEL_1 | ID_3 | MC_2 | TAIE;

    // set the period
    TACCR1 = TIMER_PERIOD;

    // enable capture/compare interrupts for CCR1
    TACCTL1 = CCIE;

    _enable_interrupts();

    LPM1;
}

#pragma vector=TIMER0_A1_VECTOR

__interrupt void Timer_A(void)
{
    switch (TAIV) {
    case 0x02:
        // CCR1 interrupt
        RedLEDToggle;
        GreenLEDToggle;
        // set the time of the next interrupt
        TACCR1 += TIMER_PERIOD;
        break;
    }
}
kfx
  • 8,136
  • 3
  • 28
  • 52
  • Note: the MSP430 (IIRC) does not allow direct manipulation of the I/O bits via `^=`, So you should keep an 'image' of the I/O port in memory, manipulate that image, then write the whole port from that image. – user3629249 Jul 19 '16 at 20:51