Is this any good ? Low voltage cutoff

I've finally completed the setup, using some 75k, 16.5k and 33k resistors.
The multimeter displays the (almost) correct voltages (4.19v, 4.17v and 4.20v). That is related to the resistances not having the exact right impedance. But that is not a problem, it can be corrected in the program.

However, the arduino diplays the voltages with a huge error ! I've attached a screenshot, the arduino displays an average of 3.96v.

I'm using the standard reference. It is not related to the high impedances of the resistors slowing the recharge of the sampling capacitor inside the arduino, because the reading of cell1 (measured without voltage divider) is also incorrect.
I doubt it's related to the usb supply, cause it gives the exact same values when powered via 12v

Here is the (way too long & messy) code:

// the setup function runs once when you press reset or power the board
void setup() {
 Serial.begin(9600);
 pinMode(4, OUTPUT);
 pinMode(A0, INPUT);
 pinMode(A2, INPUT);
 pinMode(A5, INPUT); 
 digitalWrite(4, LOW);
}

// the loop function runs over and over again forever
void loop() 
{
 
 delay(4000);



 //Cell 1


 
 int voltage1 = analogRead(A0);
 float Vcell01 = voltage1 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage11 = analogRead(A0);
 float Vcell01 = voltage11 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage12 = analogRead(A0);
 float Vcell01 = voltage12 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage13 = analogRead(A0);
 float Vcell01 = voltage13 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage14 = analogRead(A0);
 float Vcell01 = voltage14 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)digitalWrite(4, HIGH); }}}}



 //Cell 2 


 int voltage12 = analogRead(A2);
 float Vcell02 = ((voltage12 * (5.0 / 1023.0))*2)-Vcell01;
 Serial.println(Vcell02);
 if (Vcell02<3.7)
 {delay(2000);
 int voltage12 = analogRead(A2);
 float Vcell02 = ((voltage12 * (5.0 / 1023.0))*2)-Vcell01;
 Serial.println(Vcell02);
 if (Vcell02<3.7)
 {delay(2000);
 int voltage12 = analogRead(A2);
 float Vcell02 = ((voltage12 * (5.0 / 1023.0))*2)-Vcell01;
 Serial.println(Vcell02);
 if (Vcell02<3.7)
 {delay(2000);
 int voltage12 = analogRead(A2);
 float Vcell02 = ((voltage12 * (5.0 / 1023.0))*2)-Vcell01;
 Serial.println(Vcell02);
 if (Vcell02<3.7)
 {delay(2000);
 int voltage12 = analogRead(A2);
 float Vcell02 = ((voltage12 * (5.0 / 1023.0))*2)-Vcell01;
 Serial.println(Vcell02);
 if (Vcell02<3.7)digitalWrite(4, HIGH); }}}}


 //Cell 3

 
 int voltage123 = analogRead(A5);
 float Vcell03 = ((voltage123 * (5.0 / 1023.0))*3)- (Vcell01 + Vcell02);
 Serial.println(Vcell03);
 if (Vcell03<3.7)
 {delay(2000);
 int voltage31 = analogRead(A5);
 float Vcell03 = ((voltage123 * (5.0 / 1023.0))*3)- (Vcell01 + Vcell02);
 Serial.println(Vcell03);
 if (Vcell03<3.7)
 {delay(2000);
 int voltage32 = analogRead(A5);
 float Vcell03 = ((voltage123 * (5.0 / 1023.0))*3)- (Vcell01 + Vcell02);
 Serial.println(Vcell03);
 if (Vcell03<3.7)
 {delay(2000);
 int voltage33 = analogRead(A5);
 float Vcell03 = ((voltage123 * (5.0 / 1023.0))*3)- (Vcell01 + Vcell02);
 Serial.println(Vcell03);
 if (Vcell03<3.7)
 {delay(2000);
 int voltage34 = analogRead(A5);
 float Vcell03 = ((voltage123 * (5.0 / 1023.0))*3)- (Vcell01 + Vcell02);
 Serial.println(Vcell03);
 if (Vcell03<3.7)digitalWrite(4, HIGH); }}}}
}

[/code]

Hi,
Can you please post a copy of your circuit for the tests you are now doing, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you add Serial.println("Cell1"); and Serial.println("Cell2"); etc in your code so we know what figures we are looking at.
As an example below for Cell1. the same in your cell2 and cell3 sections.

//Cell 1

 Serial.print("Cell1);
 int voltage1 = analogRead(A0);
 float Vcell01 = voltage1 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage11 = analogRead(A0);
 float Vcell01 = voltage11 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage12 = analogRead(A0);
 float Vcell01 = voltage12 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage13 = analogRead(A0);
 float Vcell01 = voltage13 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)
 {delay(2000);
 int voltage14 = analogRead(A0);
 float Vcell01 = voltage14 * (5.0 / 1023.0);
 Serial.println(Vcell01);
 if (Vcell01<3.7)digitalWrite(4, HIGH); }}}}

Thanks.. Tom.. :slight_smile:

Hi Tom, thank you for the prompt reply!
Here are some photos:
Google Photos
Google Photos

I've edited the script like you said, and also added Serial.println(voltage1); etc after int voltage1 = analogRead(A0); idk if that helps.

The circuit should work fine because the multimeter reads the right voltages between the ground pin and A0, A2 and A5

the new serial montitor screenshot is attached

voltages2.png

Hi,
OP, monitor display
917243cbd3e94d033f6a27e32e0d1d5c805d568b.png
Pictures don't work.
Please attach them..

Tom... :slight_smile:

Hi,
This equation is okay possibly for Vcell01

 float Vcell01 = voltage1 * (5.0 / 1023.0);

If your max cell A0 input voltage calculated is 5.0V

However this equatation is not for Vcell02

float Vcell02 = ((voltage12 * (5.0 / 1023.0))*2)-Vcell01;

Your 5.0 is not your Max input, it is what ever you calculated your max for your potential divider for the second the third cell junction.
Likewise.

 float Vcell03 = ((voltage123 * (5.0 / 1023.0))*3)- (Vcell01 + Vcell02);

The 5.0 is not your Max input, it is what ever you calculated your max for your potential divider for the third cell junction.

Can you show your calculations for your potential dividers please.
As it looks like you can take pictures, please draw a circuit diagram by hand and post (attach) a picture of it .

Thankyou.... Tom... :slight_smile:
(Just having first cup of java for the morning.. ahhhhhh.. :slight_smile: )

float Vcell01 = voltage1 * (5.0 / 1023.0);

A lower resulting voltage means a higher than 5volt Aref.

Try
float Vcell01 = voltage1 * (5.3 / 1024.0);
And see what you get.

I think default Aref should't be used to measure voltages.
Default Aref varies too much with the way you supply the Arduino.

Drop battery voltage to 1volt, and measure with the ~1.1volt bandgap Aref enabled.
Leo..

thank you for the replies! I'll look into it tomorrow, its getting late here :wink:
Sorry if the links to the pictures were faulty.
Here they are again, this time as attachments.

I don't get it, how can it be that this

float Vcell01 = voltage1 * (5.0 / 1023.0);

is right and this

float Vcell02 = ((voltage12 * (5.0 / 1023.0))*2)-Vcell01;

is wrong, as they both give almost the same result?

Let's assume the second and third equations are wrong, then why doesn't the first give the correct result ?

I have not calculated the potential dividers, 2 of same R = voltage divided by half, one of xR and another of x/2 R and your voltage is divided by 3.
It works fine using a voltmeter so that must be right.

It's just the arduino who has an error of ~0.20v, which is huge for a lipo low voltage cutoff.

@wawa that does indeed work, but like you said if Aref ever decreases it will cause huge problems to the lipo.
Unfortunately I can't drop the voltage to 1v, it starts self-destructing below 3v

Thanks wawa !!!!
Found it, I read somewhere arduino automatically switches to the external supply when connected to usb and an external source. So I connected it to an external source and usb, because the usb voltage was 5.26v and the voltage on the 5v pin was exactly 5v when connected to the external source.
But mine does not switch to external !! so when I plugged the arduino in to the pc, the readings were incorrect.

It's all fine now and it's very precise !!

I would still be nice to make it switch to external while connected to usb to verify the measurements.

hitachi3d7:
Found it, I read somewhere arduino automatically switches to the external supply when connected to usb and an external source.

Yes. With a minimum of 6.6volt on V-in, or a minimum of 7.3volt on the DC socket, external supply takes over.
Unless USB supply is a diode drop higher than output of the onboard 5volt regulator.

hitachi3d7:
Unfortunately I can't drop the voltage to 1v, it starts self-destructing below 3v

?
Maybe you understood that wrong.
Use a voltage divider that drops 4.2volt to ~1volt. And 8.4volt to 1volt. And 12.6 to 1volt.
Try with e.g. 33k from first battery to analogue pin, and 10k from that analogue pin to ground.
Add this to void setup()

analogReference(INTERNAL); // use the internal 1.1volt bandgap reference

And change the maths line to

float Vcell01 = voltage1 * (1.075 / 1024.0); // change 1.075 slightly to calibrate.

That will give you a supply independent LiPo voltage, and a five times higher resolution.
Leo..

Graynomad:
That is some seriously badly written code, but not bad for your first attempt.

I disagree, that loop() function is atrocious. There should never, EVER be four closing curly braces in a row on a single line. There is no indenting at all to speak of beyond the first level.

hitachi3d7:
Holy ****, thanks tom !!! I just supposed a lipo had a chip in it that sended the voltage of each cell through a balancing cable. My bad. I'll update the code asap.

Do not assume.

Do not ever assume, especially with a dangerous component like a Li-Po battery. Samsung just recalled their new Note 7 because they messed up the battery's production process and several dozen of them caught fire while being charged overnight. I believe lithium batteries are the most delicate chemistry out there right now (at least in mass production), far more delicate than lead acid or nickle metal hydride. Do your batteries have the protection circuit built in to guard against short circuit, over voltage, or over discharging?

Don't assume, find out.

Graynomad:
And add voltage dividers.

I think some differential amplifiers will be better for this, one for each battery. You can make maximum use of the ADC's range for all of the batteries, and you don't need to do any funky arithmetic for the two on "top".

I've finally completed the setup, using some 75k, 16.5k and 33k resistors.

The input to the ADC should have an impedance of less than 10k. These resistors are cutting just a bit too close to that, and should probably all be about 5x lower value.

Jiggy-Ninja:
The input to the ADC should have an impedance of less than 10k. These resistors are cutting just a bit too close to that, and should probably all be about 5x lower value.

There are several tricks to fix that problem.
Reading the input twice, and using the last reading is one of them.
A 100n cap from analogue input to ground, to give the A/D a solid voltage to sample from is another one.
This post stretches that by using a 2 * 10Megohm divider.
http://jeelabs.org/2013/05/16/measuring-the-battery-without-draining-it/
Leo..

Maybe this could work.
Zero battery drain when not measuring.
One mosfet gate "high" at the time.
Then measure A0 with 1.1volt Aref enabled.
Leo..

I disagree, that loop() function is atrocious. There should never, EVER be four closing curly braces in a row on a single line. There is no indenting at all to speak of beyond the first level.

I'm curious why, as I'm still learning, It should be noted however that it will never actually enter those loops under normal circumstances.

Jiggy-Ninja:
Do not assume.

Do not ever assume, especially with a dangerous component like a Li-Po battery. Samsung just recalled their new Note 7 because they messed up the battery's production process and several dozen of them caught fire while being charged overnight. I believe lithium batteries are the most delicate chemistry out there right now (at least in mass production), far more delicate than lead acid or nickle metal hydride. Do your batteries have the protection circuit built in to guard against short circuit, over voltage, or over discharging?

Don't assume, find out.

I had just finished the code and ordered the lipo, of course I would've measured it before connecting it to the arduino, I'm not that dumb.

Why would I code a LVC if the battery has a protection circuit build in ?

I think some differential amplifiers will be better for this, one for each battery. You can make maximum use of the ADC's range for all of the batteries, and you don't need to do any funky arithmetic for the two on "top".The input to the ADC should have an impedance of less than 10k. These resistors are cutting just a bit too close to that, and should probably all be about 5x lower value

It works fine, and it has a huge precision, so I'll stick to this I think.

Wawa:
Maybe this could work.
Zero battery drain when not measuring.
One mosfet gate "high" at the time.
Then measure A0 with 1.1volt Aref enabled.
Leo..

Interresting, would have done this if I knew this before, now it's all finished using a 8 pin relay that will go open if the arduino detects low voltage, it does drain the battery while in use, but if it's turned off, it shouldn't.

In response to your other post, I am powering the arduino through a 12v supply, but it does not switch from usb to ext.

For those interested, here is the final working code, it might be long and messy, but it is working:

void setup() {
  Serial.begin(9600);
  pinMode(4, OUTPUT);
  pinMode(A0, INPUT);
  pinMode(A2, INPUT);
  pinMode(A5, INPUT); 
  digitalWrite(4, LOW);
  delay(2000);
}

void loop() 
{
  
  delay(500);



  //Cell 1

Serial.println("Cell1");
  int voltage1 = analogRead(A0);
  float Vcell01 = voltage1 * (5.26 / 1023.0);
  Serial.println(Vcell01);
  if (Vcell01<3.7)
  {delay(2000);
  int voltage11 = analogRead(A0);
  float Vcell01 = voltage11 * (5.26 / 1023.0);
  Serial.println(Vcell01);
  if (Vcell01<3.7)
  {delay(2000);
  int voltage12 = analogRead(A0);
  float Vcell01 = voltage12 * (5.26 / 1023.0);
  Serial.println(Vcell01);
  if (Vcell01<3.7)
  {delay(2000);
  int voltage13 = analogRead(A0);
  float Vcell01 = voltage13 * (5.26 / 1023.0);
  Serial.println(Vcell01);
  if (Vcell01<3.7)
  {delay(2000);
  int voltage14 = analogRead(A0);
  float Vcell01 = voltage14 * (5.26 / 1023.0);
  Serial.println(Vcell01);
  if (Vcell01<3.7)digitalWrite(4, HIGH); }}}}



  //Cell 2 

Serial.println("Cell2");
  int voltage12 = analogRead(A2);
  float Vcell02 = ((voltage12 * (5.26 / 1023.0))*2)-Vcell01;
  Serial.println(Vcell02);
  if (Vcell02<3.7)
  {delay(2000);
  int voltage12 = analogRead(A2);
  float Vcell02 = ((voltage12 * (5.26 / 1023.0))*2)-Vcell01;
  Serial.println(Vcell02);
  if (Vcell02<3.7)
  {delay(2000);
  int voltage12 = analogRead(A2);
  float Vcell02 = ((voltage12 * (5.26 / 1023.0))*2)-Vcell01;
  Serial.println(Vcell02);
  if (Vcell02<3.7)
  {delay(2000);
  int voltage12 = analogRead(A2);
  float Vcell02 = ((voltage12 * (5.26 / 1023.0))*2)-Vcell01;
  Serial.println(Vcell02);
  if (Vcell02<3.7)
  {delay(2000);
  int voltage12 = analogRead(A2);
  float Vcell02 = ((voltage12 * (5.26 / 1023.0))*2)-Vcell01;
  Serial.println(Vcell02);
  if (Vcell02<3.7)digitalWrite(4, HIGH); }}}}


  //Cell 3

  Serial.println("Cell3");
  int voltage123 = analogRead(A5);
  float Vcell03 = ((voltage123 * (5.26 / 1023.0))*3)- (Vcell01 + Vcell02);
  Serial.println(Vcell03);
  if (Vcell03<3.7)
  {delay(2000);
  int voltage31 = analogRead(A5);
  float Vcell03 = ((voltage123 * (5.26 / 1023.0))*3)- (Vcell01 + Vcell02);
  Serial.println(Vcell03);
  if (Vcell03<3.7)
  {delay(2000);
  int voltage32 = analogRead(A5);
  float Vcell03 = ((voltage123 * (5.26 / 1023.0))*3)- (Vcell01 + Vcell02);
  Serial.println(Vcell03);
  if (Vcell03<3.7)
  {delay(2000);
  int voltage33 = analogRead(A5);
  float Vcell03 = ((voltage123 * (5.26 / 1023.0))*3)- (Vcell01 + Vcell02);
  Serial.println(Vcell03);
  if (Vcell03<3.7)
  {delay(2000);
  int voltage34 = analogRead(A5);
  float Vcell03 = ((voltage123 * (5.26 / 1023.0))*3)- (Vcell01 + Vcell02);
  Serial.println(Vcell03);
  if (Vcell03<3.7)digitalWrite(4, HIGH); }}}}

  //Power off button
  float A3 = A33 * (5.26 / 1023.0);
  Serial.println(A3);
  if (A3>4.5) digitalWrite(4, HIGH);
  //just for testing
  bitRead(PORTD, 4);
  Serial.println(PORTD);
}