604 lines
17 KiB
C
604 lines
17 KiB
C
/*
|
||
******************************************************************************
|
||
*
|
||
* @file bat.c
|
||
* @brief Voltage-based RC model gauge algorithm
|
||
* @ic sy8835
|
||
*
|
||
* @version 1.0
|
||
* @date 2024/11/01 17:35:40
|
||
* @author Alex Xu
|
||
*
|
||
* Copyright (c) 2013-2099,Tkplusemi Technology Co.,Ltd.
|
||
* All Rights Reserved
|
||
*
|
||
* History:
|
||
* Revision Date Author Desc
|
||
* 1.0.0 2024/11/01 Alex build this file
|
||
******************************************************************************
|
||
*/
|
||
#include "bat.h"
|
||
#include "adc.h"
|
||
#include "pmu.h"
|
||
|
||
idata uint8_t bat_level = 0;
|
||
idata uint8_t bat_level_Pec = 0;
|
||
|
||
bit F_batlevel_low = 0; //电池低压
|
||
|
||
#if 0
|
||
|
||
#if GAUGE_ENABLE
|
||
|
||
/******************************************************************************\
|
||
Macro definitions
|
||
\******************************************************************************/
|
||
|
||
/******************************************************************************\
|
||
Variables definitions
|
||
\******************************************************************************/
|
||
|
||
static idata const uint16 ocv_zero = 3200;
|
||
static idata const uint16 ocv_full = 4200;
|
||
static idata uint8 ocv_delta[20] = {255 ,93 ,24 ,48 ,38 ,41 ,34 ,30 ,33 ,40 ,48 ,66 ,84 ,78 ,74 ,79 ,82 ,85 ,86 ,85};
|
||
|
||
//带插值版的参数
|
||
static idata const uint16 kint_0deg[5] = { 25, 32, 31, 27, 24}; //初值,当小于0度时采用此值
|
||
|
||
static idata const uint8 Kint_soc0[6] = { 1, 22, 160, 255, 25, 20 }; //SOC=0~10%,不同温度Kint的delta值,每8度一个delta值*8,如第一个值代表0~7度,第二个值代表8~15度
|
||
static idata const uint8 Kint_soc1[6] = { 6, 0, 12, 110, 0, 0 }; //SOC=10~25%,不同温度Kint的delta值,每8度一个delta值*8,如第一个值代表0~7度,第二个值代表8~15度
|
||
static idata const uint8 Kint_soc2[6] = { 0, 10, 15, 40, 10, 0 }; //SOC=25~50%,不同温度Kint的delta值,每8度一个delta值*8,如第一个值代表0~7度,第二个值代表8~15度
|
||
static idata const uint8 Kint_soc3[6] = { 38, 18, 48, 160, 38, 29 }; //SOC=50~80%,不同温度Kint的delta值,每8度一个delta值*8,如第一个值代表0~7度,第二个值代表8~15度
|
||
static idata const uint8 Kint_soc4[6] = { 14, 45, 80, 210, 88, 29 }; //SOC=80~100%,不同温度Kint的delta值,每8度一个delta值*8,如第一个值代表0~7度,第二个值代表8~15度
|
||
|
||
//uint8 k_ratio_chg_fast[5];
|
||
//uint8 k_ratio_chg_norm[5];
|
||
|
||
static idata const uint8 k_ratio_chg_temp[7] = { 128, 54, 42, 32, 32, 46, 32 }; //20210304 充电kint各温度区间补偿系数
|
||
static idata const uint8 k_ratio_chg_temprange[6] = { 5, 10, 16, 35, 44, 55 }; //将温度划分成7个区间,默认为5度以下,5~9,10~14,15~34,35~44,45~55,55以上
|
||
|
||
//int8 fastchgth; //快充阈值,当充电电流大于这个阈值时,选择k_ratio_chg_fast,否则选择k_ratio_chg_norm
|
||
|
||
//高位开始代表从15度开始SOC值是否需要减1,如15度相比25度容量衰减超过1%,则bit15=1,然后14度和15度一样,则bit14=0,如果13度比15度容量小1%,则bit13=1,依次类推
|
||
//小于0度固定和0度补偿值一样,此方式最大补偿值为每1度补1%,16度以上不补偿
|
||
static idata uint16 c_delta = 0;
|
||
|
||
//用户写入参数
|
||
uint8 c_ratio_customer = 0; //客户参数区写入的值,客户预存各种场景容量损失,可以灵活补偿负载/温度/老化等多种场景
|
||
|
||
//电量计中间变量
|
||
static uint32 K_int = 0;
|
||
static uint16 OCV_int16 = 0;
|
||
static uint32 OCV_int32 = 0;
|
||
|
||
static uint8 SOC_int = 0; //直接从OCV表查表得到的SOC,(100-SOC_int)*Qmax为到充满需要的容量,SOC_int由于未补偿负载,除非常温和负载大小和建模一致否则放电使用此SOC会有误差
|
||
static int8 SOC_dsg = 0; //放电时使用的SOC,在不同温度下会有跳变,SOC_dsg=SOC_int-c_ratio_0deg/c_ratio_10deg
|
||
uint8 SOC_report = 0; //上报的SOC值,结合库仑计信息和SOC_int/SOC_dsg之间
|
||
|
||
//20210219 更新基于OCV的平滑算法
|
||
static uint16 OCV_deltahalf = 0; //用于追赶SOC的OCV累计溢出值,取各SOC 0.5%对应的OCV delta值
|
||
static uint8 OCV_count = 0; //计算当前和上次更新SOC_report的差值
|
||
static uint16 OCV_lastupdate = 0; //记录上次更新SOC_report的OCV值
|
||
|
||
|
||
/******************************************************************************\
|
||
Functions definitions
|
||
\******************************************************************************/
|
||
|
||
//20210304新增对于充电温度补偿
|
||
/*
|
||
*******************************************************************************
|
||
* static uint8 Kint_Rate_chg(int8 temperature_s)
|
||
*
|
||
* Description : 对充电温度进行补偿
|
||
|
||
* Arguments : NONE
|
||
|
||
* Returns : NONE
|
||
|
||
* Notes : NONE
|
||
*
|
||
*******************************************************************************
|
||
*/
|
||
static uint8 Kint_Rate_chg(int8 temperature_s)//查找不同温度下充电时Kint补偿系数
|
||
{
|
||
if(temperature_s > k_ratio_chg_temprange[5])
|
||
return k_ratio_chg_temp[6];
|
||
if(temperature_s > k_ratio_chg_temprange[4])
|
||
return k_ratio_chg_temp[5];
|
||
if(temperature_s > k_ratio_chg_temprange[3])
|
||
return k_ratio_chg_temp[4];
|
||
if(temperature_s > k_ratio_chg_temprange[2])
|
||
return k_ratio_chg_temp[3];
|
||
if(temperature_s > k_ratio_chg_temprange[1])
|
||
return k_ratio_chg_temp[2];
|
||
if(temperature_s > k_ratio_chg_temprange[0])
|
||
return k_ratio_chg_temp[1];
|
||
|
||
return k_ratio_chg_temp[0];
|
||
}
|
||
|
||
/*查表获得Kint值*/
|
||
/*
|
||
*******************************************************************************
|
||
* static uint16 Kint_Find_delta(int8 temperature_s)
|
||
*
|
||
* Description : 对充电温度进行补偿
|
||
|
||
* Arguments : NONE
|
||
|
||
* Returns : NONE
|
||
|
||
* Notes : NONE
|
||
*
|
||
*******************************************************************************
|
||
*/
|
||
static uint16 Kint_Find_delta(int8 temperature_s, uint8 current_s)
|
||
{
|
||
uint8 temprange,i,temperature_use,tempindex;
|
||
// uint16 Kint_chg_temp = 0;
|
||
uint32 Kintsum = 0;
|
||
// uint16 Kint_temp = 0;
|
||
|
||
if (temperature_s < 0)
|
||
temperature_use = 0;
|
||
else if (temperature_s > 47)
|
||
temperature_use = 47;
|
||
else
|
||
temperature_use = temperature_s; //温度限定在0~63度,超过63度或者低于0度则用63度和0度 temperature_s = 35
|
||
|
||
temprange = temperature_use >> 3; //找出温度区间 temperature_use/8 = 35/8 = 4 为何要用8取模和取余?Kinit表是以8度为一个区间取值
|
||
tempindex = temperature_use - (temprange << 3); //对温度取余,得到某个区间第几个温度值 temperature_use%8 = 35 % 8 = 3
|
||
|
||
if (SOC_int > 80)
|
||
{
|
||
for (i = temprange; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + (((uint32)Kint_soc4[i-1])<<3); //温度大于某个区间就从0区间到此区间的所有的delta值*8并累加,例如:35℃,所在温度区间为32~39℃,第四区间。
|
||
}
|
||
|
||
for (i = tempindex; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + ((uint32)Kint_soc4[temprange]); //将不足一个区间(0-8只间的值)数据按照加法累加,计算温度余数对应的kint累加值;例如:35℃,在温度区间余数为35-32=3℃。
|
||
}
|
||
Kintsum = Kintsum >> 3; //由于delta放大了8倍,这里要除以8
|
||
Kintsum = Kintsum + kint_0deg[4]; //得到此温度下的放电Kint值
|
||
}
|
||
else if (SOC_int > 50)
|
||
{
|
||
for (i = temprange; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + (((uint32)Kint_soc3[i-1]) << 3); //温度大于某个区间就将区间的delta值*8
|
||
|
||
}
|
||
for (i = tempindex; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + ((uint32)Kint_soc3[temprange]); //将不足一个区间(8个值)数据按照加法累加
|
||
|
||
}
|
||
Kintsum = Kintsum >> 3; //由于delta放大了8倍,这里要除以8
|
||
Kintsum = Kintsum + kint_0deg[3]; //得到此温度下的放电Kint值
|
||
}
|
||
|
||
else if (SOC_int > 25)
|
||
{
|
||
for (i = temprange; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + (((uint32)Kint_soc2[i-1]) << 3); //温度大于某个区间就将区间的delta值*8
|
||
|
||
}
|
||
for (i = tempindex; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + ((uint32)Kint_soc2[temprange]); //将不足一个区间(8个值)数据按照加法累加
|
||
|
||
}
|
||
Kintsum = Kintsum >> 3; //由于delta放大了8倍,这里要除以8
|
||
Kintsum = Kintsum + kint_0deg[2]; //得到此温度下的放电Kint值
|
||
}
|
||
|
||
else if (SOC_int > 10)
|
||
{
|
||
for (i = temprange; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + (((uint32)Kint_soc1[i-1] )<< 3); //温度大于某个区间就将区间的delta值*8
|
||
|
||
}
|
||
for (i = tempindex; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + ((uint32)Kint_soc1[temprange]); //将不足一个区间(8个值)数据按照加法累加
|
||
|
||
}
|
||
Kintsum = Kintsum >> 3; //由于delta放大了8倍,这里要除以8
|
||
Kintsum = Kintsum + kint_0deg[1]; //得到此温度下的放电Kint值
|
||
}
|
||
else
|
||
{
|
||
for (i = temprange; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + (((uint32)Kint_soc0[i-1]) << 3); //温度大于某个区间就将区间的delta值*8
|
||
|
||
}
|
||
for (i = tempindex; i > 0; i--)
|
||
{
|
||
Kintsum = Kintsum + ((uint32)Kint_soc0[temprange]); //将不足一个区间(8个值)数据按照加法累加
|
||
|
||
}
|
||
Kintsum = Kintsum >> 3; //由于delta放大了8倍,这里要除以8
|
||
Kintsum = Kintsum + kint_0deg[0]; //得到此温度下的放电Kint值
|
||
}
|
||
|
||
if(current_s > 0)
|
||
{
|
||
Kintsum = Kintsum * Kint_Rate_chg(temperature_s);
|
||
}
|
||
|
||
return (uint16)Kintsum;
|
||
}
|
||
|
||
//2023/2/17以上代码为通过查表找出随SOC,温度和充放电倍率变化的Kint值,可以根据需要适当减少数组数量,增加常温下不同SOC区间的Kint值以提高常温精度
|
||
//2023/2/17下面代码引入current_s标志位主要是为了解决没有充放电时SOC出现反弹的问题
|
||
//2023/2/17 如果对低温性能要求不高,可以删掉SOC_dsg,SOC_Dsg的只是单纯在SOC_int基础上低温时直接减去一个随温度变化的值SOC_dsg = SOC_int - c_ratio_customer;
|
||
//如果不对SOC_int做低温补偿就不会出现SOC_dsg这个值造成差异。那么这个代码就可以精简掉SOC_dsg
|
||
//这里代码还做了一个基于OCV_count的平滑,如果OCV差值只要超过0.5%(OCV_deltahalf),就允许快速平滑SOC。
|
||
//实际应用例子,因为我们的OCV-SOC_int表是基于常温的,假设某个OCV值下SOC_int=20%,但是目前是低温状态,查表得到c_ratio_customer=10%,那么SOC_dsg=10%。即实际当前是只有10%
|
||
//电量,但是SOC_int=20%,这时上报的SOC_report就要从初始的20%(=SOC_int)平滑到放电截止的时0%(SOC_dsg=0%,SOC_int=10%),因此SOC_report就要以2倍的速度下降,所以引入OCV_deltahalf
|
||
//但还有一种场景是在低温下SOC_report=SOC——dsg,但是此时恢复到常温,比如低温下SOC_report=SOC_dsg=10%,但是回到常温对应电量有20%,因此显示10%要更满速度到0%才能使电量充分放完
|
||
|
||
static void SOC_report_cal(uint8 current_s) //current_s在具体实现上用charger存在标志位取代即可
|
||
{
|
||
if(OCV_int16 > OCV_lastupdate) //取绝对值
|
||
OCV_count = OCV_int16 - OCV_lastupdate;
|
||
else
|
||
OCV_count = OCV_lastupdate - OCV_int16;
|
||
|
||
if (current_s > 0) //充电时,建议改成charger插入状态
|
||
{
|
||
if((SOC_int == 100) && (SOC_report < 100)) //如果SOC_int已经到达100%则SOC_report快速趋近100%
|
||
{
|
||
SOC_report++;
|
||
OCV_lastupdate = OCV_int16;
|
||
}
|
||
else if((OCV_count > OCV_deltahalf) && (SOC_int > SOC_report))
|
||
{
|
||
SOC_report++;
|
||
OCV_lastupdate = OCV_int16;
|
||
}
|
||
}
|
||
else //放电时
|
||
{
|
||
if((SOC_dsg == 0) && (SOC_report > 0)) //如果SOC_dsg已经到达0%则SOC_report快速趋近0%
|
||
{
|
||
SOC_report--;
|
||
OCV_lastupdate = OCV_int16;
|
||
}
|
||
else if((OCV_count > OCV_deltahalf) && (SOC_report > SOC_dsg))
|
||
{
|
||
SOC_report--;
|
||
OCV_lastupdate = OCV_int16;
|
||
}
|
||
else if((OCV_count > (OCV_deltahalf << 2)) && (SOC_report < SOC_dsg)) //OCV变化2%SOC对应的Delta允许变化1%
|
||
{
|
||
if(SOC_report > 0)
|
||
{
|
||
SOC_report--;
|
||
OCV_lastupdate = OCV_int16;
|
||
}
|
||
}
|
||
}
|
||
|
||
if(SOC_report == 100)
|
||
OCV_lastupdate = ocv_full;
|
||
if(SOC_report == 0)
|
||
OCV_lastupdate = ocv_zero;
|
||
|
||
bat_level = SOC_report;
|
||
}
|
||
|
||
|
||
//20210108更新版的SOC_dsg计算方法(计算出温度或者客户写入的容量损失后的容量)
|
||
//20210118修正代码中bug
|
||
static void SOC_dsg_cal(int8 temperature_s)
|
||
{
|
||
int8 i;
|
||
uint16 k;
|
||
|
||
SOC_dsg = SOC_int;//大于16度保持不变
|
||
|
||
if (temperature_s < 16)//低于16度做补偿,按位补偿相减
|
||
{
|
||
k = 0x8000;
|
||
for (i=16; i > temperature_s; i--)
|
||
{
|
||
if (c_delta & k)
|
||
SOC_dsg--;
|
||
k = k >> 1;
|
||
}
|
||
}
|
||
|
||
if (c_ratio_customer != 0)
|
||
{
|
||
SOC_dsg = SOC_int - c_ratio_customer;
|
||
}
|
||
if (SOC_dsg < 0)
|
||
SOC_dsg = 0;
|
||
}
|
||
|
||
//2023/2/17 查OCV表计算SOC_int
|
||
static uint8 SOCint_Calc(uint16 ocv)
|
||
{
|
||
uint8 i = 0;
|
||
uint8 k, j;
|
||
uint16 ocv_sum;
|
||
uint16 ocv_now;
|
||
|
||
ocv_now = (uint16)ocv << 3;
|
||
|
||
ocv_sum = ocv_zero << 3;
|
||
for (k = 0; k < 20; k++)
|
||
{
|
||
for (j = 0; j < 5; j++)
|
||
{
|
||
//2021/04/01 避免OCV=OCV_zero时SOC=1%而不是0%
|
||
if ((ocv_sum) >=(ocv_now))
|
||
goto Findsoc;
|
||
ocv_sum = ocv_sum + ocv_delta[k];
|
||
i++;
|
||
}
|
||
}
|
||
Findsoc:
|
||
//20210219
|
||
OCV_deltahalf = ocv_delta[k] >> 4;//OCV_deltahalf取0.5%对应的OCV差值(由于ocv_delta[k]为8倍的1%SOC OCV差值)
|
||
return i;
|
||
}
|
||
|
||
/*
|
||
*******************************************************************************
|
||
* void Gauge_Init(int vbat_init, int current_init, int temp_init)
|
||
*
|
||
* Description : Gauge Initialization
|
||
*
|
||
* Arguments :int vbat_init:Bat Adc Value
|
||
* int current_init:Charger Exist Flag
|
||
* int temp_init: Bat NTC Adc Value
|
||
*
|
||
* Returns :None
|
||
|
||
* Notes :
|
||
*
|
||
*******************************************************************************
|
||
*/
|
||
static void Gauge_Init(int vbat_init, uint8 current_init, int temp_init)
|
||
{
|
||
if (vbat_init < (ocv_zero))
|
||
{
|
||
OCV_int16 = (ocv_zero);
|
||
}
|
||
else if(vbat_init > (ocv_full))
|
||
{
|
||
OCV_int16 = (ocv_full);
|
||
}
|
||
else
|
||
OCV_int16 = vbat_init;
|
||
|
||
OCV_int32 = ((uint32)OCV_int16) << 16;
|
||
|
||
SOC_int = SOCint_Calc((uint16)(OCV_int32 >> 16));
|
||
|
||
SOC_dsg_cal((int8)temp_init);
|
||
|
||
//testdata = SOC_dsg;
|
||
SOC_report_cal(current_init);//平滑处理返回 平滑后的SOC值SOC_report
|
||
|
||
}
|
||
/*
|
||
*******************************************************************************
|
||
* void Gauge_Update(int vbat_new, int current_new, int temp_new)
|
||
*
|
||
* Description : Gauge Updata
|
||
*
|
||
* Arguments : int vbat_new:Bat Adc Value
|
||
int current_new:Charge Current
|
||
int temp_new:Bat NTC Value
|
||
|
||
* Returns : None
|
||
|
||
* Notes :
|
||
*
|
||
*******************************************************************************
|
||
*/
|
||
static void Gauge_Update(int vbat_new, uint8 current_new, int temp_new)
|
||
{
|
||
|
||
K_int = Kint_Find_delta((int8)temp_new,current_new);
|
||
|
||
OCV_int32 = OCV_int32 - (K_int * (OCV_int32 >> 16)) + (K_int * vbat_new);
|
||
|
||
OCV_int16 = (OCV_int32 >> 16);
|
||
if (OCV_int16 > (ocv_full))
|
||
{
|
||
OCV_int32 = ((uint32) ocv_full ) << 16;
|
||
}
|
||
if (OCV_int16 < (ocv_zero))
|
||
{
|
||
OCV_int32 = ((uint32) ocv_zero) << 16;
|
||
}
|
||
//20210401 增加 OCV_int16 = (OCV_int32 >> 16);避免没有及时更新OCV_int16
|
||
OCV_int16 = (OCV_int32 >> 16);
|
||
|
||
SOC_int = SOCint_Calc(OCV_int16);
|
||
|
||
SOC_dsg_cal((int8)temp_new);
|
||
|
||
SOC_report_cal(current_new);//平滑处理返回 平滑后的SOC值SOC_report
|
||
}
|
||
|
||
void Bat_Cal_Init(void)
|
||
{
|
||
uint8 Charger_On = 0;
|
||
uint8 Vbat_Init = 0;
|
||
uint16 Vbat_NTC_Value = 0;
|
||
|
||
Charger_On = CHIP_STA4 & 0x07;
|
||
#if ADC_ENABLE
|
||
Vbat_Init = Vbat_Adc; //获取Bat电压
|
||
Vbat_NTC_Value = Vntc_Adc;
|
||
#endif
|
||
Gauge_Init(Vbat_Init,Charger_On,Vbat_NTC_Value);
|
||
#ifdef _DEBUG_BAT
|
||
printf("Gauge Init!\r\n");
|
||
#endif
|
||
}
|
||
|
||
void Bat_Gauge_Handle(void)
|
||
{
|
||
uint8 Charger_On = 0;
|
||
uint8 Vbat_Adc_Value = 0;
|
||
uint16 Vbat_NTC_Value = 0;
|
||
|
||
Charger_On = CHIP_STA4 & 0x07;
|
||
#if ADC_ENABLE
|
||
Vbat_Adc_Value = Vbat_Adc; //获取Bat电压
|
||
Vbat_NTC_Value = Vntc_Adc;
|
||
#endif
|
||
Gauge_Update(Vbat_Adc_Value,Charger_On,Vbat_NTC_Value);
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
#else
|
||
|
||
//bit F_batlevel_low = 0; //电池低压
|
||
|
||
#if BAT_VALUE
|
||
|
||
#define C_offset_bat_level_MAX 150
|
||
#define C_offset_bat_level_MIN 10
|
||
|
||
#define C_bat_level_protect 0
|
||
#define C_bat_level_lowpower 1
|
||
|
||
|
||
bit F_batlevel_protect = 0; //低电保护
|
||
|
||
idata uint8_t offset_bat_level = ( C_offset_bat_level_MAX + C_offset_bat_level_MIN ) / 2;
|
||
|
||
|
||
#define C_batLevel_SetMax 20
|
||
|
||
/*充电电池电压会浮高,具体电压需要测试。*/
|
||
const uint16_t Boost_batlevel_Threshold[C_batLevel_SetMax] =
|
||
{
|
||
3000, //0%
|
||
3050, //5%
|
||
3100, //10%
|
||
3200, //15%
|
||
3250, //20%
|
||
3300, //25%
|
||
3350, //30%
|
||
3400, //4
|
||
3450,
|
||
3500, //5
|
||
3575,
|
||
3650, //6
|
||
3720,
|
||
3800, //7
|
||
3850,
|
||
3900, //8
|
||
3975,
|
||
4050, //9
|
||
4125,
|
||
4200 //10
|
||
};
|
||
#if 0
|
||
const uint16_t Charging_batlevel_Threshold1[C_batLevel_SetMax] =
|
||
{
|
||
3050, //1
|
||
3150, //2
|
||
3350, //3
|
||
3450, //4
|
||
3550, //5
|
||
3700, //6
|
||
3850, //7
|
||
3950, //8
|
||
4100, //9
|
||
4200 //10
|
||
};
|
||
#endif
|
||
void check_bat_level(void)
|
||
{
|
||
uint8_t i = 0;
|
||
//get bat level
|
||
#if ADC_ENABLE
|
||
for(i=0; i < C_batLevel_SetMax; i++)
|
||
{
|
||
#if 0
|
||
|
||
if( Vbat_Adc < Boost_batlevel_Threshold[i] )
|
||
{
|
||
break;
|
||
}
|
||
|
||
#else
|
||
if(ChgStatus == CHG_STA_ING) //充电
|
||
{
|
||
if( Vbat_Adc < Boost_batlevel_Threshold[i] + 50 )
|
||
break;
|
||
}
|
||
else //放电
|
||
{
|
||
if( Vbat_Adc < Boost_batlevel_Threshold[i] )
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
#endif
|
||
|
||
if( i > bat_level )
|
||
{
|
||
offset_bat_level++;
|
||
}
|
||
else
|
||
{
|
||
offset_bat_level--;
|
||
}
|
||
|
||
if( pmu_Info.pmu_Chip_STA & INIT_OK )
|
||
{
|
||
bat_level = i;
|
||
bat_level_Pec = 5 * bat_level;
|
||
}
|
||
|
||
//debounce
|
||
if( (offset_bat_level > C_offset_bat_level_MAX) || (offset_bat_level < C_offset_bat_level_MIN) )
|
||
{
|
||
//update
|
||
bat_level = i;
|
||
bat_level_Pec = 5 * bat_level;
|
||
offset_bat_level = ( C_offset_bat_level_MAX + C_offset_bat_level_MIN ) / 2;
|
||
}
|
||
#if 1
|
||
if( bat_level <= C_bat_level_protect )
|
||
{
|
||
F_batlevel_protect = 1;
|
||
}
|
||
else if( bat_level > ( C_bat_level_protect + 1 ) )
|
||
{
|
||
F_batlevel_protect = 0;
|
||
}
|
||
#endif
|
||
if( bat_level <= C_bat_level_lowpower )
|
||
{
|
||
F_batlevel_low = 1;
|
||
}
|
||
else if( bat_level > (C_bat_level_lowpower + 1) )
|
||
{
|
||
F_batlevel_low = 0;
|
||
}
|
||
}
|
||
|
||
#endif
|
||
#endif
|