Hello everyone, Im a computer science student who is fairly new to working with arduino and microcontrollers. Ive been tasked with designing a li-ion battery charging and discharging circuit. The circuit is required to discharge the li-ion battery to say a minimum voltage of 2.75 V and then charge it back to 3.75 V and this cycle repeats for as many times as specified in the input. Ive made a GUI using python in order to interact with the application as there is a requirement of graphing the characteristic curves for all the cycles of the battery.
Background : The hardware circuit Ive designed from looking into videos and forums is one consisting of a constant current load made using an Op-Amp (LM358) , 1ohm resistor , n-Mosfet (IRLZ44n) and a DAC(MCP4725) .The DAC sets the non-inverted input voltage for the discharge current required. Im using an arduino UNO. The basics as I understand it is that the op-amp here compares the non-inverted input (from the DAC) and the inverted input (across the resistor) and the output to the gate of the mosfet is such that it makes sure there is a constant current across the source. (Please correct me if im wrong here) . I measure the current across the 1ohm resistor and the voltage across the terminals of the battery. Im using a TP4056 to charge the li-ion battery and Im using the enable pin on the tp4056 to control when it charges the battery and when it's off so that battery discharges. Please let me know if I should include the schematic.
Code : I am only attaching the arduino code here as the python code is around 700 lines (due to the GUI) . Im using pyserial for communicating with arduino. I take inputs from the GUI for discharge current (can set between 10mA and 1000mA with steps of 10mA for current setup), min volt to discharge to , max volt to charge to and number of cycles. Then I read the voltage and current from the arduino and apply a median filter (tried using MAF, curve wasnt satisfactory) with a window size of 30 and graph using matplotlib.
#include <Wire.h> //Module to initiate I2C communications with required devices
#include <Adafruit_MCP4725.h> //DAC module for communication with the DAC from arduino
Adafruit_MCP4725 dac; //DAC object containing in-built functions , here the setVoltage function
#define voltmin 2.75 // Minimum voltage battery can discharge to
#define voltmax 3.75 // Maximum voltage battery can charge to
#define supplyVoltage 5.00
#define batteryVoltagePin A0
#define batteryCurrentPin A1
#define chargePin 11
#define enablePin 12
double battery01Capacity = 0; // Battery capacity
float state = 0; //To control discharge current values
double volt_min=0.0f;
double volt_max=0.0f;
//The below function is used to convert the values read by the arduino into voltages . 0V corresponds to 0 and 5V corresponds to 5V
double readVoltage(uint8_t voltagePin) {
return (supplyVoltage * analogRead(voltagePin)) / 1024.0; // This is used to find the voltage that the battery is at currently. We convert into a digital value by multiplying by 5 and diving by 1024 as 0-1024 is 0-5V in arduino
}
//The below function is used to monitor the voltage and capacity of the battery as it is being discharged
void logMilliampHoursForTheLastSecond(double *capacity, uint8_t state, uint8_t voltagePin) {
double voltage = readVoltage(voltagePin); // Voltage of the battery is monitored here.
double current = readVoltage(batteryCurrentPin); // Value of current at which the battery is being discharged at
*capacity += current / 3600; // 3600 as we are converting As to Ahr , if we change the delay we will have to change this value
Serial.print(*capacity,2);
Serial.print(" ");
Serial.print(voltage,7);
Serial.print(" ");
Serial.println(current,7);
}
//The below function is used to prevent the battery from over discharging i.e discharging below 2.7V
void protectFromOverDischarge(uint8_t voltagePin) {
double voltage = readVoltage(voltagePin);
if (voltage < voltmin) //This value is the minimum value of voltage
{
dac.setVoltage(0, false);
digitalWrite(enablePin, HIGH);
}
}
void protectFromOverCharge(uint8_t voltagePin) {
double voltage = readVoltage(voltagePin);
if (voltage > voltmax) {
digitalWrite(enablePin, LOW);
decideVoltage(state);
}
}
//The below function is used to decide the voltage value of the DAC to control the current at which the battery discharges based on the state/value of current required.
void decideVoltage(uint8_t state) {
if (state >= 0 && state <= 10)
dac.setVoltage((((state + 1.0) / 100) * 4095) / 5, false);
else if (state >= 11 && state <= 51)
dac.setVoltage((((state + 1.0) / 100) * 4095) / 5, false);
else if (state >= 52 && state <= 61)
dac.setVoltage((((state + 1.0) / 100) * 4095) / 5, false);
else if (state >= 62 && state <= 71)
dac.setVoltage((((state + 1.0) / 100) * 4095) / 5, false);
else if (state >= 72 && state <= 81)
dac.setVoltage((((state + 1.0) / 100) * 4095) / 5, false);
else if (state >= 82 && state <= 102)
dac.setVoltage((((state + 1.0) / 100) * 4095) / 5, false);
}
//The below function is run once and is used to initialize the I2C communication devices, here DAC
void setup() {
Serial.begin(9600);
dac.begin(0x62);
pinMode(chargePin, INPUT);
pinMode(enablePin, OUTPUT);
delay(2000);
}
//The below function loops performing the necessary operations required for charging/discharging the battery
/*
We can set the voltage to the DAC which is used to control the current at which the battery is charged with the help of the OP-AMP which works
as a voltage comparator and maintains the constant voltage between input and output. This is then fed to the n-MOSFET which is a logic level MOSFET.
The MOSFET is used to obtain a constant current for discharging the Battery
Different current values possible are : 10mA - 1000mA in steps of 10 i.e 10,20,30,40 etc
*/
void loop() {
double control = readVoltage(batteryVoltagePin);
if (control > voltmin)
{
digitalWrite(enablePin,LOW);
if (Serial.available()) {
String inputString = Serial.readStringUntil('\n');
// Split the string using ',' as a delimiter
int index = 0;
char *ptr = strtok(const_cast<char*>(inputString.c_str()), ",");
float values[3];
while (ptr != NULL && index < 3) {
values[index] = atof(ptr);
ptr = strtok(NULL, ",");
index++;
}
// Store values in specific variables
if (index >= 3) {
state = values[0];
volt_min = values[1];
volt_max = values[2];
}
}
decideVoltage(state);
if (state >= 0 && state < 101) {
Serial.print("DISCHARGING ");
protectFromOverDischarge(batteryVoltagePin);
logMilliampHoursForTheLastSecond(&battery01Capacity, state, batteryVoltagePin);
delay(1000); //This is the time delay between successive intervals for noting/plotting the values of voltage and current
}
}else
{
digitalWrite(enablePin, HIGH);
dac.setVoltage(0, false);
protectFromOverCharge(batteryVoltagePin);
double volt = readVoltage(batteryVoltagePin);
Serial.print("CHARGING ");
Serial.print("Voltage :");
Serial.print(volt);
Serial.println();
delay(1000);
}
}
My problem : While measuring the voltage and currents across the terminals of the battery using the arduino Im getting a lot of fluctuation . Also the measured potential differs from the no current potential (im assuming due to internal resistance of the components) but I have no way to correct it as Ive heard the internal resistance of the battery increases with use. Here is an image of the graph for discharge at a discharge current of 0.5A Ive gotten for reference :
The shape of the curve seems right till the drop as Ive seen from different curves but the next part does not seem to make sense. I have not looked into the curve of charging yet
I would like help on how to fix the fluctuation and the characteristic curve. I would appreciate any help with the hardware as well or general pointers
Its my first post on the forum so sorry if Ive violated any guidelines
TIA!