/****************************************************************************** * * @file ah_counter.c * @author ECS, Falko Jahn * @version V1.0.0 * @date 2020-05-01 * @brief * ******************************************************************************/ // --- INCLUDES ----------------------------------------------------------------- #include "main.h" #include "math.h" #include "sysdata.h" #include "ah_counter.h" #include "wh_counter.h" #include "eeprom.h" // --- EXTERNE VARIABLEN -------------------------------------------------------- // --- LOKALE DEFINES - bitte hier dokumentieren -------------------------------- // --- LOKALE TYPE DEFS - bitte hier dokumentieren------------------------------- // --- DEFINITIONEN GLOBALER VARIABLEN - Bitte in Header dokumentieren ---------- // --- LOKALE VARIABLEN - bitte hier dokumentieren ------------------------------ int startMeasurement = 0; // --- LOKALE FUNKTIONS PROTOTYPEN ---------------------------------------------- int getSocAhRated(void); int getSocAhAuto(void); //int64_t mAs_AutoMode; void AH_COUNTER_Init(void) { sys_data.s.values.mAs_AutoMode = (int32_t)-sys_data.s.parameter.cellCapacity * 3600;; } // --- LOKALE FUNKTIONEN - bitte hier dokumentieren ----------------------------- int getSocAhRated(void) { int64_t cellCapacitySeconds = (int64_t)sys_data.s.parameter.cellCapacity * 60 * 60; // Umrechnung mAh zu mAs return (100000 * sys_data.s.values.mAsCounter) / cellCapacitySeconds; } int getSocAhAuto(void) { const int64_t _100mPercent = 100000LL; int64_t mAh_AutoMode = sys_data.s.values.mAh_AutoMode < 0 ? -sys_data.s.values.mAh_AutoMode : 0; int64_t tmp = 0LL; if (sys_data.s.values.detectedCapacity <= 0) { tmp = _100mPercent - (mAh_AutoMode * _100mPercent) / (int64_t)sys_data.s.parameter.cellCapacity; } else { tmp = _100mPercent - (mAh_AutoMode * _100mPercent) / (int64_t)sys_data.s.values.detectedCapacity; } if (tmp > _100mPercent) tmp = _100mPercent; else if (tmp <= 0) tmp = 0LL; return tmp; } // --- GLOBALE FUNKTIONEN - bitte in Header dokumentieren------------------------ void AH_COUNTER_Exec(void) { double iBatDivIbatNenn = 0; double current = 0; double peukert = 0; double calcPow = 0; double cef = 0; double soc = 0; int64_t maxCurrentForBatteryFullDetection = 0; static int16_t batteryFullCounter = 0; static uint64_t totalDischarge = 0; static uint64_t totalCharge = 0; int64_t cellCapacitySeconds = (int64_t)sys_data.s.parameter.cellCapacity * 60 * 60; // Umrechnung mAh zu mAs if (totalDischarge == 0) totalDischarge = sys_data.s.values.dischargeTotalAh * 3600000; if (totalCharge == 0) totalCharge = sys_data.s.values.chargeTotalAh * 3600000; // bei Strom größer 0 -> Ladestrom CEF rechnen if(sys_data.s.values.batteryCurrent >= 0) { //99 --> 99% --> 0.99 cef = sys_data.s.parameter.cef / 100.0; sys_data.s.values.batteryCurrentCorrected = sys_data.s.values.batteryCurrent * cef; } else { // bei Strom kleiner 0 peukert rechnen //int32_t ratedCurrent = sys_data.s.parameter.cellRatedCurrent * 1000; int32_t ratedCurrent = sys_data.s.parameter.cellCapacity / sys_data.s.parameter.cellRatedDischargeTime; if (sys_data.s.values.batteryCurrent < -ratedCurrent) //ACHTUNG mit Minus das vorzeichen gedreht! { current = sys_data.s.values.batteryCurrent; iBatDivIbatNenn = current / ratedCurrent; iBatDivIbatNenn = -iBatDivIbatNenn; peukert = (sys_data.s.parameter.peukert / 100.0); calcPow = pow(iBatDivIbatNenn , peukert - 1.0); sys_data.s.values.batteryCurrentCorrected = (current * calcPow); } else sys_data.s.values.batteryCurrentCorrected = sys_data.s.values.batteryCurrent; } sys_data.s.values.batteryCurrentCorrected -= (int32_t)sys_data.s.parameter.extraDischargeStrom_mA; // Counting negative current if (sys_data.s.values.batteryCurrent < 0) { totalDischarge += -sys_data.s.values.batteryCurrent; sys_data.s.values.dischargeTotalAh = totalDischarge / 3600000; //Umrechnung von mAs auf Ah sys_data.s.values.fullCyclesCnt = (uint16_t) ((sys_data.s.values.dischargeTotalAh * 1000) / sys_data.s.parameter.cellCapacity); } else { totalCharge += sys_data.s.values.batteryCurrent; sys_data.s.values.chargeTotalAh = totalCharge / 3600000; //Umrechnung von mAs auf Ah } // Aufsummieren sys_data.s.values.mAsCounter += sys_data.s.values.batteryCurrentCorrected; sys_data.s.values.mAs_AutoMode += (int64_t)sys_data.s.values.batteryCurrentCorrected; sys_data.s.values.mAh_AutoMode = sys_data.s.values.mAs_AutoMode / 3600LL; // Begrenzen, Batterie darf nicht über 100% gehen if (sys_data.s.values.mAsCounter > cellCapacitySeconds) sys_data.s.values.mAsCounter = cellCapacitySeconds; if (sys_data.s.values.mAs_AutoMode > 0) { sys_data.s.values.mAs_AutoMode = 0; } //Prüfe Battery Voll Bedinungen maxCurrentForBatteryFullDetection = sys_data.s.parameter.cellCapacity * sys_data.s.parameter.iBatFull / 100.0; if (sys_data.s.values.batteryVoltage > sys_data.s.parameter.uBatFull && sys_data.s.values.batteryCurrent < maxCurrentForBatteryFullDetection) { batteryFullCounter++; } else { batteryFullCounter = 0; } if (batteryFullCounter > sys_data.s.parameter.tBatFull) { sys_data.s.values.mAsCounter = cellCapacitySeconds; sys_data.s.values.mAs_AutoMode = 0; // Here we can set Wh to max WH_COUNTER_SetToMax(); //und wir starten eine neue Battery Kapazitäts und Energiemessung startMeasurement = 1; } sys_data.s.values.mAhCounter = sys_data.s.values.mAsCounter / 3600LL; static uint16_t lowVoltageCnt; if (sys_data.s.values.batteryVoltage < sys_data.s.values.uBatEmptyTempComp && sys_data.s.values.batteryVoltage > 1000) { lowVoltageCnt++; if ((lowVoltageCnt >= 10) && (startMeasurement == 1)) // 5 Sekunden fest { lowVoltageCnt = 10; //sys_data.s.parameter.tBatFull; if ((sys_data.s.values.lastTimeVbatFull >= 3600U) && (sys_data.s.values.lastTimeVbatFull <= 200U * 3600U)) // This line prevents from very high discharge-currents to be used to estimate battery capacity { // This line is not so important anymore, because we do not allow mAh_AutoMode to be greater than zero sys_data.s.values.detectedCapacity = sys_data.s.values.mAh_AutoMode >= 0 ? sys_data.s.values.mAh_AutoMode : -sys_data.s.values.mAh_AutoMode; WH_COUNTER_SetDetectedEnergy(); startMeasurement = 0; EEPROM_storeConfig(&sys_data, 0); // Saving detected values } sys_data.s.values.lastTimeVbatEmpty = 0U; } } else lowVoltageCnt = 0; switch (sys_data.s.parameter.socCalcMode) { case SOC_CALC_MODE_AH_RATED: sys_data.s.values.soc = getSocAhRated(); break; case SOC_CALC_MODE_AH_AUTO: sys_data.s.values.soc = getSocAhAuto(); break; case SOC_CALC_MODE_WH_RATED: sys_data.s.values.soc = WH_COUNTER_GetSoCManual(); break; case SOC_CALC_MODE_WH_AUTO: sys_data.s.values.soc = WH_COUNTER_GetSoCAuto(); break; case SOC_CALC_MODE_WH_AUTO_TEMP: sys_data.s.values.soc = WH_COUNTER_GetSoCAutoTemp(); break; default: sys_data.s.values.soc = 0; } }