read LiFePO4 battery voltage from 3v3 pin

Started by d00m178, March 27, 2019, 05:16:43 PM

d00m178

I'm using Moteino R6 with RFM95 module.

MCU powered from 4 LiFePo4 batteries 18650 connected in parrallel.
Each battery shows 3.2 volts and I have total 3.2 volts on 3v3 pin.

I would like to check this voltage level in code and send this data via LoRa.
How the best way I can do it?
Please advice.

From my previous similar project I used voltage divider with 470k and 1M resistors. And capacitor 0.1uF.
I powered MCU via Vin pin from LiPo battery which have about 4.2 volts
Please take a look at attachment - there is only one change - in my previous project I connected divider to Vin pin, not 3v3.

And I use such code for read Vcc and check battery voltage:

long readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif

  delay(75); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both

  long result = (high<<8) | low;

  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in millivolts
}


float checkBattery()
{
 // if (cycleCount++ == BATT_CYCLES) //only read battery every BATT_CYCLES sleep cycles
 // {
        vcc = readVcc();
        //Serial.print(" Vcc:");Serial.println(vcc);
        //put Vcc info into array data_buf
        data_buf[13]=(float)vcc/1000.0;

    unsigned int reading=0;
    for (byte i=0; i<10; i++)
      reading += analogRead(BATT_MONITOR);

    float batteryVolts;
    //470K / (470K + 1000K) == 0.3197   1/0.3197 == 3.127
    //batteryVolts = (reading / 10.0)* 0.00322 * 3.127;

    batteryVolts = (reading / 10.0)* (data_buf[13]/1023) * 3.127;

// *********************************************************************************************************
//      Serial.print(" batV:");Serial.println(batteryVolts);
// *********************************************************************************************************
    return batteryVolts;
    //cycleCount = 0;
 // }
}


so when I call checkBattery() I receive Vcc and battery voltage values.

But now I'm not sure if such circuit and code will work - because now I power MCU via 3v3 pin..
So - do I need use voltage divider in my current setup?

Actually I checked this circuit and code (divider connected to 3v3 pin)
and it shows some strange data:

batv:3.30
vcc:3.25

vcc < batv? is it possible? I supposed taht values should be equal as I power MCU via Vcc (3v3) pin

Thank you.

d00m178


TomWS

Quote from: d00m178 on April 02, 2019, 08:47:11 AM
any thoughts, please?
My 'thought's are:
1. you are already measuring the processor's VCC voltage with the readVCC() function.  Why are you bothering to measure it again on a separate analog input through a resistor divider?
2. using 'floats' to calculate VCC is a waste of memory and processing time.  The resolution of the ADC is 10 bits and, while averaging over ten samples is going to reduce noise, it's not  going to improve resolution significantly (ie, the 32bit fixed point math in readVCC is more than good enough) and the fact that the readVCC value is used as a scaling factor, you're more likely to introduce errors from this reading than improve the overall reading.
3. why are you using 4 18650 batteries in parallel?  (I really don't want to know but couldn't stop myself from asking.)

d00m178

thank you for your answer TomWS .. look:

>1. you are already measuring the processor's VCC voltage with the readVCC() function.  Why are you bothering to measure it again on a separate analog input through a resistor divider?

I'm really not sure why I didn't think about it..
this way to measuring works ok on my previous devices, BUT - they powered from LiPo batteries from Vin pin.
so I read a lot of info and decided to use resistor divider and it works ok for me.
and when I started to create some new device based on old device but very similar - only power was changed - I just made the old circuit with this resistor divider..

So the final answer - if I want to power MCU via 3v3 pin and want to measure this voltage - I can JUST measure it with the readVCC() and that's all I need?

>2
I will take a look on this. thank you for advice.

>3 why are you using 4 18650 batteries in parallel?  (I really don't want to know but couldn't stop myself from asking.)
short answer - I need a lot of capacity..  in my old device I use 3 LiPo batteries each of 2000mAh so total I have 6000mAh and this enough for my device which works with termo- and laser sensors.
now I want to use LiFePo4 batteries - so I need power MCU via 3v3 pin (w/o LDO) and I decided to connect 4 18650 by 1500Mah to have 6000 mAh total..

Am I wrong?

Thank you in advance