开源项目:STM32+ESP8266水墨屏天气时钟-利用STM32的ADC功能计算锂电池电量

项目背景

在水墨屏天气时钟的项目中,需要显示电池的剩余电量,本次使用STM32自带的12位ADC功能检测电池电压并且计算锂电池的剩余电池电量。

设计思路

1.锂电池电压先经过两个电阻分压。
2.ADC采集分压电阻的电压。
3.根据关系计算电池剩余电量。
4.在水墨屏上显示。

硬件方案

在这里插入图片描述
电路设计其实很简单,就是用两个大电阻去分压电池的电压,注意电阻的电阻值要大一点,并且最好是1%精度以下的电阻。分压后的BAT_ADC直接输入到单片机的ADC脚位。

电池电压和电池剩余电量的关系

根据锂电池放电特性(电池容量与电池电压的关系,具体还要看电池厂家给的资料,这里的数据只作为参考):

电池电量 电池电压
100 % 4.2V
90% 4.08V
80% 4.0V
70% 3.93V
60% 3.87V
50% 3.83V
40% 3.79V
30% 3.77V
20% 3.73V
10% 3.68V
5% 3.5V
0% 2.5V

代码设计

软件设计就没什么好讲的了,就是开启STM32的ADC功能,然后得出BAT_ADC的电压,最后算出电池电压,根据关系得出电池电量。

//电池电压ADC采集初始化,ADC12_IN9,PB1
void BAT_ADC_Init(void)
{
   
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1,ENABLE);
	
	GPIO_InitStructure
### 关于电池电量稳定算法的实现 电池电量稳定算法的核心目标是在不同条件下保持电量估算的准确性和平稳性。以下是几种常见的实现方法及其对应的代码示例。 #### 1. 基于线性插值的电量计算 利用已知的电池电压-电量关系表,通过线性插值法来估算当前电量百分比。这种方法简单易用,适合大多数嵌入式系统。 ```c #include <stdio.h> // 定义电压与电量的关系数组 const float voltage_table[] = {3.0, 3.2, 3.4, 3.6, 3.8, 4.0}; const float soc_table[] = {0.0, 10.0, 30.0, 50.0, 80.0, 100.0}; float calculate_soc(float current_voltage) { int i; for (i = 0; i < sizeof(voltage_table)/sizeof(voltage_table[0]) - 1; ++i) { if (current_voltage >= voltage_table[i] && current_voltage <= voltage_table[i+1]) { // 使用线性插值计算 SOC float slope = (soc_table[i+1] - soc_table[i]) / (voltage_table[i+1] - voltage_table[i]); return soc_table[i] + slope * (current_voltage - voltage_table[i]); } } return -1; // 如果不在范围内返回错误码 } int main() { float voltage = 3.5; // 当前测得的电压 printf("Battery SOC: %.2f%%\n", calculate_soc(voltage)); return 0; } ``` 此代码基于给定的电压范围和对应电量进行线性插值[^1]。 --- #### 2. 利用卡尔曼滤波优化电量估算 卡尔曼滤波是一种有效的状态估计算法,能够减少噪声干扰并提高电量估算精度。 ```cpp #include <iostream> using namespace std; class KalmanFilter { public: double Q; // 过程噪声协方差 double R; // 测量噪声协方差 double P; // 预测误差协方差 double K; // 卡尔曼增益 double X; // 状态变量(电量) KalmanFilter(double q, double r) : Q(q), R(r), P(1), K(0), X(0) {} void update(double measurement) { P += Q; // 更新预测误差协方差 K = P / (P + R); // 计算卡尔曼增益 X += K * (measurement - X); // 更新状态变量 P *= (1 - K); // 更新预测误差协方差 } double get_state() const { return X; } }; int main() { KalmanFilter kf(0.001, 0.1); double measurements[] = {3.4, 3.42, 3.38, 3.41}; // 模拟测量数据 for (double m : measurements) { kf.update(m); cout << "Estimated SOC: " << kf.get_state() << endl; } return 0; } ``` 这段代码展示了如何使用卡尔曼滤波器平滑电量估算过程中的波动[^3]。 --- #### 3. 结合开路电压(OCV)和电流积分的方法 这种混合方法综合考虑了电池的开路电压和充放电过程中累积的电流变化,从而提高了长期使用的稳定性。 ```python import time class BatteryMonitor: def __init__(self, initial_soc=100): self.soc = initial_soc # 初始化电量 self.current_integral = 0 # 积分电流初始值 self.capacity = 2000 # 电池容量mAh def update_ocv(self, ocv): """根据开路电压更新SOC""" ocv_to_soc_map = [(3.0, 0), (3.2, 10), (3.4, 30), (3.6, 50), (3.8, 80), (4.0, 100)] for i in range(len(ocv_to_soc_map)-1): v_low, soc_low = ocv_to_soc_map[i] v_high, soc_high = ocv_to_soc_map[i+1] if v_low <= ocv <= v_high: self.soc = soc_low + (soc_high - soc_low) * ((ocv - v_low) / (v_high - v_low)) break def integrate_current(self, current_mA, dt_seconds): """累加电流消耗""" charge_change = current_mA * dt_seconds / 3600 # 转换为mAh self.current_integral += charge_change self.soc -= self.current_integral / self.capacity * 100 battery = BatteryMonitor() for _ in range(10): battery.update_ocv(3.6) # 模拟读取开路电压 battery.integrate_current(-200, 60) # 模拟每分钟耗电200mA print(f"Battery SOC: {battery.soc:.2f}%") time.sleep(1) ``` 以上 Python 示例实现了 OCV 和电流积分相结合的方式,动态调整电量估计[^4]。 --- #### 4. MicroPython 中的电量监测 如果开发环境支持 MicroPython,则可以直接调用内置函数完成电量监控任务。 ```python from machine import Pin, ADC from utime import sleep_ms def init_battery_monitor(): adc_pin = ADC(Pin(34)) # 设置ADC引脚 adc_pin.atten(ADC.ATTN_11DB) # 设置衰减等级 min_volt, max_volt = 3.2, 4.18 # 设定最小最大电压 return adc_pin, min_volt, max_volt def read_soc(adc, min_v, max_v): raw_value = adc.read_u16() # 获取原始数值 volt = raw_value * (max_v - min_v) / 65535 + min_v soc = (volt - min_v) / (max_v - min_v) * 100 return round(soc) adc, min_v, max_v = init_battery_monitor() while True: soc = read_soc(adc, min_v, max_v) print(f"Battery SOC: {soc}%") sleep_ms(1000) ``` 这是针对 ESP32 平台的一个典型例子,展示如何结合硬件特性简化电量监测逻辑[^3]。 --- ### 总结 不同的应用场景决定了采用何种算法更为合适。对于简单的场景可以选择线性插值法;而对于更复杂的场合则建议引入卡尔曼滤波或者结合多种因素的高级模型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点奶茶叫上我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值