121 lines
4.0 KiB
C
121 lines
4.0 KiB
C
//LiFePO4 4S battery soc and level calculation library
|
|
|
|
//todo:
|
|
//- battery level will forced after 60-seconds if not passing battPercentageLevelThreshold (optional)
|
|
|
|
static uint8_t battPercentageLevelThreshold = 5; //threshold for switch discrete level 0-4
|
|
static uint8_t battLastLevel = 0;
|
|
static uint8_t battLastPercentageForLevel = 0;
|
|
|
|
//variables
|
|
static float battVoltageFullChargeMinimal = 14.4; //used for longevity charge
|
|
static float battVoltageFullChargeMaximal = 14.6; //3.60V - 3.65V * 4S = 14.4V - 14.6V (can be used for "topped-off" charge mode, )
|
|
static float battVoltageFullRest = 13.6; //~3.40V - 3.50V * 4S = ~13.6V - 13.7V (can be used for "optimal" charge mode, preferred for longevity)
|
|
static float battVoltageUpperZone = 13.3; //Also can be used for "Storage/Long-term Maintenance" charge mode, or after long usage without load ~13.2V - 13.3V (50-60% state of charge)
|
|
static float battVoltageLowerZone = 12.9;
|
|
//float battVoltageHalf = 13.1; //~3.25V - 3.28V * 4S = ~13.0V - 13.1V, known as nomimal
|
|
static float battVoltageEmpty = 10.0; //~2.50V - 2.80V * 4S = ~10.0V - 11.2V
|
|
static float battVoltageCritical = 12.0; //Default ~10% => 3.0V * 4S = 12V
|
|
static float battVoltageForceShutdown = 11.2; //Default ~5% => 2.8V * 4S = 11.2V
|
|
static float battVoltageResumeChargingDefault = 13.4; //Default ~90% = ~3.35V *4S = 13.4V
|
|
|
|
//error condition
|
|
static float battOverVoltage = 15.3; //3.75V - 3.80V * 4S = 15V - 15.3V
|
|
static float battVoltageDetected = 8;
|
|
static float battVoltageNotDetected = 7;
|
|
|
|
static void resetBatteryLevel() {
|
|
battLastLevel = 0;
|
|
battLastPercentageForLevel = 0;
|
|
}
|
|
|
|
static void setBatteryPercentage(uint8_t soc) {
|
|
if (soc <= 0) {
|
|
battLastLevel = 0;
|
|
battLastPercentageForLevel = 0;
|
|
return;
|
|
} else if (soc >= 100) {
|
|
battLastLevel = 4;
|
|
battLastPercentageForLevel = 100;
|
|
return;
|
|
}
|
|
|
|
if (soc > battLastPercentageForLevel) {
|
|
//charging
|
|
if (soc - battLastPercentageForLevel > battPercentageLevelThreshold) {
|
|
battLastPercentageForLevel = soc;
|
|
if (battLastPercentageForLevel > 75) {
|
|
battLastLevel = 4;
|
|
} else if (battLastPercentageForLevel > 50) {
|
|
battLastLevel = 3;
|
|
} else if (battLastPercentageForLevel > 25) {
|
|
battLastLevel = 2;
|
|
} else if (battLastPercentageForLevel > 10) {
|
|
battLastLevel = 1;
|
|
} else {
|
|
battLastLevel = 0;
|
|
}
|
|
}
|
|
} else {
|
|
//depleted or equal
|
|
if (battLastPercentageForLevel - soc > battPercentageLevelThreshold) {
|
|
battLastPercentageForLevel = soc;
|
|
if (battLastPercentageForLevel < 10) {
|
|
battLastLevel = 0;
|
|
} else if (battLastPercentageForLevel < 25) {
|
|
battLastLevel = 1;
|
|
} else if (battLastPercentageForLevel < 50) {
|
|
battLastLevel = 2;
|
|
} else if (battLastPercentageForLevel < 75) {
|
|
battLastLevel = 3;
|
|
} else {
|
|
battLastLevel = 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint8_t getBatteryPercentage(float voltage) {
|
|
float soc = 0;
|
|
if (voltage > battVoltageUpperZone) {
|
|
soc = 90.0 + (10.0 * ((voltage - battVoltageUpperZone) / (battVoltageFullRest - battVoltageUpperZone)));
|
|
if (soc > 100) soc = 100;
|
|
} else if (voltage > battVoltageLowerZone && voltage <= battVoltageUpperZone) {
|
|
soc = 20.0 + (70.0 * ((voltage - battVoltageLowerZone) / (battVoltageUpperZone - battVoltageLowerZone)));
|
|
} else if (voltage > battVoltageEmpty) {
|
|
soc = (20.0 * ((voltage - battVoltageEmpty) / (battVoltageLowerZone - battVoltageEmpty)));
|
|
}
|
|
setBatteryPercentage(soc);
|
|
return (uint8_t) soc;
|
|
}
|
|
|
|
static uint8_t getRawBatteryLevelFromPercentage(uint8_t soc) {
|
|
if (soc <= 0) {
|
|
return 0;
|
|
} else if (soc >= 100) {
|
|
return 4;
|
|
}
|
|
|
|
if (soc > 75) {
|
|
return 4;
|
|
} else if (soc > 50) {
|
|
return 3;
|
|
} else if (soc > 25) {
|
|
return 2;
|
|
} else if (soc > 5) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uint8_t getBatteryLevel() {
|
|
return battLastLevel;
|
|
}
|
|
|
|
static uint8_t getBatteryLevel(float voltage) {
|
|
getBatteryPercentage(voltage);
|
|
return battLastLevel;
|
|
}
|