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.

Battery monitor using ADC

Other Parts Discussed in Thread: MSP430F5438, MSP430FR6989

Hello, i am using ADC to monitor battery level using the window comparator, to detect the battery voltage between two threshold or below the lower threshold or higher. The results is not accurate, how can i adjust these thresholds to be for example to be 2.8V and 2V. the input is 3.6 V. Here is my code.

Thank you

#include <msp430.h>

#define High_Threshold 0x0ff // ~2V
#define Low_Threshold 0x00f // ~1V


int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT

// Configure GPIO
P1SEL1 |= BIT3; // Configure ADC P1.1/A1
P1SEL0 |= BIT3;

// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;

// Clock System Setup


// Configure ADC12
// tsample = 16ADC12CLK cycles, tconvert = 14 ADC12CLK cycles
// software trigger for SOC, MODOSC, single ch-single conversion,
// tsample controlled by SHT0x settings
// Channel 1, reference = internal, enable window comparator
// Set thresholds for ADC12 interrupts
// Enable Interrupts
ADC12CTL0 = ADC12SHT0_3 | ADC12ON;
ADC12CTL1 = ADC12SHS_0 | ADC12SSEL_3 | ADC12CONSEQ_0 | ADC12SHP;
ADC12CTL2 = ADC12RES_2 ;
ADC12MCTL0 = ADC12INCH_3 | ADC12VRSEL_1 | ADC12WINC;
ADC12HI = High_Threshold;
ADC12LO = Low_Threshold;
ADC12IER2 = ADC12HIIE | ADC12LOIE | ADC12INIE;

// Configure internal reference
while(REFCTL0 & REFGENBUSY); // If ref generator busy, WAIT
REFCTL0 |= REFVSEL_2|REFON; // Select internal ref = 2.5V
REFCTL0 &= ~REFOUT ;
// Internal Reference ON
while(!(REFCTL0 & REFGENRDY)); // Wait for reference generator
// to settle
while(1)
{
ADC12CTL0 |= ADC12ENC | ADC12SC; // Enable & start conversion

}
}

  • Ahmed,

    while( 1 )
    {
      ADC12CTL0 |= ADC12ENC | ADC12SC; // Enable & start conversion
    }

    with this code you are starting a new conversion over and over again without waiting for a conversion to be completed. You have to check the BUSY flag or work with interrupts. In your case, not a single conversion can be finished.

    Dennis

  • HEre is the best guide to help you out with ADC. For reference voltages other than o.5v and 2.5v you need to provide steady external reference voltage.

    Have a look at this document. http://nslab.ee.ntu.edu.tw/courses/wsn-labs-fall-07/slides/Lab_3.ppt

  • sri-sri said:
    For reference voltages other than o.5v and 2.5v

    I guess you mean 1.5V?

    It depends on the used processor. If he is using the MSP430F5438(A), for example, then the REF module can provide 1.5V, 2V and 2.5V.

    Dennis

  • Thank you for your response, i am using MSP430FR6989..The reference voltage is 2.5V internally generated. The ADC results are not accurate specially when i switch the reference voltage from 1.2V to 2.5V. I think i need some calibration
  • Have you considered my first answer? And what does "not accurate" mean?
  • Dennis Eichmann said:
    I guess you mean 1.5V?

    Yup you are right, I am sorry. 

  • Yes i considered it, i was forgetting waiting for the ADC to complete. The results are accurate; i am using 2.5V as a reference voltage, when i apply to the analog pin 2.5V or higher i expect to have the full scale 0x0fff but the value is lower than this and always oscillates. I expect to have the full scale 0x0fff when the input voltage is 2.5V or higher but i notice through the debugger that the values from 2.5V to 3.6V changes proportional to the conversion result. How ??! 

  • Where do the 2.5V come from? Maybe the output impedance of the source is too high and your S&H time is too short.
  • The 2.5V is internally generated reference voltage. The input analog signal is come from 3.6V battery connected to potentiometer
  • So it is a resistor divider. What is it's value? Could you post your updated code?
  • #include <msp430.h>

    #define High_Threshold 0x400 // ~2.5V
    #define Low_Threshold 0x220 // ~2V


    int main(void)
    {
    static unsigned char batteryHighCounter = 0 ;
    static unsigned char batteryLowCounter = 0 ;
    static unsigned char batteryInCounter = 0 ;
    volatile unsigned char batteryHighFlag = 0 ;
    volatile unsigned char batteryLowFlag = 0 ;
    volatile unsigned char batteryInFlag = 0 ;

    WDTCTL = WDTPW | WDTHOLD; // Stop WDT

    // Configure GPIO
    P1SEL1 |= BIT3; // Configure ADC P1.1/A1
    P1SEL0 |= BIT3;

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    ADC12CTL0 = ADC12ON;
    ADC12CTL0 |= 0x0a00; // set the sampling period to 512 clk for high accuracy

    ADC12CTL1 = ADC12SHS_0 | ADC12SSEL_3 | ADC12CONSEQ_0 | ADC12SHP;
    ADC12CTL2 = ADC12RES_2 ;
    ADC12MCTL0 = ADC12INCH_3 | ADC12VRSEL_1|ADC12WINC ;
    ADC12HI = High_Threshold;
    ADC12LO = Low_Threshold;

    // Configure internal reference
    while(REFCTL0 & REFGENBUSY); // If ref generator busy, WAIT
    REFCTL0 |= REFVSEL_2|REFON; // Select internal ref = 2.5V
    REFCTL0 &= ~REFOUT ;
    // Internal Reference ON
    while(!(REFCTL0 & REFGENRDY)); // Wait for reference generator
    // to settle
    while(1)
    {
    __delay_cycles(10);
    ADC12CTL0 |= ADC12ENC | ADC12SC; // Enable & start conversion
    while(ADC12CTL1 & ADC12BUSY);

    if((ADC12IFGR2 & ADC12HIIFG) != 0)
    {
    ADC12IFGR2 &= ~ADC12HIIFG ;
    batteryHighCounter++ ;
    batteryInCounter = 0 ;
    batteryLowCounter = 0 ;
    }
    else if((ADC12IFGR2 & ADC12INIFG) != 0)
    {
    ADC12IFGR2 &= ~ADC12INIFG ;
    batteryInCounter++ ;
    batteryHighCounter = 0 ;
    batteryLowCounter = 0 ;
    }
    else if((ADC12IFGR2 & ADC12LOIFG) != 0)
    {
    ADC12IFGR2 &= ~ADC12LOIFG ;
    batteryLowCounter++ ;
    batteryInCounter = 0 ;
    batteryHighCounter = 0 ;
    }


    if(batteryHighCounter == 2) // 5 to ensure that the flag is set 5 times
    {
    // battery high
    batteryHighCounter = 0 ;
    batteryHighFlag = 1 ;
    batteryLowFlag = 0 ;
    batteryInFlag = 0 ;
    }

    else if(batteryInCounter == 2)
    {
    // battery between the two thresholds
    batteryInCounter = 0 ;
    batteryHighFlag = 0 ;
    batteryLowFlag = 0 ;
    batteryInFlag = 1 ;
    }
    else if(batteryLowCounter == 2)
    {
    // battery low
    batteryLowCounter = 0 ;
    batteryHighFlag = 0 ;
    batteryLowFlag = 1 ;
    batteryInFlag = 0 ;
    }

    }
    }
  • Thank you all for your concern. I was missing the ground signal of the controller, the code is OK.

  • Gald you found the issue! You could mark your thread (your last answer) as correct solution. This helps others to see it is solved and maybe someone else will find this thread and will benefit from the solution.

    Dennis

**Attention** This is a public forum