0% found this document useful (0 votes)
17 views13 pages

Text Fromat Battery - Capacitey - Tester

The document describes code for a battery manager and tester that can monitor battery voltage, calculate capacity and internal resistance during discharge, and estimate charging current. It includes functions for reading sensor values, controlling MOSFET switches, and displaying information on an LCD screen.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views13 pages

Text Fromat Battery - Capacitey - Tester

The document describes code for a battery manager and tester that can monitor battery voltage, calculate capacity and internal resistance during discharge, and estimate charging current. It includes functions for reading sensor values, controlling MOSFET switches, and displaying information on an LCD screen.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 13

//---------------------------------------------------------------------------------

--------------------------------------------------------------
//-------------------------------------------------------Battery Manager and Tester
-----------------------------------------------------------------
#include <SPI.h>
#include <stdlib.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long previousMillis = 0;
unsigned long millisPassed = 0;
unsigned long BatFull = 0;
float BatVoltQuiescent = 0; // The
battery voltage when there is no load on the battery
float Capacity = 0.0; // The
calculated capacity of the battery, measured wile discharging
float mA=0;
float SetI = 0; // The
setpoint for the discharging current. Remember you can adjust the discharging
current using the 500K trimpot.
float ChargeI = 0;
float CurTP4056 = 0;
float ResTP4056 = 0;
float ratioRI = 0;
float BatLevel = 0; // The
percentage of battery charge/level
float BatVoltCorrected = 0; // The
voltage of the battery, measured based on the arduino internal reference
float A2VoltCorrected = 0;
float VoltTP4056Pin2 = 0;
float Rprog = 0;
float BatRes = 0; // The
internal battery resistance
const float RES = 0.500; // Value of
your resistor. Change it, if you use a different resistor value
#define clk 2
#define dt 3
#define sw 4
#define MOSFET_Discharge 8 // It is an
N-MOSFET, so HIGH is ON and LOW is OFF
#define MOSFET_Charge 12
char screen = 0;
char arrowpos = 0;
char charging = 0;
char discharging = 0;
char storage = 0;
char storagecharge = 0;
char storagedischarge = 0;
char BatVoltQuiescentValue = 0; // Whether
there is a value for "the battery voltage with no load" (BatVoltQuiescent) or not.
1 for yes and 0 for no.
//char nointermediate = 0;
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
volatile boolean TurnDetected = false;
volatile boolean up = false;
volatile boolean button = false;

byte OhmChar[8] = {
B00000,
B01110,
B10001,
B10001,
B10001,
B01010,
B11011,
B00000
};

byte customChar1[8] = {
0b10000,
0b11000,
0b11100,
0b11110,
0b11110,
0b11100,
0b11000,
0b10000
};

ISR(PCINT2_vect) {
if (digitalRead(sw) == LOW) {
button = true;
}
}

void isr0 () {
TurnDetected = true;
up = (digitalRead(dt));
}

void setup() {
lcd.begin();
lcd.setCursor(0, 0);
pinMode(MOSFET_Discharge, OUTPUT);
pinMode(MOSFET_Charge, OUTPUT);
digitalWrite(MOSFET_Discharge, LOW);
digitalWrite(MOSFET_Charge, LOW);
pinMode(sw, INPUT_PULLUP);
pinMode(clk, INPUT);
pinMode(dt, INPUT);
PCICR |= 0b00000100;
PCMSK2 |= 0b00010000; // turn o PCINT20(D4)
attachInterrupt(0, isr0, RISING);
lcd.createChar(0, customChar1);
lcd.createChar(1, OhmChar);
lcd.clear();
screen0();
lcd.setCursor(0, 0);
lcd.write((uint8_t)0);
}

void loop() {
int in0 = analogRead(A0); //read the A0
pin value
int sensorValue1 = analogRead(A1); //read the A1
pin value
float val0 = in0 * 5.0 / 1024.0;
float supply = readVcc() / 1000.0;
SetI = sensorValue1 * (5.00 / 1024.00) / RES * 1000; // Calculate
the discharge rate of the battery
if (SetI <= 2000){
SetI = SetI;
}
else{
SetI = 2000;
}
BatVoltCorrected = supply / 5 * val0 * 4.28; //In case
you use different voltage dividers, you need to change the number 4.3 accordingly.
millisPassed = millis() - previousMillis;
previousMillis = millis();
//------------------------------------------------------------------- calculates
the charging current
------------------------------------------------------------------------

int in2 =
analogRead(A2); //read the A2
pin value
int in3 =
analogRead(A3); //read the A3
pin value
float val2 = in2 * 5.0 / 1024.0;
float val3 = in3 * 5.0 / 1024.0;
A2VoltCorrected = supply / 5 *
val2; //calculates reading of pin A2
based on internal voltage reference
VoltTP4056Pin2 = supply / 5 * val3;
//calculates reading of pin A3 based on internal voltage reference

Rprog = 1220 + (A2VoltCorrected * 1220 / (VoltTP4056Pin2 -


A2VoltCorrected)); //calculates the Rprog of TP4056 module

//
calculates the Charging current based on numbers from TP4056 datasheet
if (Rprog >= 10000) {
CurTP4056 =130 ;
ResTP4056 =10000 ;
ratioRI = 0.107 ;
}
else if (Rprog < 10000 && Rprog >= 5000){
CurTP4056 = 250 ;
ResTP4056 = 5000 ;
ratioRI = 0.024 ;
}
else if (Rprog < 5000 && Rprog >= 4000){
CurTP4056 = 300 ;
ResTP4056 = 4000 ;
ratioRI = 0.050 ;
}
else if (Rprog < 4000 && Rprog >= 3000){
CurTP4056 = 400 ;
ResTP4056 = 3000 ;
ratioRI = 0.100 ;
}
else if (Rprog < 3000 && Rprog >= 2000){
CurTP4056 = 580 ;
ResTP4056 = 2000 ;
ratioRI = 0.180 ;
}
else if (Rprog < 2000 && Rprog >= 1660){
CurTP4056 = 690 ;
ResTP4056 = 1660 ;
ratioRI = 0.324 ;
}
else if (Rprog < 1660 && Rprog >= 1500){
CurTP4056 = 780 ;
ResTP4056 = 1500 ;
ratioRI = 0.563 ;
}
else if (Rprog < 1500 && Rprog >= 1330){
CurTP4056 = 900 ;
ResTP4056 = 1330 ;
ratioRI = 0.706 ;
}
else if (Rprog >= 1220){
CurTP4056 = 995 ;
ResTP4056 = 1220 ;
ratioRI = 0.864 ;
}

if (Rprog < 1220){


ChargeI = 1000 ;
}
else {
ChargeI = (CurTP4056 - ((Rprog - ResTP4056) * ratioRI));
}

if (ChargeI > 0){


ChargeI = ChargeI;
}
else{
ChargeI = 0;
}
//------------------------------------------------------------------- battery
percentage - linear calculation based on voltage (linear does NOT represent the
REAL percentage)
if (BatVoltCorrected < 2.5) {
BatLevel = 0;
}
else if (BatVoltCorrected > 4.2)
{BatLevel = 100;
}
else {BatLevel = (BatVoltCorrected - 2.5 ) / 1.7 * 100 ;
}
//-------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
----
if (BatVoltCorrected <= 3.70 && BatVoltCorrected >= 3.65){ // For
3400mAh batteries storage voltage is 3.6-3.7V, for batteries below 2600mAh it
should be higher.
storagedischarge = 0;
storagecharge = 0;
}
if (BatVoltCorrected <= 3.75 && BatVoltCorrected > 3.7){ // Set these
numbers +0.5V of your batteries storage voltage
storagedischarge = 1;
storage = 2;
storagecharge = 0;
}
if (BatVoltCorrected >= 3.6 && BatVoltCorrected < 3.65){ // Set these
numbers -0.5V of your batteries storage voltage
storagecharge = 1;
storage = 2;
storagedischarge = 0;
}
if (BatVoltCorrected > 3.75 || BatVoltCorrected < 3.6){ // Set these
numbers +0.5V and -0.5V of your batteries storage voltage
storage = 0;
storagedischarge = 0;
storagecharge = 0;
}
if (BatVoltCorrected <= 3.75 && BatVoltCorrected >= 3.6){ // Set these
numbers +0.5V and -0.5V of your batteries storage voltage
storage = 1;
}
//-------------------------------------------------------------------------------
-----------------------------------------------------------------------
if (screen == 0) {
//delay(500);
BatVoltQuiescent = BatVoltCorrected - 20;
BatVoltQuiescentValue = 1;
BatFull = 0;
}
//---------------------------------------------------------------------------------
-------Capacity test mode-------------------------------------------------------
if (screen == 1) {
if (BatVoltCorrected <= 2.30){
Capacity = Capacity;
BatVoltQuiescentValue = 0;
digitalWrite(MOSFET_Discharge, LOW);
// buz();
lcd.setCursor(0,0);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(8,0);
lcd.print("I:");
lcd.print(SetI,0);
lcd.print("mA ");
lcd.setCursor(0,1);
lcd.print("C:");
lcd.print(Capacity,0);
lcd.print("mAh ");
lcd.setCursor(10,1);
lcd.print("R:");
lcd.print(BatRes,0);
lcd.print("m");
lcd.print(char(1));
delay(500);
}
if (BatVoltCorrected > 2.3 && BatVoltQuiescentValue == 0 ) {
BatRes = (BatVoltQuiescent - BatVoltCorrected) / (BatVoltCorrected / SetI);
//Calculates the internal battery resistance in mOhms
Capacity = Capacity + (SetI * (millisPassed / 3600000.0));
BatVoltQuiescent = BatVoltCorrected;
BatVoltQuiescentValue = 1;
digitalWrite(MOSFET_Discharge, HIGH);
lcd.setCursor(0,0);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(8,0);
lcd.print("I:");
lcd.print(SetI,0);
lcd.print("mA ");
lcd.setCursor(0,1);
lcd.print("C:");
lcd.print(Capacity,0);
lcd.print("mAh ");
lcd.setCursor(10,1);
lcd.print("R:");
lcd.print(BatRes,0);
lcd.print("m");
lcd.print(char(1));
delay(500);
}
else if (BatVoltCorrected > 2.3 && BatVoltQuiescentValue == 1 ) {
BatRes = (BatVoltQuiescent - BatVoltCorrected) / (BatVoltCorrected / SetI);
//Calculates the internal battery resistance in mOhms
Capacity = Capacity + (SetI * (millisPassed / 3600000.0));
digitalWrite(MOSFET_Discharge, HIGH);
lcd.setCursor(0,0);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(8,0);
lcd.print("I:");
lcd.print(SetI,0);
lcd.print("mA ");
lcd.setCursor(0,1);
lcd.print("C:");
lcd.print(Capacity,0);
lcd.print("mAh ");
lcd.setCursor(10,1);
lcd.print("R:");
lcd.print(BatRes,0);
lcd.print("m");
lcd.print(char(1));
delay(500);
}
}
//-------------------------------------------------------------------------------
---------Charge mode-------------------------------------------------------
else if (screen == 2) {
if (BatVoltCorrected >= 4.35) {
lcd.setCursor(0,0);
lcd.print("Battery Full");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(8,1);
lcd.print("I:");
lcd.print(ChargeI,0);
lcd.print("mA ");
digitalWrite(MOSFET_Charge, LOW);
delay(500);
BatFull = BatFull + 1;
}
else if (BatVoltCorrected == 0 ){
BatFull = 0;
lcd.setCursor(0,0);
lcd.print("No Battery ");
lcd.setCursor(12,0);
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(9,1);
lcd.print("I:");
lcd.print(ChargeI,0);
lcd.print("mA ");
digitalWrite(MOSFET_Charge, LOW);
//delay(9000);
//digitalWrite(MOSFET_Charge, HIGH);
delay(500);
}
else if (BatVoltCorrected < 4.35 && BatFull < 10 && BatVoltCorrected > 0 ) {
lcd.setCursor(0,0);
lcd.print("Charging....... ");

lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(8,1);
lcd.print("I:");
lcd.print(ChargeI,0);
lcd.print("mA ");
digitalWrite(MOSFET_Charge, HIGH);
//delay(9000);
//digitalWrite(MOSFET_Charge, HIGH);
delay(1000);
}
else if (BatVoltCorrected < 4.35 ) {
lcd.setCursor(0,0);
lcd.print("Battery Full");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(8,1);
lcd.print("I:");
lcd.print(ChargeI,0);
lcd.print("mA ");
digitalWrite(MOSFET_Charge, LOW);
delay(500);
}
}
//-------------------------------------------------------------------------------
---------Storage
mode-------------------------------------------------------------------------------
----------
// You need to adjust your voltages according to your batteries, for 3400mAh
batteries storage voltage (50% capacity) is 3.6-3.7V, for batteries below 2600mAh
it should be higher.
// For more info visit this:https://lygte-info.dk/info/BatteryChargePercent
%20UK.html
else if (screen == 3) {
delay(100);
if (BatVoltCorrected <= 1.5 ) {
lcd.setCursor(0,0);
lcd.print("No battery ");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
digitalWrite(MOSFET_Discharge, LOW);
digitalWrite(MOSFET_Charge, LOW);
charging = 0;
discharging = 0;
storage = 0;
storagecharge = 0;
storagedischarge = 0;
}
else if (BatVoltCorrected > 3.75 && charging == 0) {
// Checks if the "quiescent voltage" of the battery is above 3.7V and Starts the
discharge.
lcd.setCursor(0,0);
lcd.print("Discharging ");
lcd.setCursor(0,1);
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(9,1);
lcd.print("I:");
lcd.print(SetI,0);
lcd.print("mA ");
digitalWrite(MOSFET_Charge, LOW);
delay(100);
discharging = 1;
digitalWrite(MOSFET_Discharge, HIGH);
delay(5000);
digitalWrite(MOSFET_Discharge, LOW);
}
else if (storagedischarge == 1 && discharging == 1){
// Intermediate step before stopping the discharge
lcd.setCursor(0,0);
lcd.print("RDY for storage");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
discharging = 1;
digitalWrite(MOSFET_Charge, LOW);
delay(100);
digitalWrite(MOSFET_Discharge, HIGH);
delay(10000);
digitalWrite(MOSFET_Discharge, LOW);
}
else if (BatVoltCorrected >= 1.5 && BatVoltCorrected < 3.6) {
// Checks if the "quiescent voltage" of the battery is between 1.5V and 3.6V
if (discharging == 1 && BatVoltCorrected < 3.0)
{ // Stops discharging if the "discharge voltage" of the
battery is below 3.0V
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(9,1);
lcd.print("I:");
lcd.print(SetI,0);
lcd.print("mA ");
digitalWrite(MOSFET_Discharge, LOW);
}
if (discharging == 1 && BatVoltCorrected > 2){
// Prevents from charging (continues discharging) even if the "quiescent voltage"
is below 3.6V
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
lcd.setCursor(9,1);
lcd.print("I:");
lcd.print(SetI,0);
lcd.print("mA ");
}
else if (discharging == 0 && BatVoltCorrected < 3.6){
// Starts to charge the battery
lcd.setCursor(0,0);
lcd.print("Charging... ");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
digitalWrite(MOSFET_Discharge, LOW);
delay(100);
digitalWrite(MOSFET_Charge, HIGH);
charging = 1;
delay(1000);
}
else {
// used for debugging
lcd.setCursor(0,0);
lcd.print("error? ");
}
}

else if (storagecharge == 1 && charging == 1){


// Intermediate step before stopping the charge. (not actually stopping the charge)
lcd.setCursor(0,0);
lcd.print("RDY for storage");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
charging = 1;
//nointermediate = 1;
digitalWrite(MOSFET_Discharge, LOW);
delay(100);
digitalWrite(MOSFET_Charge, HIGH);
delay(1000);
}
else if (charging == 1 && BatVoltCorrected > 3.75 ){
// Stops charge . This step is used if the Intermediate stop of charge was used.
lcd.setCursor(0,0);
lcd.print("RDY for storage");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
digitalWrite(MOSFET_Discharge, LOW);
digitalWrite(MOSFET_Charge, HIGH);
delay(1000);
}
else if (storage == 1 && charging == 0){
// For 3400mAh batteries sorage voltage is 3.6-3.7V, for batteries below 2600mAh it
should be higher.
lcd.setCursor(0,0);
// This step is used if the Intermediate stop of charge was NOT used. Or after
intermadiate stop of discharge.
lcd.print("RDY for storage");
lcd.setCursor(0,1);
lcd.print("V:");
lcd.print(BatVoltCorrected);
lcd.print("V ");
digitalWrite(MOSFET_Discharge, LOW);
digitalWrite(MOSFET_Charge, LOW);
delay(1000);
}

//--------------------------------------------------------------------------------
TURN
-----------------------------------------------------------------------------------
--------------------
if (TurnDetected) {
delay(200);
switch (screen) {
case 0:
switch (arrowpos) {
case 0:
if (!up) {
screen0();
lcd.setCursor(0, 1);
lcd.write((uint8_t)0);
arrowpos = 1;
}
else {
screen0();
lcd.setCursor(8, 1);
lcd.write((uint8_t)0);
arrowpos = 2;
}
break;
case 1:
if (up) {
screen0();
lcd.setCursor(0, 0);
lcd.write((uint8_t)0);
arrowpos = 0;
}
else {
screen0();
lcd.setCursor(8, 1);
lcd.write((uint8_t)0);
arrowpos = 2;
}
break;
case 2:
if (up) {
screen0();
lcd.setCursor(0, 1);
lcd.write((uint8_t)0);
arrowpos = 1;
}
else {
screen0();
lcd.setCursor(0, 0);
lcd.write((uint8_t)0);
arrowpos = 0;
}
break;
}
break;
}
TurnDetected = false;
}
//---------------------------------------------------------------------------------
----------- BUTTON PRESS
-----------------------------------------------------------------------------------
---------
if (button) {
delay(200);
switch (screen) {
case 0:
if (arrowpos == 0) {
screen = 1;
screen1();
}
else if (arrowpos == 1){
screen = 2;
screen2();
}
else {
screen = 3;
screen3();
}
break;
case 1:
screen = 0;
screen0();
lcd.setCursor(0, 0);
lcd.write((uint8_t)0);
break;
case 2:
screen = 0;
screen0();
lcd.setCursor(0, 0);
lcd.write((uint8_t)0);
break;
case 3:
screen = 0;
screen0();
lcd.setCursor(0, 0);
lcd.write((uint8_t)0);
break;
}
arrowpos = 0;
button = false;
}
}
//---------------------------------------------------------------------------------
--------------------
SCREENS----------------------------------------------------------------------------
---------
void screen0() {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Capacity test");
lcd.setCursor(1, 1);
lcd.print("Charge");
lcd.setCursor(9, 1);
lcd.print("Store");
digitalWrite(MOSFET_Discharge, LOW);
digitalWrite(MOSFET_Charge, LOW);
charging = 0;
discharging = 0;
storage = 0;
storagecharge = 0;
storagedischarge = 0;
}

void screen1() {
lcd.clear();
}

void screen2() {
lcd.clear();
}

void screen3() {
lcd.clear();
}

//-------------------------------------------------------------------voltage based
on internal reference-------------------------------------------------------------
long readVcc() {
long result;
// Read 1.1V reference against AVcc
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) ||
defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) ||
defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(2); // Wait for Vref to
settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA, ADSC));
result = ADCL;
result |= ADCH << 8;
result = 1126400L / result; // Calculate Vcc (in
mV); 1126400 = 1.1*1024*1000
return result;
}

//void buz()
// {
// digitalWrite(9, HIGH);
// delay(100);
// digitalWrite(9, LOW);
// delay(10);
//}

You might also like