Notifications
Clear all

Battery Charger array of objects

13 Posts
2 Users
0 Likes
2,145 Views
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

Hi,

I hope someone can help me, I'm at an impasse on my Battery Charger project. I'm using an arduino Mega.

IMG 0469

I've written a BatteryHolder 'class', for each of four slots of my charger holding an individual AA, AA or Lithium battery. takes the following variables to control the charging independently; Requiring a constructor something like this;

BatteryHolder(int slot, int PWM, int relay, uint8_t highside, uint8_t lowside,
uint8_t temperature, int batteryType, float capacity, float chargeDivider, uint8_t address);

the variables are:

slot, batteryType, capacity, chargeDivider (numbers, both int & float)).
PWM, relay(two digital outputs on arduino)
highside, lowside, temperature(analog inputs on arduino)
address(an itc address for measuring current.

 

BatteryHolder::BatteryHolder(int slot, int PWM, int relay, uint8_t highside, uint8_t lowside,
uint8_t temperature, int batteryType, float capacity, float chargeDivider, uint8_t address)
{
_slot = slot;
_PWM = PWM;
_relay = relay;
_highside = highside;
_lowside = lowside;
_temperature = temperature;
_batteryType = batteryType;
_capacity = capacity;
_chargeDivider = chargeDivider;
_address = address;
long startTime = chargeTime + millis(); //note the start of charging
pinMode(PWM, OUTPUT); //Sets the gate voltage for MOSFET
pinMode(relay, OUTPUT);
pinMode(highside, INPUT); //Low side voltage of battery
pinMode(lowside, INPUT); //High side voltage of battery
pinMode(temperature, INPUT); //TEMPERATURE of battery

Adafruit_INA219 slotCurrent(_address);
if (! slotCurrent.begin())
{
Serial.println("Failed to find first INA219 chip");
while (1) { delay(10); }
}

 

I then want to initiate the class by something like this:

BatteryHolder Slot1 (1, 4, 5, A0, A1, A2, 3, 2300.0, 5.0, 0X40);

Once constructed I don't want to replicate the same instructions for EACH slot, requiring four times the code to do the same thing to EACH class member.

What I want to do, is something like this

BatteryHolder Slot[0] (1, 4, 5, A0, A1, A2, 3, 2300.0, 5.0, 0X40);
BatteryHolder Slot[1] (2, 6, 7, A3, A4, A5, 3, 2300.0, 5.0, 0X41);
BatteryHolder Slot[2] (3, 8, 9, A6, A7, A8, 3, 2300.0, 5.0, 0X42);
BatteryHolder Slot[3] (4, 10, 11, A9, A10, A11, 3, 2300.0, 5.0, 0X43);

This would allow me to do this, taking advantage of using for loops & case statements;

for(int i;  i<4;  i++)
{
   Slot[i].BatteryUpdate; //this is what does all the charging
}

 

This is driving me bonkers. I must be doing something wrong, I know that class 'objects' must be able to be contained within an array.

 

Does anyone know what I'm doing wrong?

 

Thanx, Christine


   
Quote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

   
ReplyQuote
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

   
ReplyQuote
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

The first iteration you provided led to these errors;

IRF540_Test_take_2:48:21: error: no matching function for call to 'BatteryHolder::BatteryHolder()'
BatteryHolder Slot[4];
^
In file included from /Users/christine/Documents/Arduino/IRF540_Test_take_2/IRF540_Test_take_2.ino:41:0:
sketch/BatteryHolder.h:42:5: note: candidate: BatteryHolder::BatteryHolder(int, int, int, uint8_t, uint8_t, uint8_t, int, float, float, uint8_t)
BatteryHolder (int slot, int PWM, int relay, uint8_t highside, uint8_t lowside,
^~~~~~~~~~~~~
sketch/BatteryHolder.h:42:5: note: candidate expects 10 arguments, 0 provided
sketch/BatteryHolder.h:39:7: note: candidate: constexpr BatteryHolder::BatteryHolder(const BatteryHolder&)
class BatteryHolder
^~~~~~~~~~~~~
sketch/BatteryHolder.h:39:7: note: candidate expects 1 argument, 0 provided
IRF540_Test_take_2:49:1: error: 'Slot' does not name a type
Slot[0] = BatteryHolder(1, 4, 5, A0, A1, A2, 3, 2300.0, 5.0, 0X40);
^~~~
IRF540_Test_take_2:50:1: error: 'Slot' does not name a type
Slot[1] = BatteryHolder(2, 6, 7, A3, A4, A5, 3, 2300.0, 5.0, 0X41);
^~~~
IRF540_Test_take_2:51:1: error: 'Slot' does not name a type
Slot[2] = BatteryHolder(3, 8, 9, A6, A7, A8, 3, 2300.0, 5.0, 0X42);
^~~~
IRF540_Test_take_2:52:1: error: 'Slot' does not name a type
Slot[3] = BatteryHolder(4, 10, 11, A9, A10, A11, 3, 2300.0, 5.0, 0X43);
^~~~
exit status 1
no matching function for call to 'BatteryHolder::BatteryHolder()'

The second, resulted in the following;

IT WORKS!!

I couldn't believe it, as my slot[i].doesExist() returned that the class had been created!

Any idea why the first didn't work, was it reliant on my having a second 'default constructor'?

In any event, thank you, I hope I can now get this thing to work, & finally be able to get this 'weekend task' working. My code does charge NiMH  Lithium batteries, I just have to get that done with my newly created class!

You & @Ruplicator have both been fabulous 😍 !

Thnx,

Christine

 


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@christine86

Posted by: @christine86

The first iteration you provided led to these errors;

IRF540_Test_take_2:48:21: error: no matching function for call to 'BatteryHolder::BatteryHolder()'
BatteryHolder Slot[4];
^
In file included from /Users/christine/Documents/Arduino/IRF540_Test_take_2/IRF540_Test_take_2.ino:41:0:

[SNIP]

Posted by: @christine86

IT WORKS!!

Any idea why the first didn't work, was it reliant on my having a second 'default constructor'?

Of course I do 😉

In my previous post, I mentioned the following:

Posted by: @frogandtoad

and you may need a default constructor, if so, you should get a warning message stating something to that nature

...and the message was:

Posted by: @christine86

IRF540_Test_take_2:48:21: error: no matching function for call to 'BatteryHolder::BatteryHolder()'

...you see, the moment you declare your own constructor, the implementation no longer provides a default one for you, so an object(s) such as:

BatteryHolder Slot; // Requires default constructor
BatteryHolder Slot[4]; // 4 objects that require the default constructor

...will not compile.

So, for your class, just declare a default constructor as well: "BatteryHolder();", with the body in the .cpp implementation file like your custom constructor, and it should also work.

Posted by: @christine86

In any event, thank you, I hope I can now get this thing to work, & finally be able to get this 'weekend task' working. My code does charge NiMH  Lithium batteries, I just have to get that done with my newly created class!

You & @Ruplicator have both been fabulous  !

Glad to help, and happy you got it working 🙂

Cheers!


   
ReplyQuote
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

URGH, I perhaps spoke too soon?

 

I'm using a INA219 current sensor, to track the current applied to the rechargeable battery, & have four of them, each of which I've soldered tracks to give all four possible units.

As such, as I called every BatteryHolder  constructor 'object' I also called the Adafruit class like this;

Adafruit_INA219 slotCurrent(_address);
if (! slotCurrent.begin())
{
Serial.println("Failed to find first INA219 chip");
while (1) { delay(10); }
}

I had hoped that would mean for every call to BatteryHolder::BatteryUpdate, would mean I was referring to those distinct objects, so I would be able to use something like this;

float currentAverage = 0; //reset average tally
for (int i =0; i<10; i++)
{
currentAverage +=slotCurrent.getCurrent_mA();//get another reading
delay(50); //allow MOSFET to settle between readings
}

I thought that having initialized the objects within my constructor, I could thereafter just refer to slotCurrent.whatever(), the class would ensure the right getCurrent() but alas, I get this error;

 

BatteryHolder.cpp:169:25: error: 'slotCurrent' was not declared in this scope
currentAverage +=slotCurrent.getCurrent_mA();//get another reading
^~~~~~~~~~~

 

Could I perhaps initialize the Adafruit sensor by returning a Adafruit_INA218 'object' or a ->'pointer' so that the other calls to BatteryHolder subroutines, would know exactly WHICH sensor is being used at that time?

Or am I just getting myself confused? WHY can't I upload a '.cpp' file to here, now I'm confused bout THAT too.? I'll just attach it to the end here. This must be the MOST drawn out 'weekend build' in all history! 😜 

/* Battery Holder library

Copyright 2020 Christine Whybrow

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

This library takes care of all the code to charge an individual battery, either AAA, AA.
Example of constructors for NiMH AA Battery in each slot.
You can of course change this, & in that eventuality, you should vary the following

BatterySlot: 1 BatterySlot: 2 BatterySlot: 3 BatterySlot: 4
PWN pin: 4 PWN pin: 6 PWN pin: 8 PWN pin: 10
Relay pin: 5 Relay pin: 7 Relay pin: 9 Relay pin: 11
Highside pin: A0 Highside pin: A3 Highside pin: A6 Highside pin: A9
Lowside pin: A1 Lowside pin: A4 Lowside pin: A7 Lowside pin: A10
Temperature pin; A2 Temperature pin; A5 Temperature pin; A8 Temperature pin; A11
BatteryType: 2 BatteryType: 2 BatteryType: 2 BatteryType: 2
Capacity: 2500 Capacity: 2500 Capacity: 2500 Capacity: 2500
ChargeRate: 6 ChargeRate: 6 ChargeRate: 6 ChargeRate: 6
INA219Adress: 0x40 INA219Adress: 0x41 INA219Adress: 0x42 INA219Adress: 0x43

Please take care to assign the correct pins when constructing the individual battery circuit.

I have used 3.3v from the Arduino Mega, to supply the TMP36 temperature sensor, as this gives better
readings & stability!
*/

 

#include <Wire.h>
#include "Adafruit_INA219.h"
#include "BatteryHolder.h"
#include "Adafruit_INA219.h"

//#define I2C_ADDRESS1 0x40 //address of INA219 current sensor
//#define I2C_ADDRESS2 0x41
//#define I2C_ADDRESS3 0x42
//#define I2C_ADDRESS4 0x43

//Adafruit_INA219 slotCurrent(I2C_ADDRESS1); //One ina219 per battery

const float VGSmin = 2.0; //in volts for irf510
const float VGSmax = 4.2; //in VGS conductive range
int VGSminSet = VGSmin * 255/ 5.0;//Converts figures to PWM Output values
int VGSmaxSet = VGSmax * 255 / 5.0;
int startOutput = (VGSmaxSet + VGSminSet) / 2; //Pick an arbitrary mid point
float nowOutput = startOutput;
//float CapacityNiMH = 2300; //in mAh
//float Capacity18650 = 3600; //maximum charge rate 1250mA
//float targetVoltage = 4200.0; //cut off in millivolts
float XL005Set = 5.00; //manually adjust XL005 to this voltage for niMH
float XL00518650set = 6.2; //manually adjust XL005 to this voltage for 18650
int slot_Number = 1; //holds which slot is active

float voltageHighAverage = 0; //this will hold ten high readings of battery voltage
float voltageLowAverage = 0; //this will hold ten low readings of battery voltage
//float targetCurrent = Capacity18650 / 4;//416.0 mA
//float trickleCurrent = Capacity18650 / 20.0;//CapacityNiMH / 20, which is around 125.0 mA
float currentAverage = 0; //allow averaging of current readings
float nowCurrent = 0; //will hold the averaage current readings
float highVolts = 0; //low side analog pin for slot 1
float lowVolts = 0; //high side analog pin for slot 1
float voltageOverCount = 0;
double tempHolder = 0; //holds calculation of temperature
double celsius = 0; //holds final celsius temperature
int temperatureAverage = 0; //holds average of multiple temperature readings
int temperatureCount = 0; //ensures through multtiple readings that temp must 'STOP'
int temperatureOverCount = 0; //if temp over limit 3 times,we'STOP', & go to trickle
float TemperatureCutOff = 37.0; //Battery should go to trickle at this temp
bool overTemp = false; //these will be set to 'true' if these conditions are met
bool overVolt = false;
bool overTime = false;

 

char *errorMsg[] = { "\t\t\tCurrent hasn't been changed", "\t\t\tCurrent has been increased",
"\t\t\tCurrent has been decreased", "\t\t\tBattery charged, going to trickle",
"\t\t\tTemperature exceeded, going to trickle","\t\t\tCharging STOPPED, time exceeded"};

BatteryHolder::BatteryHolder (int slot, int PWM, int relay, uint8_t highside, uint8_t lowside,
uint8_t temperature, int batteryType, float capacity, float chargeDivider,
uint8_t address)
{
_slot = slot;
_PWM = PWM;
_relay = relay;
_highside = highside;
_lowside = lowside;
_temperature = temperature;
_batteryType = batteryType;
_capacity = capacity;
_chargeDivider = chargeDivider;
_address = address;

pinMode(PWM, OUTPUT); //Sets the gate voltage for MOSFET
pinMode(relay, OUTPUT);
pinMode(highside, INPUT); //Low side voltage of battery
pinMode(lowside, INPUT); //High side voltage of battery
pinMode(temperature, INPUT); //temperature of battery

Adafruit_INA219 slotCurrent(_address);
if (! slotCurrent.begin())
{
Serial.println("Failed to find first INA219 chip");
while (1) { delay(10); }
}

}

bool BatteryHolder::setLimits(float targetCurrent, float targetVoltage, float trickleCurrent)
{
_targetCurrent = targetCurrent; //setlimits
_targetVoltage = targetVoltage;
_trickleCurrent = trickleCurrent;
}
BatteryHolder::~BatteryHolder()
{
// set a destructor here if needed
}

bool BatteryHolder::doesExist()
{
return true;
}

bool BatteryHolder::setCapacity(float capacity)
{
_capacity = capacity;
return true;
}

bool BatteryHolder::setBatteryType(int batteryType)
{
_batteryType = batteryType;
return true;
}

bool BatteryHolder::setChargeDivider(float chargeFraction)
{
_chargeDivider = chargeFraction;
return true;
}

bool BatteryHolder::setTimeToStop(double stopTime) //When battery inserted, note time to STOP
{
_timeToStop = stopTime + millis(); //note the start of chargingstartTime
return true;
}

bool BatteryHolder::batteryUpdate()
{
if (overTime)
{
return false; //charging has been stopped, go no further
}
analogWrite(_PWM, nowOutput);
digitalWrite(_relay, HIGH);
delay(50); //allow time for mosfet to settle

float currentAverage = 0; //reset average tally
for (int i =0; i<10; i++)
{
currentAverage +=slotCurrent.getCurrent_mA();//get another reading
delay(50); //allow MOSFET to settle between readings
}
nowCurrent = currentAverage / 10; //we now have ten readings to average

analogWrite(_PWM, 0); //temporarially stop charging
digitalWrite(_relay, LOW); //switch relay 'OFF' to allow precision measure of voltage
delay(50); //allow time to settle

temperatureAverage = 0;
voltageHighAverage = 0; //reset average tally
voltageLowAverage = 0;
for (int i =0; i<10; i++)
{
voltageHighAverage += analogRead(_highside);//get another high reading
voltageLowAverage += analogRead(_lowside);//get another low reading
temperatureAverage += analogRead(_temperature);
delay(50); //allow probes to settle between readings
}

temperatureAverage = temperatureAverage / 10;
int readPin = temperatureAverage;
tempHolder = (double)readPin / 1024;
tempHolder = tempHolder * 5;
tempHolder = tempHolder - 0.5;
celsius = tempHolder * 100;

float highVolt = voltageHighAverage / 10; //we now have ten readings to average
float lowVolt = voltageLowAverage / 10;
highVolts = highVolt * (5000.0 / 1023.0);
lowVolts = lowVolt * (5000.0 / 1023.0);
float voltage = highVolts - lowVolts;
delay(5000);

Serial.println("\t**************Reading battery charge*********************");
Serial.print("\t* PWM Output: "); Serial.print(nowOutput); Serial.println("\t\t\t*");
// Serial.print("\t* target current: "); Serial.print(targetCurrent); Serial.println("\t\t\t*");
Serial.print("\t* battery current: "); Serial.print(nowCurrent); Serial.println(" mA \t\t*");
Serial.print("\t* high reading: "); Serial.print(highVolt); Serial.println("\t\t\t*");
Serial.print("\t* low reading: "); Serial.print(lowVolt); Serial.println("\t\t\t*");
Serial.print("\t* high voltage: "); Serial.print(highVolts); Serial.println(" mV \t\t*");
Serial.print("\t* low voltage: "); Serial.print(lowVolts); Serial.println(" mV \t\t*");
Serial.print("\t* battery voltage: "); Serial.print(voltage); Serial.println(" mV \t\t*");
Serial.print("\t* temperature: "); Serial.print(celsius); Serial.println(" C \t\t\t*");
Serial.println("\t*********************************************************\n\n");

analogWrite(_PWM, nowOutput);
digitalWrite(_relay, HIGH);

if (voltage > _targetVoltage)
{
if (voltageOverCount > 3)
{
Serial.println(errorMsg[3]);
_targetCurrent = _trickleCurrent; //need to stop heavy charging
nowOutput = VGSminSet;
overVolt = true;
voltageOverCount = 0;
}
voltageOverCount++;
return true;
}
if (celsius > TemperatureCutOff)
{

if (temperatureOverCount > 3)
{
nowOutput = VGSminSet; //drop PWM output back to lowest output
temperatureOverCount = 0; //reset the count
overTemp = true;
Serial.println(errorMsg[4]);
return false;
}
overTemp = false; //charging CAN go back to full rate, after cooling
temperatureOverCount++;
return true; //keep charging for now

}
if (millis() > _timeToStop) //Out of time
{
Serial.println(errorMsg[5]);
digitalWrite(_relay, LOW); //switch off charging circuit
nowOutput = 0; //turn off PWM output
overTime = true; //no more charging allowed
return false;
}

if (abs(nowCurrent - _targetCurrent) > 25) //Don't change output unless greater than 25mA difference
{
if ((nowCurrent > _targetCurrent) && (nowOutput > VGSminSet))
{
nowOutput--;
Serial.println(errorMsg[2]);
return true;
}

else if ((nowCurrent < _targetCurrent) && (nowOutput < VGSmaxSet))
{
nowOutput++;
Serial.println(errorMsg[1]);
return true;
}

}
Serial.println(errorMsg[0]);

return true;

}


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@christine86

Posted by: @christine86

URGH, I perhaps spoke too soon?

 

I'm using a INA219 current sensor, to track the current applied to the rechargeable battery, & have four of them, each of which I've soldered tracks to give all four possible units.

As such, as I called every BatteryHolder  constructor 'object' I also called the Adafruit class like this;

Adafruit_INA219 slotCurrent(_address);
if (! slotCurrent.begin())
{
Serial.println("Failed to find first INA219 chip");
while (1) { delay(10); }
}

I had hoped that would mean for every call to BatteryHolder::BatteryUpdate, would mean I was referring to those distinct objects, so I would be able to use something like this;

float currentAverage = 0; //reset average tally
for (int i =0; i<10; i++)
{
currentAverage +=slotCurrent.getCurrent_mA();//get another reading
delay(50); //allow MOSFET to settle between readings
}

I thought that having initialized the objects within my constructor, I could thereafter just refer to slotCurrent.whatever(), the class would ensure the right getCurrent() but alas, I get this error;

 

BatteryHolder.cpp:169:25: error: 'slotCurrent' was not declared in this scope
currentAverage +=slotCurrent.getCurrent_mA();//get another reading
^~~~~~~~~~~

 

Could I perhaps initialize the Adafruit sensor by returning a Adafruit_INA218 'object' or a ->'pointer' so that the other calls to BatteryHolder subroutines, would know exactly WHICH sensor is being used at that time?

Or am I just getting myself confused? WHY can't I upload a '.cpp' file to here, now I'm confused bout THAT too.? I'll just attach it to the end here. This must be the MOST drawn out 'weekend build' in all history!

The error message is correct... having a quick look, you have declared and defined the "slotCurrent" variable of type "Adafruit_INA219", local to your constructor "BatteryHolder::BatteryHolder(...)".  Once your constructor runs, and your BatteryHolder objects are instantiated, this variable goes out of scope, therefore it is not visible in other parts of the code.

If you want it to be part of the class, add it is as a member variable of the class, and then dereference it with an object (or without and object if made static), or place it in the global namespace area which will make it easier to use overall.

I would try making it global first.
 
Cheers!

   
ReplyQuote
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

Hi,

I think I'd already tried this.

If I put this in my main Battery_Charger_v2.INO file;

#define I2C_ADDRESS1 0x40 //address of INA219 current sensor
#define I2C_ADDRESS2 0x41
#define I2C_ADDRESS3 0x42
#define I2C_ADDRESS4 0x43

Adafruit_INA219 slotCurrent[4] = {
Adafruit_INA219(I2C_ADDRESS1),
Adafruit_INA219(I2C_ADDRESS2),
Adafruit_INA219(I2C_ADDRESS3),
Adafruit_INA219(I2C_ADDRESS4)
};

then within my BatterHolder.cpp tells me that a call to slotCurrent[].whatever is 'out of scope'.

 

If i put those same lines in BatteryHolder.CPP at the top, then a call to slotcurrent[].whatever is met with the same error, in Battery_Charger_v2.INO.

 

Can you tell me what I'm doing wrong? I think I've tried just about everything....except the RIGHT thing apparently!

 

Thanks again, sorry my C++ experience is limited, I'd mostly just thought this project would allow me to learn Fusion360, though now, that's been the EASIER part.

 

Christine


   
ReplyQuote
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

I've found the problem, I have declared the Adafruit_INA219 as a private member of the BatteryHolder.h file. I've altered lots of things, I have to now check what i THINK it does, is what it ACTUALLY does;

 

but at least it's stopped drowning me in 'error messages'!

 

Thnx I'm hoping this might be IT!


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@christine86

Posted by: @christine86

Hi,

I think I'd already tried this.

I'm not sure what you mean by that, because as an experienced C++ programmer, the error message that I confirmed to you previously, was pretty accurate and very clear!

Posted by: @christine86

Can you tell me what I'm doing wrong? I think I've tried just about everything....except the RIGHT thing apparently!

Thanks again, sorry my C++ experience is limited, I'd mostly just thought this project would allow me to learn Fusion360, though now, that's been the EASIER part.

 

I'm trying to help you, but you're changing your code without really understanding what's going on, and at the same time, you're not providing us with the details of the changes you have made in your code!

Please elaborate, provide your latest code changes and error messages, and lets take it from there, OK?


   
ReplyQuote
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

Okay, I'm so sorry, I'm not doing this intentionally, I'm trying to learn C++. I even bought a second hand copy of 'C++ Primer' by Lippmam, Lajoie & Moo(imagine going through life with that name).

It's supposed to be the C++ bible, but not exactly the Rosetta stone, easily translated to my experience level.

I'm attaching my .INO.h files, & will have to copy my .cpp file(is there a way to upload that, other than by 'pasting' it?)

About two months go, I started designing the display portion of my charger design, & had succeeded in making the display.

IMG 0469 copy

 

The battery charging portion, that you had helped me with, finally had no errors while compiling. So, earlier today, I put both together, & it has refused to work for me. I'm getting ridiculous current readings of "inf mA", regardless of the PWM input I'm feeding it. I'm guessing I'm not actually linking the INA219, & am receiving some built in value.

Again, I'm sorry. I'm trying to understand your help, but am not up to the task.

Christine

/* Battery Holder library

Copyright 2020 Christine Whybrow

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

This library takes care of all the code to charge an individual battery, either AAA, AA.
Example of constructors for NiMH AA Battery in each slot.
You can of course change this, & in that eventuality, you should vary the following

BatterySlot: 1 BatterySlot: 2 BatterySlot: 3 BatterySlot: 4
PWN pin: 4 PWN pin: 6 PWN pin: 8 PWN pin: 10
Relay pin: 5 Relay pin: 7 Relay pin: 9 Relay pin: 11
Highside pin: A0 Highside pin: A3 Highside pin: A6 Highside pin: A9
Lowside pin: A1 Lowside pin: A4 Lowside pin: A7 Lowside pin: A10
Temperature pin; A2 Temperature pin; A5 Temperature pin; A8 Temperature pin; A11
BatteryType: 2 BatteryType: 2 BatteryType: 2 BatteryType: 2
Capacity: 2500 Capacity: 2500 Capacity: 2500 Capacity: 2500
ChargeRate: 6 ChargeRate: 6 ChargeRate: 6 ChargeRate: 6
INA219Adress: 0x40 INA219Adress: 0x41 INA219Adress: 0x42 INA219Adress: 0x43

Please take care to assign the correct pins when constructing the individual battery circuit.

I have used 3.3v from the Arduino Mega, to supply the TMP36 temperature sensor, as this gives better
readings & stability!
*/

 

#include <Wire.h>
#include "Adafruit_INA219.h"
#include "BatteryHolder.h"
#include "Adafruit_INA219.h"

//#define I2C_ADDRESS1 0x40 //address of INA219 current sensor
//#define I2C_ADDRESS2 0x41
//#define I2C_ADDRESS3 0x42
//#define I2C_ADDRESS4 0x43

//Adafruit_INA219 slotCurrent(I2C_ADDRESS1); //One ina219 per battery

//Adafruit_INA219 slotCurrent[4] = {
//Adafruit_INA219(I2C_ADDRESS1),
//Adafruit_INA219(I2C_ADDRESS2),
//Adafruit_INA219(I2C_ADDRESS3),
//Adafruit_INA219(I2C_ADDRESS4)
//};

//const float VGSmin = 2.0; //in volts for irf510
//const float VGSmax = 4.2; //in VGS conductive range
//int VGSminSet = VGSmin * 255/ 5.0;//Converts figures to PWM Output values
//int VGSmaxSet = VGSmax * 255 / 5.0;
//int startOutput = (VGSmaxSet + VGSminSet) / 2; //Pick an arbitrary mid point
//float nowOutput = startOutput;
//float CapacityNiMH = 2300; //in mAh
//float Capacity18650 = 3600; //maximum charge rate 1250mA
//float targetVoltage = 4200.0; //cut off in millivolts
//float XL005Set = 5.00; //manually adjust XL005 to this voltage for niMH
//float XL00518650set = 6.2; //manually adjust XL005 to this voltage for 18650
//int slot_Number = 1; //holds which slot is active

//float voltageHighAverage = 0; //this will hold ten high readings of battery voltage
//float voltageLowAverage = 0; //this will hold ten low readings of battery voltage
////float targetCurrent = Capacity18650 / 4;//416.0 mA
////float trickleCurrent = Capacity18650 / 20.0;//CapacityNiMH / 20, which is around 125.0 mA
//float currentAverage = 0; //allow averaging of current readings
//float nowCurrent = 0; //will hold the averaage current readings
//float highVolts = 0; //low side analog pin for slot 1
//float lowVolts = 0; //high side analog pin for slot 1
//float voltageOverCount = 0;
//double tempHolder = 0; //holds calculation of temperature
//double celsius = 0; //holds final celsius temperature
//int temperatureAverage = 0; //holds average of multiple temperature readings
//int temperatureCount = 0; //ensures through multtiple readings that temp must 'STOP'
//int temperatureOverCount = 0; //if temp over limit 3 times,we'STOP', & go to trickle
//float TemperatureCutOff = 37.0; //Battery should go to trickle at this temp
//bool overTemp = false; //these will be set to 'true' if these conditions are met
//bool _overVolt = false;
//bool overTime = false;

 

char *errorMsg[] = { "\t\t\tCurrent hasn't been changed", "\t\t\tCurrent has been increased",
"\t\t\tCurrent has been decreased", "\t\t\tBattery charged, going to trickle",
"\t\t\tTemperature exceeded, going to trickle","\t\t\tCharging STOPPED, time exceeded"};

BatteryHolder::BatteryHolder (int slot, int PWM, int relay, uint8_t highside, uint8_t lowside,
uint8_t temperature, int batteryType, float capacity, float chargeDivider,
uint8_t address)
{
_slot = slot;
_PWM = PWM;
_relay = relay;
_highside = highside;
_lowside = lowside;
_temperature = temperature;
_batteryType = batteryType;
_capacity = capacity;
_chargeDivider = chargeDivider;
_address = address;

pinMode(PWM, OUTPUT); //Sets the gate voltage for MOSFET
pinMode(relay, OUTPUT);
pinMode(highside, INPUT); //Low side voltage of battery
pinMode(lowside, INPUT); //High side voltage of battery
pinMode(temperature, INPUT); //temperature of battery

}

bool BatteryHolder::setLimits(float targetCurrent, float targetVoltage, float trickleCurrent)
{
_targetCurrent = targetCurrent; //setlimits
_targetVoltage = targetVoltage;
_trickleCurrent = trickleCurrent;
}

void BatteryHolder::setBatteryParameters(int temperatureCutOff, int nowOutput, int VGSminSet, int VGSmaxSet,
int voltageOverCount, bool overVolt)
{
_temperatureCutOff = temperatureCutOff;
_nowOutput = nowOutput;
_VGSminSet = VGSminSet;
_VGSmaxSet = VGSmaxSet;
_voltageOverCount = 0;
_overVolt = false;

}

void BatteryHolder::setNowOutput(int output)
{
_nowOutput = output;
}

bool BatteryHolder::batteryIsIn()
{
if (!_batteryInstalled)
{
_batteryInstalled = true;
return false;
}
return true;
}

bool BatteryHolder::returnBatteryInsertion()
{
return _batteryInstalled;
}

float BatteryHolder::batteryInstalled()
{
//float temp = analogRead(_highside);
//_batteryInstalled = true;

return analogRead(_highside);
}

BatteryHolder::~BatteryHolder()
{
// set a destructor here if needed
}

bool BatteryHolder::doesExist()
{
return true;
}

bool BatteryHolder::setCapacity(float capacity)
{
_capacity = capacity;
return true;
}

bool BatteryHolder::setBatteryType(int batteryType)
{
_batteryType = batteryType;
return true;
}

bool BatteryHolder::setChargeDivider(float chargeFraction)
{
_chargeDivider = chargeFraction;
return true;
}

void BatteryHolder::setTimeToStop(unsigned long stopTime) //When battery inserted, note time to STOP
{
_timeToStop = stopTime + millis(); //note the start of charging
return true;
}
/*
* This is the main program, doing the bulk of the work to charge the battery
* **************************************************************************
*/
bool BatteryHolder::batteryUpdate()
{

if (millis() > _timeToStop)
{
Serial.print("at start of time loop ");Serial.print(_timeToStop);Serial.print("\t\t"); Serial.println(millis());
return false; //charging has been stopped, go no further
}
digitalWrite(_relay, HIGH);
analogWrite(_PWM, _nowOutput);
Serial.print(_PWM); Serial.print("\t");Serial.println( _nowOutput);
delay(50); //allow time for mosfet to settle

float currentAverage = 0; //reset average tally
for (int i =0; i<10; i++)
{
currentAverage += slotCurrent[_slot - 1].getCurrent_mA();//get another reading
delay(60); //allow MOSFET to settle between readings
}
float _nowCurrent = currentAverage / 10; //we now have ten readings to average

analogWrite(_PWM, 0); //temporarially stop charging
digitalWrite(_relay, LOW); //switch relay 'OFF' to allow precision measure of voltage
delay(50); //allow time to settle

float temperatureAverage = 0;
float voltageHighAverage = 0; //reset average tally
float voltageLowAverage = 0;
for (int i =0; i<10; i++)
{
voltageHighAverage += analogRead(_highside);//get another high reading
voltageLowAverage += analogRead(_lowside);//get another low reading
temperatureAverage += analogRead(_temperature);
delay(50); //allow probes to settle between readings
}

temperatureAverage = temperatureAverage / 10;
int readPin = temperatureAverage;
double tempHolder = (double)readPin / 1024;
tempHolder = tempHolder * 5;
tempHolder = tempHolder - 0.5;
float celsius = tempHolder * 100;

float highVolt = voltageHighAverage / 10; //we now have ten readings to average
float lowVolt = voltageLowAverage / 10;
float highVolts = highVolt * (5000.0 / 1023.0);
float lowVolts = lowVolt * (5000.0 / 1023.0);
float voltage = highVolts - lowVolts;
delay(50);

Serial.println("\t**************Reading battery charge*********************");
Serial.print("\t* PWM Output: "); Serial.print(_nowOutput); Serial.println("\t\t\t*");
Serial.print("\t* battery current: "); Serial.print(_nowCurrent); Serial.println(" mA \t\t*");
Serial.print("\t* high reading: "); Serial.print(highVolt); Serial.println("\t\t\t*");
Serial.print("\t* low reading: "); Serial.print(lowVolt); Serial.println("\t\t\t*");
Serial.print("\t* high voltage: "); Serial.print(highVolts); Serial.println(" mV \t\t*");
Serial.print("\t* low voltage: "); Serial.print(lowVolts); Serial.println(" mV \t\t*");
Serial.print("\t* battery voltage: "); Serial.print(voltage); Serial.println(" mV \t\t*");
Serial.print("\t* temperature: "); Serial.print(celsius); Serial.println(" C \t\t\t*");
Serial.println("\t*********************************************************\n\n");

analogWrite(_PWM, _nowOutput);
digitalWrite(_relay, HIGH);

if (voltage > _targetVoltage)
{
if (_voltageOverCount > 3)
{
Serial.println(errorMsg[3]);
_targetCurrent = _trickleCurrent; //need to stop heavy charging
_nowOutput = _VGSminSet;
_overVolt = true;
_voltageOverCount = 0;
}
_voltageOverCount++;
return true;
}
if (celsius > _temperatureCutOff)
{

if (_temperatureOverCount > 3)
{
_nowOutput = _VGSminSet; //drop PWM output back to lowest output
_temperatureOverCount = 0; //reset the count
_overTemp = true;
Serial.println(errorMsg[4]);
return false;
}
_overTemp = false; //charging CAN go back to full rate, after cooling
_temperatureOverCount++;
return true; //keep charging for now

}
if (millis() > _timeToStop) //Out of time
{
Serial.println(errorMsg[5]);
digitalWrite(_relay, HIGH); //switch off charging circuit
_nowOutput = 0; //turn off PWM output
//overTime = true; //no more charging allowed
return false;
}

if (abs(_nowCurrent - _targetCurrent) > 25) //Don't change output unless greater than 25mA difference
{
if ((_nowCurrent > _targetCurrent) && (_nowOutput > _VGSminSet))
{
_nowOutput--;
Serial.println(errorMsg[2]);
return true;
}

else if ((_nowCurrent < _targetCurrent) && (_nowOutput < _VGSmaxSet))
{
_nowOutput++;
Serial.println(errorMsg[1]);
return true;
}

}
Serial.println(errorMsg[0]);

return true;

}

 


   
ReplyQuote
Christine86
(@christine86)
Member
Joined: 4 years ago
Posts: 45
Topic starter  

OK, I've largely got this working now, both the INA219 & BatteryHolder classes are finally playing nice. Now i just have to work out how to have four of these instances running 'virtually' in my battery slots of the charger.

 

Thnx for the help!

 

Christine


   
ReplyQuote