Calculating the largest and smallest of 6 analog values

Hi All :slight_smile:

I have been an arduino convert for quite some time now, and have successfully completed several projects which are now integrated into my daily life.

However this one has stumped me. I'm afraid I don't have any code yet, because this is fairly intrinsic to my aim.
I am creating a voltage monitoring circuit to enable me to safely use LiPo batteries to power an eBike. As you probably know, over-discharge, over-charge, or un-balanced discharge are a very quick way to kill a lithium battery, and possibly anyone close by.

I am using 6-cell LiPos, and want to measure the voltage of every cell, individually. I already have the circuit worked out and the PCB designed and ready to etch.

Part of my code will require the measurement and comparison of each of the 6 values - I am using one analogue pin for each cell.

I need to determine the maximum value of the 6 inputs, and the minimum value of the 6 inputs, in order to determine what the difference is between them, and cut the power if the difference is above a preset level.

I've tried 'max(x, y)' but apparently this is wrong as it can only accept 2 variables. I'm pretty sure it will be a case of 'let me google that for you', but I must be googling the wrong thing!

Many thanks in advance,

Tom.

How are the cells connected? In Series? Or in parallel.
Parallel, if can't isolate, you can't measure.
Series, will have range from 3.7 to 22.2, or maybe 25.2 if all are at 4.2V.
Your analog input only goes to 5V.
We've discussed different ways in the past of presenting each battery's contacts to a floating arduino for instance, so the arduino looks like a multimeter with 2 probes. 6 double pole relays could do that.
Other methods have been suggested also involving more electronics, optoisolators, process for each battery making its own reading and sending to a master over opto's, etc.

First, I hope you’re not leaving the cells connected as you measure them. Each must have - to ground and + to a analog pin, and each must be less then 5 volts. Unless using a voltage divider.
Example:
OK, you need 2 variables, Low set to 100 and High set to 0.
Loop for each battery
if battery > then High, then High = battery.
If battery < Low, then Low = battery.
Do that for all 6 batteries.
The result Low will be the lowest and the result for High will be the highest.

Hi CrossRoads, Thanks for the amazingly quick reply! :astonished:

Cells are in series. I am using a basic stepped voltage divider setup, with a 100k TrimPot for each input above the first cell (which is directly connected).
This will allow me to use a multimeter to roughly pre-set the resistance, and a fresh, charged (4.2V/Cell), balanced cell and the serial port to ‘trim’ each input to the same analogue value - thus each cell (balanced to within 10mV) will appear as the same analogue value on the arduino. From here I can discharge and balance the cells to 3.7V and make sure the trim holds (at least roughly) true.

I am attempting to attach a screengrab of my PCB (I’ve given up on circuit diagrams, sorry!) hopefully it is well enough annotated for you to get the gist.

Here is some code I’ve thrown together - obviously it doesn’t work, but I’m hoping you will be able to see what I’m getting at.

#include <Wire.h>

int flatLED = 4;
int buzz = 5;
int okLED = 6;
int cellConn = 7;
int loadFET = 8;

int cell1 = A3;
int cell2 = A2;
int cell3 = A1;
int cell4 = A0;
int cell5 = A6;
int cell6 = A7;

float Vmax = 0.0;
float Vmin = 0.0;
float Vdiff = 0.0;


void CalcFETstate(){
  
  if (Vdiff >= 0.20){
    digitalWrite(loadFET, LOW);
    digitalWrite(flatLED, HIGH);
    digitalWrite(okLED, LOW);
    digitalWrite(buzz, HIGH);
  }
  else{
    digitalWrite(loadFET, HIGH);
    digitalWrite(flatLED, LOW);
    digitalWrite(okLED, HIGH);
    digitalWrite(buzz, LOW);
  }
}

void CalcVolts(){

float Vlc1 = analogRead(cell1);
float Vlc2 = analogRead(cell2);
float Vlc3 = analogRead(cell3);
float Vlc4 = analogRead(cell4);
float Vlc5 = analogRead(cell5);
float Vlc6 = analogRead(cell6);

float Voc1 = (5.0 / 1024.0) * Vlc1;
float Voc2 = (5.0 / 1024.0) * Vlc2;
float Voc3 = (5.0 / 1024.0) * Vlc3;
float Voc4 = (5.0 / 1024.0) * Vlc4;
float Voc5 = (5.0 / 1024.0) * Vlc5;
float Voc6 = (5.0 / 1024.0) * Vlc6;

Vmax = max(Voc1, Voc2, Voc3, Voc4, Voc5, Voc6);
Vmin = min(Voc1, Voc2, Voc3, Voc4, Voc5, Voc6);

Vdiff = (Vmax - Vmin);

}

void setup(){
Serial.begin(9600);
digitalWrite(cellConn, HIGH);
}

void loop(){
  CalcVolts();
  delay(10);
  CalcFETstate();
}

I think this is a bit of an XY problem.

It’s my understanding that you can’t gauge the amount of remaining power in Lithium chemistry cells by measuring their voltage. They put out contestant voltage until the are almost completely dead, and then the output voltage suddenly plummets.

Lithium cells have integrated power management chips that measure the current drawn from them, calculate the power remanning, and report it to the device and/or charging circuit.

The charger communicates with the power management chip to figure out when the battery is fully charged.

Thus the only way you are going to figure out the charge level of your cells is by communicating with the power management chip in each one.

As to your specific question, though, this is simple. Get all your readings in an array, readings:

#define cellCount 6
float [cellCount] readings;

float max = -10000;
float min =   10000;

for (int index = 0; index < cellCount; index++)
{
  if (readings[index] > max)
    max = readings[index];
  if (readings[index < min)
    min = readings[index];
}

TomLS:
Hi All :slight_smile:

I have been an arduino convert for quite some time now, and have successfully completed several projects which are now integrated into my daily life.

However this one has stumped me. I’m afraid I don’t have any code yet, because this is fairly intrinsic to my aim.
I am creating a voltage monitoring circuit to enable me to safely use LiPo batteries to power an eBike. As you probably know, over-discharge, over-charge, or un-balanced discharge are a very quick way to kill a lithium battery, and possibly anyone close by.

I am using 6-cell LiPos, and want to measure the voltage of every cell, individually. I already have the circuit worked out and the PCB designed and ready to etch.

Part of my code will require the measurement and comparison of each of the 6 values - I am using one analogue pin for each cell.

I need to determine the maximum value of the 6 inputs, and the minimum value of the 6 inputs, in order to determine what the difference is between them, and cut the power if the difference is above a preset level.

I’ve tried ‘max(x, y)’ but apparently this is wrong as it can only accept 2 variables. I’m pretty sure it will be a case of ‘let me google that for you’, but I must be googling the wrong thing!

Many thanks in advance,

Tom.

Steinie - that looks like a sensible approach, if a little wordy ;). However, my code seems to mostly look like that, unfortunately, unless I run out of space I can't generally be bothered to tidy up my code! I will give it a try.
I am well aware of the the dangers of LiPo batteries and am taking the best care to make sure I'm connecting things the right way. It's either that or a nice warm fire!

DuncanC - in a way you are right - but I am not using a commercial battery but an RC battery - no internal controller circuits here!
You are right that LiPo's have a steep initial decline to nominal, and a steep decline from nominal to dead.
However, I am not interested in extracting every last drop of power, and possibly killing a 6s4p (22.2V @ 20Ah) battery pack.
Charging to 4.18V, and monitoring and disconnecting at a drop of the lowest cell to 3.6V, will keep them running for a very long life, and enable me to achieve ~ 80-85% usable power from the pack. on each charge.

I will give your index idea a go too - it seems a little tidier, but I don't think I'm going to strech the 32k of my ProMini too much. I just have to get my head around it first!

Post a schematic. I don't see how the batteries are connected in series there.
The 7805 will be smoking hot having to reduce 24V to 5V.
Unless the batteries are isolated from each other, I don't see how voltage will not rise above Vcc after the first battery.

DuncanC:

I’m having some trouble when plumbing your code into the IDE.
I’m at the first 2 lines and I’m clearly missing an “insert your text here” moment. could I possibly ask you to apply your example to my code posted up the page?

P.S I’ve jsut clicked your ‘XY’ link. I like the explanation at the top :D. In a sense I agree with you, but I am using the same principal on my RC helicopter (albeit only monitoring the total (14.8v) voltage via divider, rather than individual cells, and each of my 6 batteries has over 200 cycles on it with no discernible loss in capacity. This method may not be idea, but it’s working for me!

My reasoning behind individual monitoring in this scenario is that my heli can pull down its battery in 6 minutes - minimal time for un-balancing to occur.
This scenario involves a long-term discharge, which may me less stressful on the batteries, but allows more time for an out of balance situation to occur. Couple with that my heli is always far away from me - if it catches fire I’m ok. In this situation, I have 20x the Wh, and it will be uncomfortably close to my ‘gentlemans area’. Crispy-fried is not its preferred state =(.

CrossRoads: I have included a basic schematic of the series nature of the battery. It’s basic! The 7805 is fine with a small heatsink for the 80ma** it has to produce - that’s the bit I’ve tested :). I may exchange it for a switchmode when I’m out of proto - for the sake of a PCB schema; the pins and spacing are adequate, the nomenclature is so I don’t forget what all the pads mean!

** This is the maximum - and it will sink ~1.5W - obviously a bit warm! Under normal circumstances, apart from the momentary peaks of charging the transistor gates, this will be more like 30mA (~0.6W) while the battery is ‘OK’. When it’s flat and starts winging at me, it will get hotter, but the idea is that I will turn it off then!!

Connect one leg of your pots to Gnd and take the wiper to the analog input.
Otherwise what will happens is they will only act as current limiters, and the input protection diodes will clamp the >5V signals to 5V, and your readings will be 1023 all the time.

If your problem is only a programming problem, finding the largest of six values, then the max( ) function ( or macro ) defined on the arduino probably wont work as you have used it, because it takes only 2 arguments. But, it is not very hard.

byte analogpins[] = { A0,A1,A2,A3,A4,A5 };
float volts[6] ;

for ( int i=0 ; i<6 ; i++ )   volts[i] = 5.0*analogRead( analogpins[i] )/1023.0 ;

float largest_v=0.0 ;
float smallest_v=0.0 ;

for ( int i=0 ; i<6 ; i++ )
{
    if ( i==0 || volts[i] > largest_v )  largest_v = volts[i] ;
   if ( i==0 || volts[i] < smallest_v ) smallest_v = volts[i] ;
}

That's not the problem - it is monitoring 6 sources, looking for high/low on each to detect overcharging, overdischarging.