I am also using a 12volt LiFePO4 battery for my purposes. I have plenty of step down buck converters laying around that I am already using to step down the 12 volts to provide 5vdc to arduino nano, and 12volts DC to power motor controller and a peristaltic pump. Is it possible to use the buck converter and provide voltage to pin A0 instead of voltage divider? im worried I'm running out of space to add additional circuits.
Remember to ADD all the error factors of EACH device to get the error of the final system.
The ADS1115 has 32768 steps.
And doesn't need an external reference.
PGA1 (4.096volt) has the best resolution.
Leo..
If you use a zener to drop the 12V to 3V, you could power the Nano with the 3V. Then you could set Vcc as the ADC reference voltage, and measure the voltage of the internal 1.1V source. So instead of using the 1.1V as the reference to measure some other voltage, you measure the 1.1V with reference to Vcc. The lower your Vcc, the higher the reading. No external parts needed other than the zener.
I think the 1.1V varies from chip to chip, so you would have to calibrate. And I don't know how temperature stable it is. Could you perhaps accomplish the same thing more accurately by just accumulating the time under load?
Topic split from another topic. Please do not add your own questions to the end of other people's topics.
Could you take a few moments to Learn How To Use The Forum
It will help you get the best out of the forum in the future.
Thank you.
For reference, I am attempting to produce an output voltage on the serial monitor that reads the voltage and the percent of the charge of the battery.
I'm trying to implement thresholds which would send alerts at 75%, 50%, and 25% but the percent's in my sketch don't seem to coincide with the values found on this LiFePO4 battery life chart. For example, 13.2 VDC on the serial monitor is 99%, 12.06 VDC is 90%, and 6.6 VDC is 50%, but in reality the battery would have been dead for a while at that voltage. I am using an Arduino NANO and this is the battery I am using : https://www.amazon.com/ECI-Power-Rechargeable-2000-5000-Applications/dp/B0973L9XMY/ref=sr_1_3?crid=1PEQU8UVPT8BG&keywords=lifepo4%2B5%2Bah%2Beci&qid=1667889614&sprefix=lifepo4%2B5%2Bah%2Beci%2Caps%2C96&sr=8-3&ufe=app_do%3Aamzn1.fos.006c50ae-5d4c-4777-9bc0-4513d670b6bc&th=1
I am Using a voltage divider for this, R1 is 100K ohm and R2 is 60K ohm. Please advise
int readPin = A0;
float Voltage = 0;
int readVal;
int delayTime = 1000;
void setup() {
pinMode(readPin, INPUT);
Serial.begin(9600);
}
void loop() {
readVal = analogRead(readPin);
Voltage = (13.3 / 1023.) * readVal;
int volts = (readVal / 1023.) * 100;
Serial.print(Voltage);
Serial.println (" VDC");
delay(delayTime);
if (volts == 100) {
Serial.print (volts);
Serial.println (" %");
delay(delayTime);
}
else if (volts < 10) {
Serial.print (volts);
Serial.println (" %");
delay(delayTime);
}
else {
Serial.print (volts);
Serial.println (" %");
delay(delayTime);
}
}
The divider lowers voltage to "R2 / (R1 + R2) = 60/160" of the battery voltage.
When you want to display original voltage, you first do this
voltage = analogRead(A0) * 5.0 / 1024; // to get voltage at the Arduino pin
then multiply with the inverse of the voltage divider (16/6 or 2.6666) to return to battery voltage.
100k:60k results in more than 5volt with 13.6 input. Use 100k:56k.
As said, (genuine) ADS1115 could give you much better results.
Leo..
Using a divider is fine but I would consider a few things. First make sure your choice of divider will never allow and input voltage to your A/D exceeding allowable limits. You mention using 100K and 60K which I would avoid doing. My reasoning is having 60K or really anything exceeding 10K output impedance driving you Analog in simply is not a good idea. The reasoning here is easily explained here:
THE INPUT IMPEDANCE OF AN ARDUINO ADC PIN
If you want accurate measurements I would keep your source impedance below 10K and rearrange your divider network. Next if you want good accuracy I would just use an ADS1115 on the front end. I saw earlier mention of doing that in Post #3 by Wawa.
Ron
Thank you Wawa and Ron_Blair, I've ordered an ADS1115 from adafruit and changed the resistor values. I'm still having issues wrapping my mind around the percentage of charge to the voltage of the battery. Should I be using a different multiplier to account for the LiFePO4 discharge rate or would I need to write if else code so that each voltage range coincides with specific percentages like if vBat < 13.4 && > 13.3, percentage = " 100%") else vBat <13.3 && > 13.2, percentage = " 75%", etc?
here is updated code, also attached the basic schematic of my circuit, I don't have my sketch book at the moment
#define readPin A0
const float mvpc = 4.9 ; //measured voltage of arduino through voltmeter
float counts = 0; //battery volts in millivolts
float mv = 0;
float multiplier = 2.714;
float output = 0;
int charge = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
counts = analogRead(readPin);
Serial.println(counts);
mv = counts * mvpc;
Serial.println(mv);
output = (mv * multiplier)/1000 ;
Serial.print(output);
Serial.println("V");
charge = (counts/1024)*100;
Serial.print(charge);
Serial.println("%");
delay(1000);
}
The relation between voltage and charge% is not linear so
float demoArray[2][4] = {// incomplete
{13.4, 13.3, 13.2, 13.1},
{100, 99, 90, 70}
};
int perCent;
void setup() {
float volTage = 13.3;//<<<<<<<<<<<<<<<<<<<<<<
Serial.begin(115200);
perCent = 0;
for (int x = 0; x < 4; x++) {
if (volTage >= demoArray[0][x]) {
perCent = demoArray[1][x];
break;
}
}
Serial.println();
Serial.print(perCent);
}
void loop()
{}
Do you really have 3 batteries in series ?
Isn't it easier to use multimap().
Leo..
No just 1, the website I used to build the schematic didnt have a 12 volt, I've attached a more accurate figure of the basic circuit
A pot is not as stable as two metalfilm resistors.
Remove it if you want at least a one decimal place readout.
Not a problem to use high values if... you also add a 100n capacitor from A0 to ground.
A capacitor also lowers input impedance (to zero ohm).
I suppose you want a stable readout and at least two decimal places.
Try averaging multiple A/D readings (smoothing code).
Leo..
Yes and that would cover that.
Sitting here looking at the cap in the drawing and looked right past it. Poof and it was gone. Thank you for pointing that out.
As to using a voltage divider with the ADS1115 while I agree that yes, thin metal film resistors are a great way to go all things considered I would just put a decent 15 turn 10K inexpensive pot across the battery. Figure the current draw of a 10K pot at a fully charged battery would be 13.6 volts / 10000 ohms = 1.3 mA. An inexpensive Spectrol or actually now Vishay 10K 15 turn pot has a temperature coefficient resistance of about 100 PPM / Degree C between -55C to 145C. In a stable environment I would just use a 10K 15 turn pot. We are only measuring battery voltage to 0.1 volt resolution.
Using only a pot like one of these adjusted for a 3:1 ratio applying 10.000 volts using an ADS1115 with a GAIN_TWOTHIRDS); +/- 6.144V 1 bit = 0.1875mV I am reading 10.00 volts as stable as I could need for an application like this. Using a 3:1 divider would allow for an input of 18.4 volts. Well enough above the 100% 14.6 volt charging voltage and the 100% 13.6 volt resting voltage . So yes, while I agree that metal film precision resistors with a low TCR is going to yield much better precision and accuracy how precise do things need to be?
Ron
Easier and much better. I did not know that library. Thank you
Understood, I was using it to control the voltage to see the response on the serial monitor as it was all I had available but was able to get my hands on a power supply. I was able to adapt code from this post : 12V battery meter with Arduino MEGA - #19 by septillion and produced the following sketch which "works" though the voltage displayed on the serial monitor is not the same as displayed on the power supply.
for example, when power supply voltage is 10.51, serial monitor displays 10505 mV corresponding with 0%, any lower than 10505 mV and the serial monitor reads 62%. same with the max voltage, when I set the power supply to 13.44, serial monitor reads 13426 and prints it as 100%.
Any feedback and suggestions would be appreciated
#define readPin A0
const unsigned long BatR1R2[] = {5000, 2930}; // resistor values
const unsigned long RefVolt = 4940; // voltage divider output at A0
const unsigned long BatRsVal = 1024;
const unsigned long Ratio = ((BatR1R2[0] + BatR1R2 [1]) * RefVolt) / BatR1R2[1];
const unsigned long BatVoltMax = 13400; // fully charged LifePO4 battery
const unsigned long BatVoltMin = 10500; //approximate fully discharged voltage
const unsigned int NrSamples = 1000; // not sure what this does
float counts = 0;
void setup()
{
Serial.begin( 9600);
}
void loop()
{
delay(5);
unsigned int adcValue = averageRead( readPin);
analogReference(DEFAULT);
unsigned int BatVoltage = adcValue * Ratio / BatRsVal;
Serial.print("Batery voltage [mV]: ");
Serial.println(BatVoltage);
byte percent = 100 * (BatVoltage - BatVoltMin) / (BatVoltMax - BatVoltMin);
Serial.print("Battery level [%]: ");
Serial.println(percent);
delay(5000);
}
// --------------------------------------------
// averageRead()
// --------------------------------------------
// By using 'float' numbers for the average,
// it is possible to get more bits than
// the 10 or 12 bits that is returned by analogRead().
//
// The total of the samples is not done with float, because
// then bits could get lost.
// Only at the end, the floating point calculation is done.
//
// When the voltage is calculated, use 1024, not 1023.
// The "half a bit" is explained here: https://www.gammon.com.au/adc
//const int nSamples = 1000; // Usually from 5 to 10000
unsigned int averageRead( byte pin)
{
unsigned long total = 0;
for ( int i = 0; i < NrSamples; i++)
{
total += analogRead( pin);
}
total += NrSamples / 2; // add half a bit
return ( total / NrSamples);
}
I'm not too sure about the precision, the batteries will be used on the second iteration of autosampler prototypes which are designed to be placed in the elements, so I am a bit concerned on if I should be accounting for weather given that the temperature these devices will be between 0 and -9 degrees Celsius if we have a mild winter
Well if going outdoors I would look carefully at the temperature coefficients of whatever resistors you use for a divider, I would then consider a pair of 1K in series and a 1K making for a 3:1 divider. With an ADS1115 at default gain that still gives you about 18 volts. That gives you 1 bit = 0.185 mV.
Thank you kindly for the reminder of winter on the horizon as I sit here in NE Ohio USA.
Maybe come January I'll go visit and hang with friends in Daytona, Florida.
Ron
That throws away almost 1/4 of the resolution.
Because you shouldn't put more than VCC on the inputs of an ADS1115.
See post#3.
Leo..
Then go with the higher gain and change the divider ratio. How much resolution does the thread starter really need?
Thanks
Ron


