BMS STM32 V4.0.0.0
This commit is contained in:
+273
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file OCV.c
|
||||
* @author
|
||||
* @version
|
||||
* @date
|
||||
* @brief
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f10x.h"
|
||||
#include "global.h"
|
||||
|
||||
uint8_t OCV_soc; //通过OCV曲线获得的soc值
|
||||
uint8_t OCV_status; //定时校准的当前状态,0:刚开机要获取存储时间 1:符合条件正在计时 2:不在静置 3:不允许OCV校准
|
||||
uint8_t OCV_Wait_flag; //允许OCV校准走倒计时的标志
|
||||
uint8_t OCV_CaliSOC_flag; //允许执行OCV校准获取当前电压对应soc的标志
|
||||
|
||||
uint16_t OCV_WrTime_count; //在非待机状态下,每过30min记录一次,防止关机时未回到待机状态导致不可用
|
||||
|
||||
OCV_Data ocv_data[15]; //OCV曲线数组
|
||||
uint16_t ocv_Media_dp[15]; //根据写入数据获得中间值
|
||||
|
||||
|
||||
//根据paraMem值,填充ocv_data[]和ocv_Media_dp[]
|
||||
void OCV_CaliSOC_DataWr(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
//填充SOC,共15个点
|
||||
ocv_data[0].soc = 0;
|
||||
ocv_data[1].soc = 5;
|
||||
ocv_data[2].soc = 10;
|
||||
ocv_data[3].soc = 15;
|
||||
ocv_data[4].soc = 20;
|
||||
ocv_data[5].soc = 30;
|
||||
ocv_data[6].soc = 40;
|
||||
ocv_data[7].soc = 50;
|
||||
ocv_data[8].soc = 60;
|
||||
ocv_data[9].soc = 70;
|
||||
ocv_data[10].soc = 80;
|
||||
ocv_data[11].soc = 85;
|
||||
ocv_data[12].soc = 90;
|
||||
ocv_data[13].soc = 95;
|
||||
ocv_data[14].soc = 100;
|
||||
|
||||
//填充电压,共15个点
|
||||
for(i=0;i<15;i++)
|
||||
{
|
||||
//ocv_data[i].ocv_cp = paraMem.ocv_cpBuf[i] * bmsMem.ucCellNum;
|
||||
ocv_data[i].ocv_dp = paraMem.ocv_dpBuf[i] * bmsMem.ucCellNum;
|
||||
}
|
||||
|
||||
//赋值中间量,共14个点
|
||||
for(i=0;i<=13;i++)
|
||||
{
|
||||
ocv_Media_dp[i] = (ocv_data[i].ocv_dp + ocv_data[i+1].ocv_dp) / 2;
|
||||
}
|
||||
//50%-90%之间不考虑
|
||||
ocv_Media_dp[7] = ocv_data[7].ocv_dp; //低于50%对应基准值,校准50%
|
||||
ocv_Media_dp[11] = ocv_data[12].ocv_dp; //高于90%对应基准值,校准90%
|
||||
}
|
||||
|
||||
//计算OCV表格的dp里,当前总电压对应的SOC
|
||||
uint8_t OCV_CaliSoc_dp(void)
|
||||
{
|
||||
uint16_t caliSoc = 0;
|
||||
|
||||
//对总电压求出对应SOC
|
||||
if(bmsMem.packVoltage >= ocv_Media_dp[13]) //超过最大值认为是满电
|
||||
{
|
||||
caliSoc = 100;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[13]) && (bmsMem.packVoltage >= ocv_Media_dp[12]))
|
||||
{
|
||||
caliSoc = 95;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[12]) && (bmsMem.packVoltage >= ocv_Media_dp[11]))
|
||||
{
|
||||
caliSoc = 90;
|
||||
}
|
||||
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[11]) && (bmsMem.packVoltage > ocv_Media_dp[7]))
|
||||
{
|
||||
//当电压在>50%、<90%的电压值内时,若实时SOC不在范围内,则校准到50%/90%,否则不校准
|
||||
if(bmsMem.soc > 90)
|
||||
{
|
||||
caliSoc = 90;
|
||||
}
|
||||
else if(bmsMem.soc < 50)
|
||||
{
|
||||
caliSoc = 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
caliSoc = bmsMem.soc; //等于当前值,使不会校准
|
||||
}
|
||||
}
|
||||
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[7]) && (bmsMem.packVoltage >= ocv_Media_dp[6]))
|
||||
{
|
||||
caliSoc = 50;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[6]) && (bmsMem.packVoltage >= ocv_Media_dp[5]))
|
||||
{
|
||||
caliSoc = 40;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[5]) && (bmsMem.packVoltage >= ocv_Media_dp[4]))
|
||||
{
|
||||
caliSoc = 30;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[4]) && (bmsMem.packVoltage >= ocv_Media_dp[3]))
|
||||
{
|
||||
caliSoc = 20;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[3]) && (bmsMem.packVoltage >= ocv_Media_dp[2]))
|
||||
{
|
||||
caliSoc = 15;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[2]) && (bmsMem.packVoltage >= ocv_Media_dp[1]))
|
||||
{
|
||||
caliSoc = 10;
|
||||
}
|
||||
else if((bmsMem.packVoltage < ocv_Media_dp[1]) && (bmsMem.packVoltage >= ocv_Media_dp[0]))
|
||||
{
|
||||
caliSoc = 5;
|
||||
}
|
||||
else if(bmsMem.packVoltage <= ocv_Media_dp[0]) //小于最小值认为是空电
|
||||
{
|
||||
caliSoc = 0;
|
||||
}
|
||||
|
||||
return caliSoc;
|
||||
}
|
||||
|
||||
//在RTC有效+允许执行校准倒计时+满足静置时间时,获取开路电压法对应soc
|
||||
//在电芯温度合适+原SOC不靠谱时,将该soc写入
|
||||
//执行校准后,刷新计时起点,重新等待30min后再次执行校准
|
||||
void OCV_CaliSOC(void)
|
||||
{
|
||||
uint8_t tempEE[4]; //用于保存计时起点
|
||||
|
||||
if((LSEErrFlag == 0) && ((paraMem.ocv_min_disable & 0x8000) == 0)) //RTC有效,且允许开路电压校准SOC
|
||||
{
|
||||
//静置状态,对应OCV_status为1
|
||||
if((bmsMem.packCurrent > (-500)) && (bmsMem.packCurrent < 500))
|
||||
{
|
||||
//刚开机,读取存在EEPROM的时间
|
||||
if(OCV_status == 0)
|
||||
{
|
||||
OCV_status = 1;
|
||||
OCV_Wait_flag = 1; //允许在rtc函数中进行时间判断
|
||||
|
||||
EEPROM_RdMulByte(EE_TIME_OCV, tempEE);
|
||||
ocvtimecount = tempEE[0]<<24 | tempEE[1]<<16 | tempEE[2]<<8 | tempEE[3];
|
||||
|
||||
if(ocvtimecount > timecount) //存的数据异常
|
||||
{
|
||||
//更新计时起点
|
||||
ocvtimecount = RTC_GetCounter();
|
||||
|
||||
//保存到EEPROM
|
||||
tempEE[0] = (ocvtimecount >> 24) & 0xff;
|
||||
tempEE[1] = (ocvtimecount >> 16) & 0xff;
|
||||
tempEE[2] = (ocvtimecount >> 8) & 0xff;
|
||||
tempEE[3] = (ocvtimecount >> 0) & 0xff;
|
||||
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
|
||||
delay_ms(10);
|
||||
}
|
||||
}
|
||||
//从其他状态回来/从不允许改为允许,更新当前时间为计时起点
|
||||
else if(OCV_status != 1)
|
||||
{
|
||||
OCV_status = 1;
|
||||
OCV_Wait_flag = 1; //允许在rtc函数中进行时间判断
|
||||
|
||||
//更新计时起点
|
||||
ocvtimecount = RTC_GetCounter();
|
||||
|
||||
//保存到EEPROM
|
||||
tempEE[0] = (ocvtimecount >> 24) & 0xff;
|
||||
tempEE[1] = (ocvtimecount >> 16) & 0xff;
|
||||
tempEE[2] = (ocvtimecount >> 8) & 0xff;
|
||||
tempEE[3] = (ocvtimecount >> 0) & 0xff;
|
||||
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
|
||||
delay_ms(10);
|
||||
}
|
||||
|
||||
//当倒计时结束,校准SOC并更新计时起点
|
||||
if((OCV_Wait_flag == 1) && (OCV_CaliSOC_flag == 1))
|
||||
{
|
||||
//准备下一次计时
|
||||
OCV_CaliSOC_flag = 0;
|
||||
ocvtimecount = RTC_GetCounter();
|
||||
|
||||
//保存到EEPROM
|
||||
tempEE[0] = (ocvtimecount >> 24) & 0xff;
|
||||
tempEE[1] = (ocvtimecount >> 16) & 0xff;
|
||||
tempEE[2] = (ocvtimecount >> 8) & 0xff;
|
||||
tempEE[3] = (ocvtimecount >> 0) & 0xff;
|
||||
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
|
||||
delay_ms(10);
|
||||
|
||||
//更新OCV中值表
|
||||
OCV_CaliSOC_DataWr();
|
||||
|
||||
//获取校准SOC
|
||||
OCV_soc = OCV_CaliSoc_dp();
|
||||
|
||||
if((OCV_soc == 0) && ((bmsMem.packVoltage == 0) || (bmsMem.packVoltage > ocv_data[0].ocv_dp))) //电压异常改0% or 电压正常但计算得0% = 不执行
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if(OCV_soc < bmsMem.soc-paraMem.ocv_soc_Range) //只减不增
|
||||
{
|
||||
//若温度和原值差距过大则不替换
|
||||
if((TemperatureAverage > 250+2731-paraMem.ocv_T_Range*10) && (TemperatureAverage < 250+2731+paraMem.ocv_T_Range*10))
|
||||
{
|
||||
bmsMem.soc = OCV_soc;
|
||||
bmsMem.rcc = fcc/100 * bmsMem.soc;
|
||||
|
||||
rcc_Ah = fcc_Ah * bmsMem.soc /100;
|
||||
oldrcc_Ah = rcc_Ah;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OCV_WrTime_count = 0;
|
||||
}
|
||||
//不在静置状态,对应OCV_status为2
|
||||
else
|
||||
{
|
||||
OCV_status = 2;
|
||||
|
||||
//清除标志位
|
||||
OCV_Wait_flag = 0;
|
||||
OCV_CaliSOC_flag = 0;
|
||||
|
||||
//非静置状态,每隔30min记录一次计时起点,防止突然断电,导致倒计时偏差过大
|
||||
//此值在带电流重启后立刻静置的条件下启用
|
||||
OCV_WrTime_count++;
|
||||
if(OCV_WrTime_count > 60*30) //等30min
|
||||
{
|
||||
OCV_WrTime_count = 0;
|
||||
ocvtimecount = RTC_GetCounter();
|
||||
|
||||
//保存到EEPROM
|
||||
tempEE[0] = (ocvtimecount >> 24) & 0xff;
|
||||
tempEE[1] = (ocvtimecount >> 16) & 0xff;
|
||||
tempEE[2] = (ocvtimecount >> 8) & 0xff;
|
||||
tempEE[3] = (ocvtimecount >> 0) & 0xff;
|
||||
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
|
||||
delay_ms(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
//关闭开路电压法,对应OCV_status为3
|
||||
else
|
||||
{
|
||||
OCV_status = 3;
|
||||
|
||||
//清除倒计时和标志位
|
||||
ocvtimecount = 0;
|
||||
OCV_Wait_flag = 0;
|
||||
OCV_CaliSOC_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user