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 indicator

Other Parts Discussed in Thread: MSP430FG4618, MSP430G2553

Hello,

I have designed a talking alarm clock using MSP430FG4618 experiments board. However, on the display i noticed that there is a battery indicator symbol

that i can use. It should be very simple to implement it. But i cannot get my head around it. Can anyone help me with this.

#define BAT_FULL LCDM12 |= 0x0F                    //    BAT_FULL = "BB"+"B0"+"B1"+"BT" (ON)
#define BAT_LOW LCDM12 |= 0x08 // BAT_LOW = "BB" (ON)
#define BAT_50 LCDM12 |= 0x0C // BAT_50% = "BB"+"B0" (ON)
#define BAT_90 LCDM12 |= 0x0e // BAT_90% = "BB"+"B0"+"B1" (ON)

I have defined the following variables just to indicate the status of the battery. 
The way i m thinking about it is a bunch of if conditions . LIke

If (something is true)
{ BAT_FULL;}......
if(something else is true){
BAT_LOW;}

I m not sure what comparison to make....maybe the ADC ref ....but how??? Please help...some kind of short code will be appreciated...or some kind of direction....??
  • Hi Imran,

    below a short code snippet from one of my tests. You will need to adopt it to your MSP430 - but the idea should become clear. You can use the internal voltage reference and AVcc voltage divider to measure the supply voltage to become a frist idea of your battery status. The code below uses the internal 2.5V reference (REF2_5V) and as input channel the voltage divider. 

    In my case the MSP has a 10bit ADC (your IMHO 12bit), so the entire ADC range from 0V to 2.5V is divided in 1024 steps of 0.00244. I read for example a value of 721 - multiplied with the step range gives 1.76V - at the voltage divider, finally multiply by two and you get 3.52V.

    For your problem, define which voltages are "full" (maybe 3V and above, that means 1.5V at the divider giving an ADC value of 613) and  low (maybe 1.8V, giving 0.9V at the divider or an ADC value of 368). This as guide only, your ADC will differ and likely you will be a bit more pessimistic with your low voltage and you maybe need more than 1.8V minimum.

    Details are in the datasheet for the minimum voltages across the cpu frequency range and the ADC and it's channels are described in the familiy guide (page 789 e.g.):

    http://www.ti.com/general/docs/lit/getliterature.tsp?literatureNumber=slau056j&fileType=pdf

    #include <msp430g2553.h>
    #include <stdbool.h>

    void Single_Measure(unsigned int);
    void Single_Measure_REF(unsigned int, unsigned int);

    unsigned int ADCValue;                                                  // Measured ADC Value
    unsigned int i;
    bool ADCDone;                                                           // ADC Done flag

    void main(void) {
        WDTCTL = WDTPW + WDTHOLD;                                           // Stop watchdog timer
        P1DIR |= 0x01;                                                      // Set P1.0 to output direction
        __bis_SR_register(GIE);

        ADCDone = false;
        Single_Measure_REF(INCH_11, REF2_5V);

        while(true) {

            if (ADCDone) {
                ADCDone = false;
                i = ADCValue;                                               // Set breakpoint here
            }
        }
    }

    void Single_Measure_REF(unsigned int chan, unsigned int ref) {
        ADC10CTL0 &= ~ENC;                                                  // Disable ADC
        ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ref + ADC10IE;  // Use reference,
                                                                            // 16 clock ticks, internal reference on
                                                                            // ADC On, enable ADC interrupt, Internal = 'ref'
        ADC10CTL1 = ADC10SSEL_3 + chan;                                     // Set 'chan', SMCLK
        __delay_cycles(128);                                                // Delay to allow Ref to settle
        ADC10CTL0 |= ENC + ADC10SC;                                         // Enable and start conversion
    }

    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void) {
        ADCValue = ADC10MEM;                                                // Saves measured value.
        ADCDone = true;                                                     // Sets flag for main loop.
        ADC10CTL0 &= ~ENC;                                                  // Disable ADC                                                                  
    }


  •  HI Jan,
    Look this is the program I modified ...taking the example code from code examples.... This should work right?? Its a bit
    different from what you are trying to do....will this not work???
    
    
    #include "msp430fg4618.h"
    #include "LCD_defs.h" // BAT_FULL and BAT_low defined here....
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    ADC12CTL0 = SHT0_2 + ADC12ON; // Sampling time, ADC12 on
    ADC12CTL1 = SHP; // Use sampling timer
    ADC12IE = 0x01; // Enable interrupt
    ADC12CTL0 |= ENC;
    P6SEL |= 0x01; // P6.0 ADC option select
    P5DIR |= 0x02; // P5.1 output

    while (1)
    {
    ADC12CTL0 |= ADC12SC; // Start sampling/conversion
    __bis_SR_register(LPM0_bits + GIE); // LPM0, ADC12_ISR will force exit
    }
    }

    #pragma vector = ADC12_VECTOR
    __interrupt void ADC12_ISR(void) //(2^12=4096 ....2.5/4096
    { // AVcc=3V
    if (ADC12MEM0 >=0x7ff) // ADC12MEM = A0 > 1.5V (0x7ff= 2047 in decimal half of 2^12)

    BAT_FULL; //display battery full (defined in header files)

    else
    BAT_LOW; // display battery low

    __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
    }
  • Not having read the complete data sheet and guide, I'm missing a setup for ADC12MCTL0 - to select the reference and input channel for your conversation? Where do you get a voltage reference from?

    For monitoring the supply voltage I recommend to use the internal 2.5V reference and the internal voltage divider. So you do not need any external pins or parts and you are done over the entire operating voltage range.

  • Hi Jan,

    I really apologise . But I have been trying for a while, however, I m not able to follow your code. So  here is what I did. The ADC

    I am using is 12 bit...so 2^12= 4096.....dividing the range 0-2.5 v gives me 0.000614...Now for simplicity. I will consider

    two cases only low voltage( Low battery will turn a segment ON at the LCD) and High voltage( battery full lights up another segment 

    On at LCD to indicate)

    The corresponding values for :high voltage=3V ...at divider= 1.5 V and ADC value=1.5/0.000614= 2459 (0x99C in hex)

                                                         : Low voltage= 2.5 V at divide = 1,25V and ADC value=1.25/0.000614=2049(0x801 in hex)

    Now this is how i calculate the corresponding values....are they alright??

    If I come to your code..... the BOLD part is what I added to it......... Does it make any sense?? Thanks so much for your time

    but I have been sitting on this for hours and hours...but it still making no sense to me....It is suppose to be very simple...!!

    The integer ''i'' you have defined... The way I am thinking about it is....when the ADC has finished conversion
    the ADC value is assigned to i.....
    #include <msp430g2553.h>
    #include <stdbool.h>
    #include "LCD_defs.h"

    void Single_Measure(unsigned int);
    void Single_Measure_REF(unsigned int, unsigned int);

    unsigned int ADCValue; // Measured ADC Value
    unsigned int i;
    bool ADCDone; // ADC Done flag

    void main(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
    P1DIR |= 0x01; // Set P1.0 to output direction
    __bis_SR_register(GIE);

    ADCDone = false;
    Single_Measure_REF(INCH_11, REF2_5V);

    while(true) {

    if (ADCDone) {
    ADCDone = false;
    i = ADCValue; // Set breakpoint here
    }
    }
    /// BATTery INDICATION ROUTINE
    if (i>=0x99C) // if VCC>=2.5 ( for simplicity i will display any value above 2.5 as battery full
    //any value less than 2.5 will be battery low
    BAT_FULL;
    else

    BAT_LOW;


    }




    void Single_Measure_REF(unsigned int chan, unsigned int ref) {
    ADC10CTL0 &= ~ENC; // Disable ADC
    ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ref + ADC10IE; // Use reference,
    // 16 clock ticks, internal reference on
    // ADC On, enable ADC interrupt, Internal = 'ref'
    ADC10CTL1 = ADC10SSEL_3 + chan; // Set 'chan', SMCLK
    __delay_cycles(128); // Delay to allow Ref to settle
    ADC10CTL0 |= ENC + ADC10SC; // Enable and start conversion
    }

    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void) {
    ADCValue = ADC10MEM; // Saves measured value.
    ADCDone = true; // Sets flag for main loop.
    ADC10CTL0 &= ~ENC; // Disable ADC
    }

  • I mean ... I will fix other things like header file and ADC12 parameters instead of ADC10... Later on and everything....but  just to get a general idea....is it right to think about this problem??

  • I have made the necessary changes....Does this make sense.....Still not quite sure how to implement the display....!!
    
    
    
    
    
    
    #include <msp430fg4618.h>
    #include <stdbool.h>
    #include "LCD_defs.h"

    void Single_Measure(unsigned int);
    void Single_Measure_REF(unsigned int, unsigned int);

    unsigned int ADCValue; // Measured ADC Value
    unsigned int i;
    bool ADCDone; // ADC Done flag

    void main(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
    P1DIR |= 0x01; // Set P1.0 to output direction
    __bis_SR_register(GIE);
    //LCD_A S0-S21 configuration
    LCDAPCTL0 = LCDS24 | LCDS20 | LCDS16 | LCDS12 | LCDS8 | LCDS4;

    // LCD_A configuration
    LCDACTL = LCDFREQ_192 | LCD4MUX | LCDSON | LCDON; // (ACLK = 32768)/192, 4-mux LCD, LCD_A on, Segments on
    LCDAVCTL0 = LCDCPEN; // Charge pump enable
    LCDAVCTL1 = VLCD_3_44; // VLCD = 3,44 V

    ADCDone = false;
    Single_Measure_REF(INCH_11, REF2_5V);

    while(1) {

    if (ADCDone) {
    ADCDone = 0;
    i = ADCValue;
    if (i>=0x99C){ // if VCC>=2.5 ( for simplicity i will display any value above 2.5 as battery full
    //any value less than 2.5 will be battery low
    BAT_FULL;
    } else

    BAT_LOW;


    }// Set breakpoint here
    }
    }
    /// BATTery INDICATION ROUTINE





    void Single_Measure_REF(unsigned int chan, unsigned int ref) {
    ADC12CTL0 &= ~ENC; // Disable ADC conversion
    ADC12CTL0 = SHT0_2 + REFON + ADC12ON +ref ;
    ADC12MCTL0=SREF_1+chan; // selecting reference and channel 11(( Avcc-Avss)/2)
    __delay_cycles(128); // Delay to allow Ref to settle
    ADC12IE=0x01;
    // Use reference,
    // ADC12CTL0 = SREF_1 + REFON + ADC12ON + ref + ADC12IE; // 16 clock ticks, internal reference on
    ADC12CTL1 = ADC12SSEL_3;
    __enable_interrupt(); // ADC On, enable ADC interrupt, Internal = 'ref'
    // Set 'chan', SMCLK

    ADC12CTL0 |= ENC + ADC12SC;
    // Enable and start conversion
    }

    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12_ISR(void) {
    //ADCValue =(void(*)())& ADC12MEM;
    ADCValue =(unsigned int)ADC12MEM0; // Saves measured value.
    ADCDone = 1; // Sets flag for main loop.
    ADC12CTL0 &= ~ENC; // Disable ADC conversion
    }

**Attention** This is a public forum