228 lines
8.8 KiB
C
228 lines
8.8 KiB
C
/*
|
||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||
|
||
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||
|
||
The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "modStateOfCharge.h"
|
||
#include "main.h"
|
||
|
||
modStateOfChargeStructTypeDef modStateOfChargeGeneralStateOfCharge;
|
||
modPowerElectronicsPackStateTypedef *modStateOfChargePackStatehandle;
|
||
modConfigGeneralConfigStructTypedef *modStateOfChargeGeneralConfigHandle;
|
||
uint32_t modStateOfChargeLargeCoulombTick;
|
||
uint32_t modStateOfChargeStoreSoCTick;
|
||
|
||
bool modStateOfChargePowerDownSavedFlag = false;
|
||
|
||
modStateOfChargeStructTypeDef* modStateOfChargeInit(modPowerElectronicsPackStateTypedef *packState, modConfigGeneralConfigStructTypedef *generalConfigPointer){
|
||
modStateOfChargePackStatehandle = packState;
|
||
modStateOfChargeGeneralConfigHandle = generalConfigPointer;
|
||
driverSWStorageManagerStateOfChargeStructSize = (sizeof(modStateOfChargeStructTypeDef)/sizeof(uint16_t)); // Calculate the space needed for the config struct in EEPROM
|
||
|
||
modStateOfChargeLargeCoulombTick = HAL_GetTick();
|
||
modStateOfChargeStoreSoCTick = HAL_GetTick();
|
||
|
||
return &modStateOfChargeGeneralStateOfCharge;
|
||
};
|
||
|
||
float real_capacity = 0;
|
||
float previous_capacity = 0;
|
||
float previous_SoC = 0;
|
||
//static float current_SoC = 0;
|
||
float soc_diff = 0;
|
||
float capacity_diff = 0;
|
||
uint8_t SoC_Save_Flag = 0;
|
||
|
||
void modStateOfChargeProcess(void){
|
||
// Calculate accumulated energy
|
||
uint32_t dt = HAL_GetTick() - modStateOfChargeLargeCoulombTick;
|
||
|
||
static float lastsaved_remainingCapacityAh = 0;
|
||
modStateOfChargeStructTypeDef lastGeneralStateOfCharge;
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
* <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> = <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
* soc = <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> / <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> * 100
|
||
*
|
||
* <20> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> 1% (<28><>)
|
||
* b - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> 5% (<28><>) ( x amp - 5%
|
||
* y amp - 100%; y = 100x/5
|
||
*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> = ( 100 * <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> ) / <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
* 100 * 2 /1 = 200
|
||
*
|
||
* *
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1%, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1,4<><34><EFBFBD>
|
||
* <20><> = (100 * 1.4) / 1 = 140 <20><><EFBFBD>
|
||
*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1%, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 2,8<><38><EFBFBD>
|
||
* (100 * 2,8) /1 = 280 <20><><EFBFBD>
|
||
*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 2%, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1,4
|
||
* (100 * 1.4) /2 70 <20><><EFBFBD>
|
||
*
|
||
*
|
||
*
|
||
* soh
|
||
*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 150, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1,5, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 99%
|
||
*
|
||
*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
* soh = <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
* soc =
|
||
*
|
||
*
|
||
*/
|
||
|
||
lastGeneralStateOfCharge = modStateOfChargeGeneralStateOfCharge;
|
||
|
||
modStateOfChargeLargeCoulombTick = HAL_GetTick();
|
||
// calc in Ahmps how much we put or take
|
||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh += dt*modStateOfChargePackStatehandle->packCurrent/(3600*1000);// (miliseconds * amps)/(3600*1000) accumulatedCharge in AmpHour.
|
||
|
||
// Cap the max stored energy to the configured battery capacity.
|
||
// if we put more than battery is, set maximum
|
||
if(modStateOfChargeGeneralStateOfCharge.remainingCapacityAh > modStateOfChargeGeneralConfigHandle->batteryCapacity)
|
||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
|
||
|
||
// if we take more than battery, set zero
|
||
if(modStateOfChargeGeneralStateOfCharge.remainingCapacityAh < 0.0f)
|
||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = 0.0f;
|
||
|
||
// Calculate state of charge
|
||
// calc percent of we put/take to battery capacity
|
||
modStateOfChargeGeneralStateOfCharge.generalStateOfCharge =
|
||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh / modStateOfChargeGeneralConfigHandle->batteryCapacity * 100.0f;
|
||
|
||
if(SoC_Save_Flag == 0) {
|
||
previous_SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||
previous_capacity = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||
|
||
SoC_Save_Flag = 1;
|
||
}
|
||
|
||
if(previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge > 1) {
|
||
soc_diff = previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||
//
|
||
if(soc_diff == 0) soc_diff = 1;
|
||
capacity_diff = previous_capacity - modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||
real_capacity = (100 * capacity_diff) / soc_diff;
|
||
|
||
export_real_capacity = real_capacity;
|
||
|
||
previous_SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||
previous_capacity = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||
|
||
//SoC_Save_Flag = 0;
|
||
|
||
} //else if (previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge < -1) {
|
||
// SoC_Save_Flag = 0;
|
||
//}
|
||
|
||
|
||
|
||
// if we have more than 100% it is 100%
|
||
if(modStateOfChargeGeneralStateOfCharge.generalStateOfCharge >= 100.0f)
|
||
modStateOfChargeGeneralStateOfCharge.generalStateOfCharge = 100.0f;
|
||
|
||
// save soc and amps
|
||
modStateOfChargePackStatehandle->SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||
modStateOfChargePackStatehandle->SoCCapacityAh = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||
|
||
// Store SoC every 'stateOfChargeStoreInterval'
|
||
|
||
modStateOfChargeGeneralConfigHandle->stateOfChargeStoreInterval = 10000;
|
||
|
||
|
||
|
||
if(modDelayTick1ms(&modStateOfChargeStoreSoCTick,modStateOfChargeGeneralConfigHandle->stateOfChargeStoreInterval) &&
|
||
(lastsaved_remainingCapacityAh != modStateOfChargeGeneralStateOfCharge.remainingCapacityAh)) {
|
||
lastsaved_remainingCapacityAh = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||
modStateOfChargeStoreStateOfCharge();
|
||
}
|
||
|
||
|
||
};
|
||
|
||
bool modStateOfChargeStoreAndLoadDefaultStateOfCharge(void){
|
||
bool returnVal = false;
|
||
if(driverSWStorageManagerStateOfChargeEmpty){
|
||
// TODO: SoC manager is empy -> Determin SoC from voltage when voltages are available.
|
||
modStateOfChargeStructTypeDef defaultStateOfCharge;
|
||
defaultStateOfCharge.generalStateOfCharge = 100.0f;
|
||
defaultStateOfCharge.generalStateOfHealth = 100.0f;
|
||
defaultStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
|
||
defaultStateOfCharge.remainingCapacityWh = 0.0f;
|
||
|
||
driverSWStorageManagerStateOfChargeEmpty = false;
|
||
driverSWStorageManagerStoreStruct(&defaultStateOfCharge,STORAGE_STATEOFCHARGE);
|
||
// TODO_EEPROM
|
||
}
|
||
|
||
modStateOfChargeStructTypeDef tempStateOfCharge;
|
||
driverSWStorageManagerGetStruct(&tempStateOfCharge,STORAGE_STATEOFCHARGE);
|
||
|
||
modStateOfChargeLoadStateOfCharge();
|
||
return returnVal;
|
||
};
|
||
|
||
bool modStateOfChargeStoreStateOfCharge(void){
|
||
HAL_GPIO_TogglePin(HL2_GPIO_Port, HL2_Pin);
|
||
return driverSWStorageManagerStoreStruct(&modStateOfChargeGeneralStateOfCharge,STORAGE_STATEOFCHARGE);
|
||
};
|
||
|
||
bool modStateOfChargeLoadStateOfCharge(void){
|
||
return driverSWStorageManagerGetStruct(&modStateOfChargeGeneralStateOfCharge,STORAGE_STATEOFCHARGE);
|
||
};
|
||
|
||
bool modStateOfChargePowerDownSave(void) {
|
||
// if(!modStateOfChargePowerDownSavedFlag) {
|
||
// modStateOfChargePowerDownSavedFlag = true;
|
||
// modStateOfChargeStoreStateOfCharge();
|
||
// // TODO_EEPROM
|
||
// return true;
|
||
// }else
|
||
// return false;
|
||
};
|
||
|
||
void modStateOfChargeVoltageEvent(modStateOfChargeVoltageEventTypeDef eventType) {
|
||
switch(eventType) {
|
||
case EVENT_EMPTY:
|
||
break;
|
||
case EVENT_FULL:
|
||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
};
|