esp-iot-solution 中的 BQ27220 电量计驱动:从 I2C 接线到 CEDV 参数配置与采样数据采集
【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution
本指南以 components/sensors/battery_fuel_gauge/bq27220/README.md 为核心,系统讲解 ESP-IDF 生态下 BQ27220 单节锂离子电池电量计(Fuel Gauge)驱动组件的使用方法:包括 I2C 总线初始化、CEDV 电量计参数表与 Gauging 配置位的含义、驱动初始化时自动烧写电池参数的完整流程,以及配套sample-data-app工具如何以 CSV 格式采集放电数据、配合 Gauging Parameter Calculator 标定电池模型。读完本文,你将能够在 ESP32 等乐鑫芯片上快速接入 BQ27220,读取电压、电流、剩余容量、SoC、SoH 等关键指标,并为自己的电芯生成一套可用的 CEDV 参数。
组件概览:BQ27220 能做什么
BQ27220 是 TI 出品的单节锂离子电池电量计 IC,能够提供精确的电池状态监测,包括:
- 荷电状态(State of Charge,SoC)
- 剩余容量(Remaining Capacity,mAh)
- 健康状态(State of Health,SoH)
- 电压、电流、温度、平均功率、循环次数、预计剩余/充满时间等一系列关键参数
在 esp-iot-solution 中,该组件通过 I2C 接口与主机控制器通信,提供了完整的驱动实现。组件目录结构如下:
components/sensors/battery_fuel_gauge/bq27220/ ├── bq27220.c / bq27220.h # 驱动核心实现与公共 API ├── priv_include/ │ ├── bq27220_reg.h # 标准命令、Control() 子命令、解锁密钥定义 │ └── bq27220_data_memory.h # 数据存储器(Data Memory)地址映射表 ├── test_apps/ # Unity 测试工程 └── tools/sample-data-app/ # 实时采样数据采集工具其中 bq27220.h 是唯一需要用户包含的头文件,bq27220_reg.h 与 bq27220_data_memory.h 为私有头文件,封装了芯片寄存器与数据存储器细节。
除基础功能外,组件还附带了一个工具 sample-data-app,可以实时监测电池状态,并以 CSV 格式打印数据,供 Gauging Parameter Calculator(GPCCEDV)离线生成电芯的 CEDV 参数。
快速开始:驱动使用示例
组件的使用流程非常简洁:先创建 I2C 总线,再定义 CEDV 参数与 Gauging 配置,最后调用bq27220_create()完成设备初始化。下面是在 400 kHz I2C 主模式下的完整示例(与 README.md 及 test_apps/main/bq27220_test.c 中的用法一致):
#define I2C_MASTER_SCL_IO GPIO_NUM_1 /*!< gpio number for I2C master clock */ #define I2C_MASTER_SDA_IO GPIO_NUM_2 /*!< gpio number for I2C master data */ // Default Gauging Parameter static const parameter_cedv_t default_cedv = { .full_charge_cap = 650, .design_cap = 650, .reserve_cap = 0, .near_full = 200, .self_discharge_rate = 20, .EDV0 = 3490, .EDV1 = 3511, .EDV2 = 3535, .EMF = 3670, .C0 = 115, .R0 = 968, .T0 = 4547, .R1 = 4764, .TC = 11, .C1 = 0, .DOD0 = 4147, .DOD10 = 4002, .DOD20 = 3969, .DOD30 = 3938, .DOD40 = 3880, .DOD50 = 3824, .DOD60 = 3794, .DOD70 = 3753, .DOD80 = 3677, .DOD90 = 3574, .DOD100 = 3490, }; // Default Gauging Config static const gauging_config_t default_config = { .CCT = 1, .CSYNC = 0, .EDV_CMP = 0, .SC = 1, .FIXED_EDV0 = 0, .FCC_LIM = 1, .FC_FOR_VDQ = 1, .IGNORE_SD = 1, .SME0 = 0, }; static i2c_bus_handle_t i2c_bus = NULL; static bq27220_handle_t bq27220 = NULL; i2c_config_t conf = { .mode = I2C_MODE_MASTER, .sda_io_num = I2C_MASTER_SDA_IO, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_io_num = I2C_MASTER_SCL_IO, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = 400 * 1000, }; i2c_bus = i2c_bus_create(I2C_NUM_0, &conf); bq27220_config_t bq27220_cfg = { .i2c_bus = i2c_bus, .cfg = &default_config, .cedv = &default_cedv, }; bq27220 = bq27220_create(&bq27220_cfg);几点关键说明:
- I2C 地址:驱动在 bq27220.c 中固定使用设备地址
0x55,总线创建后无需额外指定。 - 总线依赖:组件依赖
espressif/i2c_bus(版本1.4.*),因此必须先用i2c_bus_create()创建总线句柄再传入驱动,详见 idf_component.yml。 - 硬件接线:I2C 的 SCL/SDA 需配置上拉(
GPIO_PULLUP_ENABLE),示例默认使用 GPIO1(SCL)与 GPIO2(SDA),可按实际板卡修改宏定义。
深入理解 CEDV 参数表
parameter_cedv_t(定义于 bq27220.h)是 CEDV(Compensated End-of-Discharge-Voltage,补偿型放电终止电压)参数集,这些值会被写入芯片 RAM,用于针对特定电芯化学特性配置电量计。各字段含义如下:
| 字段 | 含义 |
|---|---|
full_charge_cap | 已学习的满充容量(mAh),即实际可用容量 |
design_cap | 设计容量(mAh) |
reserve_cap | 保留容量(mAh) |
near_full | 接近充满阈值(mAh) |
self_discharge_rate | 自放电率索引(0~255),自放电百分比/天 = 值 × 0.0025% |
EDV0 | 0% SoC 时的放电终止电压(mV) |
EDV1 | 3% SoC 时的放电终止电压(mV) |
EDV2 | 电池低电量百分比对应的放电终止电压(mV) |
EMF | 无负载电芯电压,高于计算出的最高电芯 EDV 阈值 |
C0 | 无负载、容量相关的 EDV 调整因子 |
R0 | 一阶倍率依赖因子,用于补偿电池阻抗 |
T0 | 电池阻抗随温度变化的调整量 |
R1 | 电池阻抗随容量变化的调整量 |
TC | 冷态(T < 23°C)阻抗变化的调整量 |
C1 | EDV0 处期望保留的电池容量 |
DOD0 ~ DOD100 | 放电深度(Depth-of-Discharge)0%~100% 对应的电压表(mV) |
从源码结构看,这份示例参数对应一颗 650 mAh 的电芯(design_cap = 650),DOD 电压表从满电的 4147 mV 平滑下降到放空的 3490 mV,与 EDV0 一致。实际项目中的电芯参数应通过 TI 的 Gauging Parameter Calculator 工具(见下文)生成,不要直接套用示例值。
Gauging Config 配置位
gauging_config_t(bq27220.h)是一个 16 位位域联合体,对应数据存储器中 Gauging Configuration 寄存器(地址0x929B,见 bq27220_data_memory.h)。各位的语义:
| 位 | 含义 |
|---|---|
CCT | 0 = 使用 DesignCapacity() 的百分比计算 CC(默认);1 = 使用 FullChargeCapacity() 的百分比 |
CSYNC | 在有效充电终止时将 RemainingCapacity() 与 FullChargeCapacity() 同步 |
EDV_CMP | EDV 补偿使能 |
SC | 平滑引擎(Smoothing Engine)使能 |
FIXED_EDV0 | 固定 EDV0 使能 |
FCC_LIM | 满充容量限制 |
FC_FOR_VDQ | 使用满充电压用于 VDQ |
IGNORE_SD | 忽略自放电 |
SME0 | 平滑引擎模式选择 |
默认配置中启用了CCT(基于满充容量计算)、SC(平滑)、FCC_LIM、FC_FOR_VDQ和IGNORE_SD,适合大多数消费类应用。
驱动初始化流程:bq27220_create 内部做了什么
bq27220_create()(bq27220.c)并非简单的句柄分配,而是一次完整的设备验证与电池参数编程流程:
- 参数校验:检查
config、i2c_bus、cedv、cfg均非空,分配驱动数据结构并在 I2C 总线上创建0x55地址的设备句柄。 - 设备识别:通过
Control()子命令CONTROL_DEVICE_NUMBER(0x0001)请求设备号,再从 MAC scratch 空间(0x40)读回,必须等于BQ27220_DEVICE_ID(0x0220),否则初始化失败——这是防止 I2C 接错器件的关键保护。 - 版本读取:读取固件版本(
CONTROL_FW_VERSION)与硬件版本(CONTROL_HW_VERSION)并打印日志,例如启动日志中的Firmware Version 2002/Hardware Version 0004。 - 解除密封:调用
bq27220_unseal(),通过两个解锁密钥UNSEALKEY1 = 0x0414、UNSEALKEY2 = 0x3672(bq27220_reg.h)进入未密封状态以访问配置数据。 - 参数比对与烧写:先读取芯片当前的设计容量、EMF、T0、DOD20 与传入 CEDV 参数比对;若完全一致则跳过烧写并打印
Skip battery profile update。否则进入 Config Update 模式(CONTROL_ENTER_CFG_UPDATE,0x0090),通过Select Subclass(0x3E)+MAC Data(0x40)+MAC Data Sum(0x60)逐项写入 Gauging Configuration、满充容量、设计容量、近满阈值、自放电率、保留容量、EDV0/1/2、EMF、C0/R0/T0/R1、TC/C1 以及 DOD0~DOD100 电压表,随后用CONTROL_EXIT_CFG_UPDATE_REINIT(0x0091)退出并复位。 - 校验与密封:回读设计容量确认写入成功(日志
Battery profile update success),最后执行bq27220_seal()防止配置数据被意外篡改。
整个流程涉及数据存储器写操作的校验和机制:bq27220_set_parameter_u16()会先发送 [地址低字节、地址高字节、值高字节、值低字节] 四个字节,再发送对这四个字节求反的校验和以及固定长度 6(见 bq27220.c)。
值得注意:
bq27220_create()内部会把TC与C1打包进同一个 16 位字((TC << 8) | C1)写入0x92B1,对应数据存储器中 TC(0x92B1)与 C1(0x92B2)相邻的布局。
公共 API 一览:读取电池关键指标
bq27220.h 提供了丰富的只读查询接口,全部通过标准命令(Standard Commands)直接读取,底层实现见 bq27220.c:
| API | 返回内容 |
|---|---|
bq27220_get_voltage() | 电池电压(mV) |
bq27220_get_current() | 瞬时电流(mA),充电为正、放电为负 |
bq27220_get_avgcurrent() | 平均电流(mA) |
bq27220_get_temperature() | 温度(0.1°K,转换为摄氏度需/10 - 273) |
bq27220_get_remaining_capacity() | 剩余容量(mAh) |
bq27220_get_full_charge_capacity() | 补偿后的满充容量(mAh) |
bq27220_get_design_capacity() | 设计容量(mAh) |
bq27220_get_state_of_charge() | 荷电状态 SoC(0~100%) |
bq27220_get_state_of_health() | 健康状态 SoH(0~100%,满充容量/设计容量之比) |
bq27220_get_cycle_count() | 充放电循环次数 |
bq27220_get_charge_voltage()/bq27220_get_charge_current() | 充电电压(mV)/ 充电电流(mA) |
bq27220_get_average_power() | 平均功率(mW),充电为正、放电为负 |
bq27220_get_time_to_empty()/bq27220_get_time_to_full() | 预计放空/充满时间(分钟) |
bq27220_get_maxload_current()/bq27220_get_standby_current() | 最大负载电流 / 待机电流(mA) |
bq27220_get_battery_status() | 电池状态位域(充放电状态、FC/FD、OCV 标志等) |
bq27220_get_operation_status() | 运行状态位域(SEC 安全等级、CFGUPDATE、INITCOMP 等) |
bq27220_get_fw_version()/bq27220_get_hw_version() | 固件/硬件版本 |
bq27220_seal()/bq27220_unseal() | 密封/解除密封配置访问 |
bq27220_set_parameter_u16()/bq27220_get_parameter_u16() | 按数据存储器地址读写 16 位参数 |
bq27220_delete() | 释放句柄并删除 I2C 设备 |
其中battery_status_t与operation_status_t均为位域联合体,便于直接读取如DSG(放电中)、FC(已满充)、FD(已满放)、SEC(当前安全访问等级)等状态位;两结构体均通过ESP_STATIC_ASSERT强制占用 2 字节以匹配寄存器宽度。
sample-data-app:为 GPCCEDV 采集标定数据
BQ27220 的电量计精度高度依赖 CEDV 参数与真实电芯的匹配度。组件自带的 sample-data-app 工具就是为此设计的:它从 BQ27220 读取数据,以 CSV 格式在控制台打印放电过程数据,供 TI 的 Gauging Parameter Calculator(GPCCEDV)工具使用,从而生成该电芯专属的 CEDV 参数。
菜单配置
工具参数全部通过 menuconfig 配置,定义于 Kconfig.projbuild:
| 配置项 | 默认值 | 说明 |
|---|---|---|
CONFIG_I2C_SCL_IO | 1 | I2C SCL 引脚 |
CONFIG_I2C_SDA_IO | 2 | I2C SDA 引脚 |
CONFIG_DISCHARGE_ENABLE_IO | 4 | 放电使能 GPIO(低电平先关闭放电,初始化文件系统后再拉高开始放电) |
CONFIG_END_DISCHAGE_VOLTAGE | 3300 | 结束放电电压(mV),即采样记录停止的阈值 |
默认结束放电电压为 3.3V,可通过 menuconfig 修改。
采集逻辑
main.c 的流程是:
- 初始化 I2C 总线与 BQ27220(使用与上文相同的默认 CEDV 参数与 Gauging 配置);
- 将放电使能 IO 配置为输出并拉低,挂载 SPIFLASH 上的 FAT 文件系统(
/log分区); - 拉高放电使能 IO 开始放电,随后以 2 秒间隔调用
bq27220_get_voltage()、bq27220_get_current()、bq27220_get_temperature()采集数据,温度从 0.1°K 转换为摄氏度; - 当电压低于结束放电电压(默认 3300 mV)时停止记录,关闭放电并卸载文件系统。
输出格式
CSV 输出由printf直接打印到控制台,表头与数据格式如下(节选自 tools/sample-data-app/README):
I (311) bq27220_sample: Hello BQ27220 Battery Fuel Gauge! I (316) bq27220_sample: Discharge enable IO: 4 I (321) bq27220_sample: I2C master SCL IO: 1 I (325) bq27220_sample: I2C master SDA IO: 2 I (329) i2c_bus: i2c0 bus inited I (331) i2c_bus: I2C Bus V2 Config Succeed, Version: 1.1.0 I (370) bq27220: Firmware Version 2002 I (386) bq27220: Hardware Version 0004 I (452) bq27220: Design Capacity: 650, EMF: 3670, T0: 4547, DOD20: 3969 I (452) bq27220: Skip battery profile update I (453) bq27220_sample: End discharge voltage: 3300 -------- Start record -------- ElapsedTime, Voltage, Current, Temperature 0, 4078, -33, 27.8 2, 4077, -32, 27.7 4, 4077, -32, 27.7 6, 4077, -32, 27.8 8, 4077, -32, 27.7 10, 4077, -32, 27.7 12, 4077, -32, 27.7 14, 4077, -32, 27.8 16, 4076, -32, 27.8 18, 4077, -32, 27.8 20, 4076, -32, 27.7 22, 4076, -32, 27.8 24, 4076, -32, 27.8 26, 4076, -32, 27.7 ......采集完成后,把完整的 CSV 数据交给 GPCCEDV 工具即可得到针对当前电芯的 CEDV 参数,再回填到parameter_cedv_t结构中,即可完成一次电芯标定闭环。工具的 CMake 通过EXTRA_COMPONENT_DIRS "../../../bq27220"直接复用组件源码(CMakeLists.txt),并使用 partitions.csv 划分出日志分区。
测试与验证
组件提供了基于 Unity 的测试工程 test_apps,其中 bq27220_test.c 覆盖了两类用例:
- 基础信息查询测试(
bq27220 basic information query test):完成创建→读取电池状态、电压、电流、剩余/满充容量、温度、循环次数、SoC、平均功率、最大负载、预计时间等全量信息→删除的完整链路; - 内存泄漏检测:
setUp/tearDown中通过heap_caps_get_free_size()对比 8-bit 与 32-bit 堆空闲量,阈值首次为 -110 字节、之后为 0,确保 create/delete 循环无内存泄漏。
该测试同时验证了驱动的 I2C 时序、命令交互与资源回收正确性,可作为自己项目接入时的参考模板。
工程集成要点
- 组件依赖(idf_component.yml):
espressif/i2c_bus 1.4.*(public 依赖)、cmake_utilities 0.*,并要求 IDF>=4.4。若在组件管理器(Component Manager)下使用,bq27220会自动拉取这些依赖。 - 构建配置(CMakeLists.txt):仅需
driver组件作为编译依赖,priv_include目录不对外暴露。 - 版本信息:当前版本 v0.1.1(2025-09-22),修复了 i2c_bus 依赖改为 public 导致的编译错误;v0.1.0(2025-08-12)为初始版本,提供 BQ27220 基本功能,详见 CHANGELOG.md。
- 许可:驱动源码以 Apache-2.0 / CC0-1.0 双许可形式发布,详见各文件 SPDX 头与 license.txt。
小结
esp-iot-solution 的 BQ27220 组件以"一次 create、自动完成设备识别—解锁—参数烧写—密封"的设计,把电量计接入的门槛降到了最低:上层只需定义好 CEDV 参数与 Gauging 配置,之后即可通过一组bq27220_get_*接口轮询电池状态。配合sample-data-app工具与 GPCCEDV 的标定流程,开发者可以从零为任意一款单节锂电建立精确的电量模型。建议在正式产品中:
- 使用 GPCCEDV 基于实际电芯生成 CEDV 参数,替换示例中的默认值;
- 按产品功耗与安全要求,通过 menuconfig 调整结束放电电压等采样参数;
- 参考 test_apps 中的读取与泄漏检查模式,把电池信息上报纳入自己的业务循环。
【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考