软件系统性电池充放电百分比计算(电量百分比)

一、说明

本文讲述锂电池在系统中进行充放电过程中进行电量百分比计算,仅供参考,电池电量百分比计算相对于来说是略微复杂,不仅需要分压电路并且还需要根据电池电压的大小来进行分级,因此除去最基础的ADC驱动(不同平台配置不同),整个充放电系统流程都有涉及到。

二、电路

1.电池电压检测电路

在电量百分比计算中,硬件电路尤为重要,简单来说就是对电池进行分压,运用串联电阻分压的特性,防止电压超过最高电压烧坏MCU的情况出现,检测电池电压。

2.充电电压检测电路

检测充电电压。

3.充电电流检测电路

检测充电电流电压。

三、软件计算

1ADC采集

建议使用DMA进行读取,这里从获取ADC的数据开始,再划出ADC缓存区,根据不同的采集通道来存放各自的数据。

//放置在.h文件

#define ADC_BUFFER_LEN       10       //ADC单个通道缓存区大小
#define ADC_CHANNEL_NUM      4        //ADC通道总数
#define ADC_BATTERY_VOLTAGE  0
#define ADC_BATTERY_NTC      1
#define ADC_CHARGE_VOLTAGE   2
#define ADC_CHARGE_CURRENT   3

/*定义ADC数据的结构体*/
struct ADC_Sample{
    uint16_t buffer[ADC_BUFFER_LEN];
    uint8_t size;
    uint8_t index;
};

/*定义ADC通道枚举*/
enum{
    BATTERY_VOLTAGE=0,
    BATTERY_NTC,
    CHARGE_VOLTAGE,
    CHARGE_CURRENT,
};

uint16_t ADC_GetValue(uint8_t channel);
void Buffer_fill(struct ADC_Sample *channel,uint16_t data);
void Range_Updata(void);



//放置在.c文件

struct ADC_Sample ADC_buffer_fill[ADC_CHANNEL_NUM];

/*获取ADC相对应的通道数据*/
uint16_t ADC_GetValue(uint8_t channel){
    if(channel >= ADC_CHANNEL_NUM){
        return 0;
    }
    return ADC_Buffer[channel];
}

/*ADC缓存区循环填充*/
void Buffer_fill(struct ADC_Sample *channel,uint16_t data){
    channel->buffer[channel->index] = data;
    channel->index++;
    if(channel->index >= CURRENT_BUFFER_LEN){
        channel->index = 0;
    }
}

/*更新ADC采样值*/
void Range_Updata(void)//需要在定时器进行中断更新
{
    Buffer_fill(&ADC_buffer_fill[BATTERY_VOLTAGE],ADC_GetValue(ADC_BATTERY_VOLTAGE));
    Buffer_fill(&ADC_buffer_fill[BATTERY_NTC],ADC_GetValue(ADC_BATTERY_NTC));
    Buffer_fill(&ADC_buffer_fill[CHARGE_VOLTAGE],ADC_GetValue(ADC_CHARGE_VOLTAGE));
	Buffer_fill(&ADC_buffer_fill[CHARGE_CURRENT],ADC_GetValue(ADC_CHARGE_CURRENT));
}

2.采集电池电压

电池采集的数据为电压类,因此采用电压类的ADC转换

/*获取电压类ADC*/
uint16_t Get_Voltage(uint8_t channle){
    struct ADC_Sample *adc_dev = &vol_buffer[channle];
    uint32_t temp = 0;
	  int i = 0;
	
    for (; i < CURRENT_BUFFER_LEN; i++) {
        temp += adc_dev->buffer[i];
    }
		
    return temp/CURRENT_BUFFER_LEN;
}

/*获取电池电压*/
float Get_BatteryVol(void)
{
    return (float)Get_Voltage(BATTERY_VOLTAGE) / 4096.0f * 3.3f * xxx;//xxx为分压转换系数
}

3采集充电电压

同上

/*获取充电电压 */
float Get_ChargeVol(void)
{
    return (float)Get_Vol(VOL_CHARGE) / 4096.0f * 3.3f * xxx;//xxx为分压转换系数
}

4.采集充电电流

电流类相较于电压类是需要进行转换的,因此充电电流采取电流类转换

/*充电电流电流类*/
uint16_t Get_Current(uint8_t channle){
    struct ADC_Sample *adc_dev = &current_buffer[channle];
    uint32_t temp = 0;
	  int i = 0;
	  uint16_t current;
    for (; i < CURRENT_BUFFER_LEN; i++) {
        temp += adc_dev->buffer[i];
    }
    temp/=CURRENT_BUFFER_LEN;
    current = temp * 3300 / 4096 * 10;
		
    return current;
}

/*当前充电电流*/
uint16_t Get_ChargeCurrent(void)
{
	uint16_t current_I;
    current_I  = (uint16_t)(Get_Current(CHARGE_CURRENT)/10);
	  if(current_I > reference_current){
			return (current_I-reference_current);
		}else{
			reference_current = current_I;
			return 0;
		}
}

5.判断是否接入适配器

通过判断充电电压是否在正常电压范围内进行判断有无适配器接入。

/*判断是否有外接电源适配器*/
uint8_t ChargeAccess(void){
    charge_vol = ADC_GetValue(ADC_CHARGE_DET) / 4096.0f * 3.3f * xxx;//xxx为分压转换系数
    if(charge_vol > 3.5f && charge_vol < 5.5f){
        return 1;
    }
    return 0;
}

6.当前充电基准电流

基准电流在充电其实设置即可。

/*设置当前充电基准电流*/
void Set_ChargeRefCurrent(void)//在开启充电时进行设置
{
    reference_current = (uint16_t)(Get_Current(CURRENT_CHARGE)/10);
}

6.充电过温保护

过温保护即为电池过温保护,使用NTC的查表法进行温度检测,达到设置温度停止充电,防止出现危险情况。

放置.h文件

#define NTC_HIGH_PRECISION 	1//1=0.1℃ 0=1℃
#define NUM 141
//-20℃~120℃ 
static int16_t NTC3435_10K[NUM]=
{
	3581,3559,3535,3511,3486,3461,3435,3408,3381,3353,
	3324,3295,3266,3234,3203,3171,3138,3105,3072,3037,
	3003,                                             //0                                      
	2968,2932,2896,2859,2823,2785,2748,2710,2672,2633,
	2595,2556,2517,2478,2438,2399,2360,2321,2281,2242,
	2203,2164,2125,2086,2048,2009,1971,1933,1896,1858,
	1822,1785,1749,1713,1678,1643,1896,1896,1540,1507,
	1475,1436,1411,1380,1349,1319,1289,1260,1231,1203,
	1176,1149,1122,1096,1070,1045,1021,997,974,951,
	928,906,885,864,843,823,803,784,766,747,
	729,712,695,678,662,646,631,616,601,587,
	573,559,546,533,520,508,496,484,473,462,
	451,440,430,420,410,400,391,382,373,365,
	356,348,340,332,325,317,310,303,296,290,
	283,277,271,265,259,253,247,242,237,231,
};
int16_t Read_NTC_Temperature(int16_t *list,u16 rADC,int16_t BaseValue);



//输入参数:ADC表  采集的ADC值   ADC表的起始温度值(-20℃=-200)
//返回值:温度值 单位0.1℃ 例如返回值是100,对应的就是100*0.1℃=10℃。
//该函数得到的结果还需要除以10得到的结果才是正确的结果
int16_t Read_NTC_Temperature(int16_t *list,uint16_t rADC,int16_t BaseValue)
{
	uint16_t index=0;
	uint16_t deta=0;
	uint16_t t=0;
	int16_t result=0;
	if(rADC>=list[0])
		return BaseValue;
	if(rADC<=*(list+NUM-1))
	{
		result=((NUM-1)*10+BaseValue);
		return result;
	}
	index=NTC_Lookup(list,rADC);
#if NTC_HIGH_PRECISION
	deta=list[index]-list[index+1];
	t=10*(list[index]-rADC)/deta;
#endif
	result=(BaseValue+index*10+t);
	return result;
}

7.电池充满判断

在充电电压到达一定数值后,电压变化不会太明显,为精确判断充电是否完成,因此根据最后充电电流的变化来确认充电是否完成,当电流降低达到一定值之后便认为是充电完成。

#define CHARGE_DONE_CURRENT         190  //充电电流小于190即判定为充满

uint8_t Is_Charge_Done(void)
{
    return Charge_Finish;
}

void Reset_Charge_Done(void)
{
    Charge_Finish = 0;
}


//判断语句,在合适的位置进行判断,如果充电电流小于190,并且电量不小于99%
if(Get_ChargeCurrent() < CHARGE_DONE_CURRENT && Get_Battery_Percent() >= 99){
	if(Charge_Ctrl_Flag()){ //如果充电脚使能
		if(!Is_Charge_Done()){
			charge_time = Get_sysTime();	//充电完成时间
			Charge_Finish = 1;
		}			
	}						
}

8.电量计算

最后是电量的计算,通过调用此函数就可以将电池电量百分比计算出来。

typedef enum{
    NO_BATTERY = 0,
    BATTERY_LEVEL_1,
    BATTERY_LEVEL_2,
    BATTERY_LEVEL_3,
    BATTERY_LEVEL_4,
    BATTERY_LEVEL_5,
}BatteryLevel;  //五个等级
BatteryLevel batteryLevel;

//每个等级对应的电池电压
#define LOW_POWER_VAL               (23.1f*6.0f/7.0f)//22.8
#define POWER_LEVEL1_VAL            (24.9f*6.0f/7.0f)//24.2
#define POWER_LEVEL2_VAL            (25.4f*6.0f/7.0f)//24.8
#define POWER_LEVEL3_VAL            (26.0f*6.0f/7.0f)//25.6
#define POWER_LEVEL4_VAL            (26.8f*6.0f/7.0f)//26.5
#define POWER_LEVEL5_VAL            (27.8f*6.0f/7.0f)//27.8

/*延时充电等级*/
#define BATTERY_DELAY_LEVEL_1       1
#define BATTERY_DELAY_LEVEL_2       2

uint8_t battery_percent;//电池百分比
uint8_t battery_cur_count;//静态计数
uint32_t battery_refrece;//电池时间参考
static float battery_val;//获取电池电压
static const float battery_rate[6] ={LOW_POWER_VAL,POWER_LEVEL1_VAL,POWER_LEVEL2_VAL,POWER_LEVEL3_VAL,POWER_LEVEL4_VAL,POWER_LEVEL5_VAL};//每个等级对应的电池电压数组

bool is_first = true;//为第一次运行减少误差
static uint32_t battery_updata_rate;//更新速率等级
static uint8_t bat_diff_count = 0;//与上次的差异值
static uint8_t delay_charge = 0;//充电延时

void Delay_Charge_Set(uint8_t delay_level)
{
	delay_charge = delay_level;
}

void Delay_Charge_Reset(void)
{
	delay_charge = 0;
}

uint8_t Delay_Charge_Get(void)
{
	return delay_charge;
}

void Charge_Ctrl_Enable(void)
{
    GPIO_SetBits(CHARGE_CTRL_GPIO,CHARGE_CTRL_GPIO_PIN);
}

void Charge_Ctrl_Disable(void)
{
    GPIO_ResetBits(CHARGE_CTRL_GPIO,CHARGE_CTRL_GPIO_PIN);
}

uint8_t Charge_Ctrl_Flag(void)
{
	return GPIO_ReadOutputDataBit(CHARGE_CTRL_GPIO,CHARGE_CTRL_GPIO_PIN);
}

/*获取电池电量百分比*/
uint8_t Get_Battery_Percent(void)
{
  int  i = 0;
	if(is_first){ //第一次跑机,延时获取
		while(i++ < 20){
		battery_val = Get_BatteryVal();	//获取电池电压
		if(battery_val < 3.6f){//最小电压		
		}else if((battery_val > 4.3f) && ChargeAccess()){ 
		}else{
			break;
		}
		DELAY_WaitmS(100);//第一次获取数据延时一小段时间
		}
	}else if(delay_charge && ChargeAccess()){ //主要在充电完成之后
		if((Get_sysTime() - Get_Charge_Start_Time() > 5*1000) && (Delay_Charge_Get() != BATTERY_DELAY_LEVEL_2)){ //延时级别1,正常延时5秒充电使能
			battery_val = Get_BatteryVal();	
			if(battery_val <= battery_rate[BATTERY_LEVEL_5]){ //如果电池电压未到满压,立即开始充电
				Charge_Ctrl_Enable();//开始充电
				Delay_Charge_Reset();//清清除延时等级
					
				//延时再次判断
				DELAY_WaitmS(200);
				battery_val = Get_BatteryVal();	
				if(battery_val > 4.8f || Read_NTC_Temperature(NTC3435_10K,Get_Battery_Temper(),-200)/10) > 40){ //充电过温保护,关闭充电
					Charge_Ctrl_Disable();
					Delay_Charge_Set(BATTERY_DELAY_LEVEL_2);
				}
			}
		}
			
		if(Get_sysTime() - Get_Charge_Start_Time() > 60*1000){ //延时级别2,过温保护延时1分钟充电使能
			Charge_Ctrl_Enable();
			Delay_Charge_Reset();
		}
	}
		
    battery_val = Get_BatteryVal();	

	  //动态调整电压值
    if(battery_val ){//可要可不要
			battery_val += 0.02f;		
    }else {
			battery_val += 0;
    }
	
    //如果是充电脚,用于在充电的过程中电池电压相较于实际电压略高的问题
    if(Charge_Ctrl_Flag()){
			(battery_val > POWER_LEVEL5_VAL) ? (battery_val -= 0.05f) : ((battery_val > POWER_LEVEL4_VAL) ? (battery_val -= 0.15f) : (battery_val -= 0.2f));
    }
		
	//电池数据更新时间,根据不同电压调整电量衰减时间
    if(battery_percent <= 20 ){
			battery_updata_rate = 1;
    }else if(battery_percent >= 80){
			battery_updata_rate=16;
		}else if(battery_percent >= 50){
	    battery_updata_rate = 8;
		}else if(Charge_Ctrl_Flag()){ //充电速率
			battery_updata_rate = 10;
    }else{
			battery_updata_rate = 4;
    }		
	 
    if((Get_sysTime() - battery_refrece > (uint32_t)(1000 * battery_updata_rate)) || is_first){	
			if (battery_val >= battery_rate[BATTERY_LEVEL_4]){
       /* 充电时: 80%-90%电压判断,90%-100% 电流判断 */
				if (Charge_Ctrl_Flag()) {
						if (battery_val >= battery_rate[BATTERY_LEVEL_5]) {
							battery_cur_count=(uint8_t)((11-(Get_ChargeCurrent()/100))+90);
							if (Is_Charge_Done()) {
								battery_cur_count = 100;
							} else if (battery_cur_count > 99) {
								if (Is_Charge_Done()) {
									battery_cur_count = 100;
								} else {
									battery_cur_count = 100;
								}
							}
							batteryLevel = BATTERY_LEVEL_5;
						} else if (battery_val >= battery_rate[BATTERY_LEVEL_4]) {
							 battery_cur_count = (uint8_t) ((battery_val - battery_rate[BATTERY_LEVEL_4]) /(battery_rate[BATTERY_LEVEL_5] - battery_rate[BATTERY_LEVEL_4]) * 10 + 80);
							 batteryLevel = BATTERY_LEVEL_4;
						}
				 } else {
					 /* 耗电时,全部按电压判断 */
					 if(battery_val >= battery_rate[BATTERY_LEVEL_4]){
							battery_cur_count = (uint8_t)((battery_val - battery_rate[BATTERY_LEVEL_4])/(battery_rate[BATTERY_LEVEL_5] - battery_rate[BATTERY_LEVEL_4])*20 + 80);
							batteryLevel = BATTERY_LEVEL_4;
							if (Is_Charge_Done() && Charge_Ctrl_Flag()) { //充电完成并且有充电标志的情况下才显示100%
								batteryLevel = BATTERY_LEVEL_5;
								battery_cur_count = 100;
							} else if (battery_cur_count > 99) {
								if (Is_Charge_Done()) {
									batteryLevel = BATTERY_LEVEL_5;
									battery_cur_count = 100;
								} else {
									battery_cur_count = 100;
								}
							}
					 }
				}
      } else if(battery_val >= battery_rate[BATTERY_LEVEL_3]){
				battery_cur_count = (uint8_t)((battery_val - battery_rate[BATTERY_LEVEL_3])/(battery_rate[BATTERY_LEVEL_4] - battery_rate[BATTERY_LEVEL_3])*20 + 60);
				batteryLevel = BATTERY_LEVEL_3;
      }else if(battery_val >= battery_rate[BATTERY_LEVEL_2]){
        battery_cur_count = (uint8_t)((battery_val - battery_rate[BATTERY_LEVEL_2])/(battery_rate[BATTERY_LEVEL_3] - battery_rate[BATTERY_LEVEL_2])*20 + 40);
        batteryLevel = BATTERY_LEVEL_2;
      }else if(battery_val >= battery_rate[BATTERY_LEVEL_1]){
        battery_cur_count = (uint8_t)((battery_val - battery_rate[BATTERY_LEVEL_1])/(battery_rate[BATTERY_LEVEL_2] - battery_rate[BATTERY_LEVEL_1])*20 + 20);
        batteryLevel = BATTERY_LEVEL_1;
      }else if(battery_val >= battery_rate[NO_BATTERY]){
        battery_cur_count = (uint8_t)((battery_val - battery_rate[NO_BATTERY])/(battery_rate[BATTERY_LEVEL_1] - battery_rate[NO_BATTERY])*20 + 0);
        batteryLevel = NO_BATTERY;
      }else{
				battery_cur_count = 1; 
		}
		//如果跟上一次的百分比不一致
		if (battery_cur_count != battery_percent){
				bat_diff_count ++;
		} else {
				bat_diff_count = 0;
		}
		if (!is_first) { //非首次运行
			//如果不同次数大于2次
			if (bat_diff_count >= 2){
				bat_diff_count = 0;
				if (ChargeAccess() && battery_cur_count > battery_percent){
					++battery_percent;
				} else if (battery_cur_count < battery_percent){
					--battery_percent;
				}
			}
		} else {
			is_first = false;
            //如果需要做掉电保存还可以在此处进行Flash的电量读取
		}
		//限定范围在1~100
			battery_percent = battery_percent>100?  100: battery_percent;
      battery_percent = battery_percent<1  ?  1: battery_percent;
      battery_refrece = Get_sysTime();	//获取系统时间为下一次电量计算做准备
    }
    return battery_percent;
}

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: ASP锂电池的剩余电量可以通过测量电池的电压来估算。锂电池的标准工作电压是3.7伏,所以当电池电压接近3.7伏时,剩余电量应该是较高的。常见的方式是使用电压表或多用途电池测试器测量电池的电压。一般来说,当ASP锂电池电压在3.7伏以下时,电量将逐渐减少,当电压接近3伏时,电量已经接近耗尽。但是需要注意的是,电池的电压并不是一个百分比值,而是一种数值范围的估计,具体的电量还受到许多其他因素的影响,如电池的年龄,充放电次数等。因此,为了获得更准确的电量估算,我们需要使用专业的电池管理系统或设备来进行测量。 ### 回答2: ASP锂电池剩余电量是指目前电池充满电时,还能够供应电能的剩余电量。ASP锂电池采用锂离子作为电荷载体,具有高能量密度、长寿命等优点。为了确保电池的可靠和稳定,ASP锂电池的剩余电量应该根据实际使用情况进行评估。 通常来说,ASP锂电池剩余电量可以通过电量计算和电压测量来进行估算。首先,通过测量电池的电压,然后与电池的已知电量曲线进行比较,可以大致了解剩余电量的情况,但这种方法不是非常准确。 另外一种方法是借助专门的电量测量设备,如电池容量测试仪,通过对电池进行放电测试,可以直接测量电池尚余电量百分比。这种方法相对准确,但需要特定设备进行。 除了这些方法外,还可以通过软件进行电量估算。ASP锂电池往往配备了内置的芯片和电量管理系统,可以通过分析电池的实时信息,如充电过程、放电过程、负载情况等,来预测剩余电量。这种方法可以在设备上显示电池电量百分比,用户可以根据显示的电量进行合理的使用。 总而言之,ASP锂电池剩余电量的准确测量需要借助专门设备或软件进行评估,可以通过电压测量、电量计算、放电测试等方法进行估算。而准确评估剩余电量对于合理使用电池和维持电池寿命具有重要意义。 ### 回答3: ASP锂电池的剩余电量可以通过测量其电压来间接估算。锂电池的工作电压范围一般在3.0V至4.2V之间,当锂电池的电压接近4.2V时表示电池已经充满,当锂电池的电压降至3.0V以下时表示电池即将耗尽。因此,我们可以通过测量ASP锂电池的电压,来大致判断其剩余电量的多少。 另外,一些锂电池也配备了电量显示功能,可以通过按下电量显示按钮或触摸电池表面的电量显示区域,以LED灯、液晶屏等方式直接显示电池的剩余电量。这种方式更直观、准确,可以更方便地了解ASP锂电池的剩余电量。 此外,还有一种更精确的方法是使用专门的锂电池保护板或电池管理系统。这些设备可以监测电池的电流、电压以及温度等参数,通过对电池进行精确计算和管理,可以实时准确地显示ASP锂电池的剩余电量。 总之,通过测量电压、使用电量显示功能或使用专用的锂电池保护板或电池管理系统,我们可以大致了解ASP锂电池的剩余电量。不过需要注意的是,这些方法只能提供一个大概的估计,具体的剩余电量还需要根据电池的使用情况和工作环境等因素进行综合考虑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值