This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Finding time for ADC input

Other Parts Discussed in Thread: MSP430G2553

I am using msp430G2553.

I basically want to find the time for which ADC value is greater than 511 and use this time to put on either the red or green led.

But whenever I run this code only the if(t<3000000) condition is executed at all times.

I want the code to run dynamically.

This is my code.

#include<msp430.h>

unsigned int value=0;

// Function prototypes
void ConfigureAdc(void);

void main(void)
{
{ int t;
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ;
BCSCTL2 &= ~(DIVS_3);
P1DIR|=BIT0+BIT6;

P1SEL|=BIT1;
P1SEL |= BIT3;
TACTL=TASSEL_2+ID_0+MC_2;
ConfigureAdc(); // ADC set-up function call
__enable_interrupt(); // Enable interrupts.

while(1)
{
__delay_cycles(1000); // Wait for ADC Ref to settle
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
__bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled// Low Power Mode 0 with interrupts enabled
value = ADC10MEM;
if(value>511)
TA1R=0;
else

{

t=TA1R;

if(t<3000000)
{P1OUT&=~(BIT0+BIT6);
P1OUT|=BIT0;
}
else
{P1OUT&=~(BIT0+BIT6);
P1OUT|=BIT6;

}

}


}

}
}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR

__interrupt void ADC10_ISR (void)

{

__bic_SR_register_on_exit(CPUOFF); // Return to active mode

}


// Function containing ADC set-up
void ConfigureAdc(void)
{

ADC10CTL1 = INCH_3 + ADC10DIV_3 ; // Channel 3, ADC10CLK/3
ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; // Vcc & Vss as reference, Sample and hold for 64 Clock cycles, ADC on, ADC interrupt enable
ADC10AE0 |= BIT3; // ADC input enable P1.3
}

  • TAxR is a 16-bit register, so it can never be larger than 65535.
  • I actually want to calculate the time for which adc<511 and use this time(if time<3 sec) to glow my leds. How do i go about this?
  • Use the divider bits (IDx) to run the timer at a slower speed. Or use another, slower clock.

    Use the timer overflow interrupt (TAIFG) to detect when the timer overflows, and count those overflows.

  • I tried this code but still I am not able to get the results.I want to glow the led on pin1.6 when time<3sec otherwise glow led on pin 1.0.

    #include<msp430.h>
    unsigned int value=0;
    unsigned int count=0;

    // Function prototypes
    void ConfigureAdc(void);

    void main(void)
    {
    {

    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ;
    BCSCTL2 &= ~(DIVS_3);
    P1DIR|=BIT0+BIT6;

    P1SEL|=BIT1;
    // SMCLK = DCO = 1MHz
    P1SEL |= BIT3;
    // ADC input pin P1.3
    ConfigureAdc(); // ADC set-up function call
    __enable_interrupt(); // Enable interrupts.

    while(1)
    {
    __delay_cycles(1000); // Wait for ADC Ref to settle
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled// Low Power Mode 0 with interrupts enabled
    value = ADC10MEM;
    if(value>511)
    { TAR=0;
    CCTL0 = CCIE; // CCR0 interrupt enabled
    TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK/1, upmode
    CCR0 = 1000; //overflow frequency :1000hz frequency


    }

    else
    {
    if(count<3000)
    {P1OUT&=~(BIT0+BIT6);
    P1OUT|=BIT6;
    }
    else
    {P1OUT&=~(BIT0+BIT6);
    P1OUT|=BIT0;

    }

    }


    }

    }
    }

    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR

    __interrupt void ADC10_ISR (void)

    {

    __bic_SR_register_on_exit(CPUOFF); // Return to active mode

    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
    count++;
    }


    // Function containing ADC set-up
    void ConfigureAdc(void)
    {

    ADC10CTL1 = INCH_3 + ADC10DIV_3 ; // Channel 3, ADC10CLK/3
    ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; 
    ADC10AE0 |= BIT3; // ADC input enable P1.3

    1. }
  • The count variable must be volatile, otherwise the main loop might not see changes made by an interrupt handler.
    The count variable should be initialized when you are starting the timer.
  • What do you mean by count variable must be volatile?I have initialized count globally.Why should we initialize the count variable at the start of the timer?
  • Should count=0; be after TACTL = TASSEL_2 + MC_1 + ID_0;?
  • I ran the following code.Still not able to find the results.Please help me.
    #include<msp430.h>
    unsigned int value=0;
    unsigned volatile int count;

    // Function prototypes
    void ConfigureAdc(void);

    void main(void)
    {
    {

    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ;
    BCSCTL2 &= ~(DIVS_3);
    P1DIR|=BIT0+BIT6;

    P1SEL|=BIT1;
    // SMCLK = DCO = 1MHz
    P1SEL |= BIT3;
    // ADC input pin P1.3
    ConfigureAdc(); // ADC set-up function call
    __enable_interrupt(); // Enable interrupts.

    while(1)
    {
    __delay_cycles(1000); // Wait for ADC Ref to settle
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled// Low Power Mode 0 with interrupts enabled
    value = ADC10MEM;
    if(value>511)
    { TAR=0;
    CCTL0 = CCIE; // CCR0 interrupt enabled
    TACTL = TASSEL_2 + MC_1 + ID_0;
    count=0;// SMCLK/1, upmode
    CCR0 = 1000; //overflow freq:1000hz frequency


    }

    else
    {
    if(count<3000)
    {
    P1OUT&=~(BIT0+BIT6);
    P1OUT|=BIT6;
    }
    else
    {
    P1OUT&=~(BIT0+BIT6);
    P1OUT|=BIT0;

    }

    }


    }

    }
    }

    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR

    __interrupt void ADC10_ISR (void)

    {

    __bic_SR_register_on_exit(CPUOFF); // Return to active mode

    }
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
    count++;
    }


    // Function containing ADC set-up
    void ConfigureAdc(void)
    {

    ADC10CTL1 = INCH_3 + ADC10DIV_3 ; // Channel 3, ADC10CLK/3
    ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; // Vcc & Vss as reference, Sample and hold for 64 Clock cycles, ADC on, ADC interrupt enable
    ADC10AE0 |= BIT3; // ADC input enable P1.3
    }
  • Some things to say...
    You don't want to wait for the reference to settle each time. Do it once after setting-up the ADC (in the ADC init function). But you use SREF_0, so using VCC. No reference settling time needed at all. (or did you mean using SREF0, which would select the internal reference? Then REFON woudl be needed too)
    To avoid being locked-up you should have interrupts disabled all time and enable them (as you do) with the instruction to enter LPM. Else it might happen that your ISR is called (once) before you have even entered LPM and then you're stuck in LPM. That's a general thing.
    As soon as your ADC value is >511, you clear TAR. This isn't the recommended method to reset the counter (but works in most cases). But moreover, you disturb the timer cycle this way, so your whole timing gets a skew.
    Also, you don't start the timer right away, so when you start your program, the timer is stopped and count is not increasing, no matter how long it takes for the first time to get >511.
    Finally, count may eventually overflow (that is, if you ever got above 511 and then never again) after 65 seconds. So it will appear as if there was a value >511 even if there was none. You should have a line that limits count before it reaches 65535. Maybe inside the ISR.

**Attention** This is a public forum