简介:这是一套面向嵌入式开发初学者与进阶者的锂电池管理系统实战项目,基于STM32F103主控与TI BQ76920专用电池监控芯片,完整实现电压/温度采集、均衡控制、过压/欠压/过流保护及SOC估算等核心BMS功能。资源适用于电子信息、自动化、通信工程等专业学生开展课程设计、毕业设计或企业原型验证,亦支持工程师在现有代码基础上二次开发。压缩包含1003个文件,主体为576个C源码与265个头文件(构建驱动层、应用逻辑与HAL适配),辅以IAR工程配置(.icf)、PCB设计文件(.kicad_pcb/.gbr)、PDF文档说明及CMSIS-DSP数学库相关实现(如arm_rfft_init_f32.c等),整体大小26.69MB。目前已有941人学习下载,所有代码均经实机测试运行通过,配套README清晰指引编译与调试流程,兼顾原理理解与工程落地。
1. 项目概述:从零构建一个可靠的锂电池管家
最近在整理工作室的旧项目,翻出来一个几年前做的锂电池管理系统,核心是STM32F103C8T6和TI的BQ76920。当时是为了给一个户外移动储能设备做电池包,市面上成品的BMS要么功能太单一,要么价格高得离谱,索性就自己动手了。这个项目麻雀虽小,五脏俱全,从硬件选型、PCB绘制、固件开发到调试优化,完整走了一遍。今天就把这个项目的核心思路、关键代码和踩过的那些坑,系统地梳理出来。如果你正打算用STM32和BQ76920这类模拟前端做自己的BMS,或者对嵌入式系统在电池管理上的应用感兴趣,这篇内容应该能给你提供一个清晰的、可落地的参考框架。
简单来说,这个系统就是一个“电池保姆”。它的核心任务就是实时监控一个由多节锂电池串联组成的电池包(比如3到5串),精确测量每一节电池的电压、整个电池包的总电流以及温度,然后基于这些数据做出智能决策:该充电时控制充电,该放电时安全放电,一旦发现任何一节电池过压、欠压、过流或者温度异常,立刻切断回路,保护电池和用电设备的安全。STM32F103作为主控大脑,负责逻辑控制和通信;BQ76920作为专业的模拟前端芯片,则扮演了“感官系统”的角色,专门负责高精度采集那些危险的、高共模电压的电池信号。整个项目的源码用C语言编写,结构清晰,完全开源。
2. 核心芯片选型与设计思路解析
为什么是STM32F103和BQ76920这个组合?这背后是一系列工程权衡的结果,绝不是随便抓两个芯片就能用的。
2.1 主控MCU:为何是STM32F103C8T6
在项目起步时,主控的选择范围其实很广。最终锁定STM32F103C8T6,也就是大家常说的“蓝莓派”或最小系统板核心芯片,主要基于以下几点考量:
首先,性能与资源足够。F103系列基于ARM Cortex-M3内核,72MHz的主频对于BMS这种偏重控制、通信和中等复杂度算法的应用绰绰有余。它需要处理的任务包括:通过I2C或SPI定期读取BQ76920的寄存器数据、运行保护算法(比较、判断)、控制MOSFET驱动电路、通过UART向上位机或显示屏发送数据、以及可能的ADC采集(如用于备份或辅助测温)。C8T6拥有64KB Flash和20KB RAM,对于这个项目的代码量和变量存储来说非常充裕。
其次,开发生态极其成熟。这是最关键的一点。STM32的HAL库、标准外设库资料浩如烟海,社区支持强大。当你调试I2C通信死活不通,或者PWM输出不对时,能快速找到大量的排查帖子和例程。相比之下,一些更小众的MCU可能会在开发工具链、调试器支持上让你耗费大量时间。对于个人项目或小团队快速原型开发,成熟的生态就是最高的效率。
再者,成本与采购便利性。STM32F103系列是绝对的“国民芯片”,价格透明,货源充足,从立创商城到淘宝,随时可以买到。封装也是常见的LQFP48,手工焊接难度适中。综合来看,它在性能、易用性、成本和可获得性上取得了最佳平衡。
注意:虽然F103足够用,但如果你计划未来扩展功能,比如加入复杂的电池均衡算法、图形显示界面或无线通信(如4G Cat.1),可能需要考虑Flash和RAM更大的型号,如STM32F103CBT6或F4系列。但在项目初期,从C8T6开始是完全合理的。
2.2 电池监控前端:BQ76920的关键角色
如果说STM32是大脑,那BQ76920就是遍布电池包各处的精密传感器和第一道安全哨兵。选择它,而不是直接用STM32的ADC去测量电池电压,原因非常深刻:
高共模电压处理能力:这是最核心的原因。对于多节串联的锂电池,测量第3节电池的电压时,其负极对地(电池包总负极)的电压可能高达12.6V(假设3串)。STM32的ADC输入电压范围通常是0-3.3V,直接测量会瞬间损坏芯片。BQ76920内部集成了专门的高压多路复用器和差分放大器,可以安全地测量每一节电芯相对于电池包总负极的电压,并将其转换成低压信号通过I2C接口输出。
集成化与安全性:BQ76920不仅仅是一个ADC。它集成了库仑计(用于电流积分计算容量)、多种硬件保护比较器(过压、欠压、过流、短路)、温度传感器接口、以及MOSFET驱动控制逻辑。很多保护功能可以在芯片内部独立于MCU快速动作(通常在微秒级),这种硬件级的保护比软件判断更可靠、响应更快,是电池安全最后的防线。
精度与可靠性:TI在电池管理领域是标杆,BQ76920的电压测量精度典型值在±5mV以内,这对于判断锂电池的充放电状态至关重要。其内部基准和测量电路针对电池管理进行了优化,比用分立运放搭建的电路更稳定、更省心。
设计思路总结:这个组合是典型的“模拟前端+数字主控”架构。BQ76920负责解决高精度、高电压、高安全性的“模拟世界”信号采集与初级保护;STM32则负责处理“数字世界”的逻辑、算法、通信和高级控制。两者通过I2C总线连接,分工明确,优势互补。
3. 硬件系统设计与核心电路剖析
有了芯片,接下来就是如何把它们和电池、负载连接起来,构成一个能工作的硬件系统。这里重点讲几个容易出问题的核心电路。
3.1 电源树设计:多电压域的可靠供给
整个系统的供电来自电池包本身。一个3串锂电池包,电压范围大约在9V到12.6V之间。我们需要从这个电压衍生出几个不同的电压域:
- BQ76920的VDD:通常需要5V或3.3V(具体看型号)。它由电池包总电压通过一个低压差线性稳压器产生。
- STM32及外围数字电路:需要3.3V。
- MOSFET驱动电路:驱动放电和充电MOSFET的栅极,通常需要一个高于电池包总电压的电压(比如用电荷泵产生),以确保MOSFET能完全导通。
关键设计点:
- LDO的选择:给BQ76920供电的LDO非常关键。因为BQ76920的模拟电路对电源噪声敏感,必须选择低噪声、高PSRR(电源抑制比)的LDO,如TPS7A系列。输入电容和输出电容的容值、类型(建议用MLCC+钽电容组合)必须严格按照数据手册推荐,否则可能导致电压测量跳动。
- 3.3V电源的时序:务必确保BQ76920的VDD上电早于或同时于STM32的3.3V上电,并且STM32的I/O口在初始化完成前处于高阻态。防止STM32在BQ76920未准备好时,通过I2C上拉电阻向其灌电,导致异常。
3.2 采样与均衡电路
BQ76920通过VC0-VC5等引脚连接各节电池。这里的PCB布局布线是影响测量精度的重中之重。
- 走线策略:采样走线(从电池焊点到芯片引脚)必须使用差分对的形式,尽量等长、等距,并远离功率线(如放电回路)和开关噪声源。最好在PCB上做开窗处理,直接上锡以减小走线电阻。
- 均衡电路:BQ76920支持被动均衡(通过电阻放电)。需要在每节电池的正负极之间连接一个均衡电阻和MOSFET。这个MOSFET的选型要注意其导通电阻和封装功耗。当多节电池同时均衡时,总热量可能不小,需要考虑散热。均衡电流一般设为50mA-100mA左右,通过调整均衡电阻阻值来实现。
3.3 电流采样与保护电路
BQ76920支持外接一个采样电阻(Shunt Resistor)来测量电流。这个电阻的选择是门学问。
- 阻值计算:阻值太大,测量精度高,但压降大,功耗大,发热严重。阻值太小,压降信号微弱,容易受噪声干扰。通常根据最大预期电流和BQ76920的差分输入电压范围来计算。例如,假设最大放电电流10A,希望在此电流下采样电阻压降为50mV,那么阻值 R = 50mV / 10A = 5mΩ。
- 电阻选型:必须选用四端开尔文连接的精密采样电阻,如BVR系列。普通的两端电阻,其引线电阻会引入显著误差。电阻的功率定额也要足够,P = I²R。上例中,P = 10A² * 0.005Ω = 0.5W,至少应选择1W或以上的电阻。
- 布局:采样电阻应放置在放电回路的负极路径上。连接BQ76920 SRP和SRN引脚的走线,必须从采样电阻的电压感知点(即开尔文连接点)直接引出,形成“电压感测环”,避免将功率电流路径的压降引入感测信号。
3.4 MOSFET驱动与负载控制
这是系统的执行机构,控制着电池包与外部世界的通断。
- 驱动电路:BQ76920的DSG和CHG引脚是开漏输出,需要外接上拉电阻和驱动三极管/MOSFET,去控制功率MOSFET的栅极。这里常用一个NPN三极管+PMOS的组合,或者专用的MOSFET驱动芯片。
- 功率MOSFET选型:主要看三个参数:耐压(Vds)、导通电阻(Rds(on))和连续电流(Id)。耐压必须高于电池包最高电压并留有余量(如20%)。导通电阻决定了导通损耗和发热。需要计算在最恶劣工况下的功耗,并确保MOSFET的结温在安全范围内,必要时加散热片。
- 体二极管与反向保护:功率MOSFET内部有体二极管。在放电回路中,这个体二极管的方向要防止电池被意外反向充电。有时需要在放电回路中串联一个肖特基二极管来增强反向阻断能力,但这会引入额外的压降和损耗。
4. 固件架构与关键代码实现
硬件是躯体,固件是灵魂。下面以模块化的方式,拆解整个C语言项目的核心代码逻辑。
4.1 工程结构与模块划分
一个清晰的工程结构是后期调试和功能扩展的基础。我的项目主要分为以下几个模块:
BMS_Project/ ├── Core/ │ ├── main.c │ ├── stm32f1xx_it.c │ └── system_stm32f1xx.c ├── Drivers/ │ ├── STM32F1xx_HAL_Driver/ │ └── BSP/ (板级支持包) │ ├── bq76920.c/.h │ ├── gpio.c/.h │ ├── i2c.c/.h │ ├── uart.c/.h │ └── timer.c/.h ├── Application/ │ ├── bms_core.c/.h // BMS核心状态机与保护算法 │ ├── bms_data.c/.h // 数据存储与滤波 │ ├── bms_comm.c/.h // 通信协议(如Modbus简易版) │ └── bms_ui.c/.h // 状态指示(LED)或简单显示 └── Middlewares/ (如果需要)4.2 BQ76920驱动层实现
这是与硬件打交道最直接的一层,稳定可靠的驱动是上层应用的基石。
1. 初始化序列(bq76920_init): 初始化绝不是简单地写几个配置寄存器。必须遵循数据手册规定的上电时序。
BQ76920_StatusTypeDef BQ76920_Init(void) { HAL_StatusTypeDef hal_status; // 1. 延时等待VDD稳定(手册要求至少1ms) HAL_Delay(10); // 2. 发送“唤醒”命令(如果芯片之前处于睡眠模式) uint8_t cmd = 0x0092; // 子命令:唤醒 hal_status = BQ76920_WriteSubCommand(cmd); if (hal_status != HAL_OK) return BQ76920_ERROR; HAL_Delay(2); // 等待内部振荡器稳定 // 3. 读取芯片ID,验证通信是否正常 uint8_t dev_id[2]; hal_status = BQ76920_ReadRegister(BQ76920_REG_DEVICE_ID, dev_id, 2); if (hal_status != HAL_OK || (dev_id[0] != 0x76)) { // 0x76是BQ76920的ID return BQ76920_DEVICE_ID_MISMATCH; } // 4. 配置保护阈值寄存器(OVP, UVP, OCC, OCD, SCD等) // 例如,设置单节过压保护为4.20V uint16_t ovp_threshold = (uint16_t)(4.20 / 0.001); // 寄存器单位是1mV uint8_t ovp_reg[2] = { (ovp_threshold >> 8) & 0xFF, ovp_threshold & 0xFF }; hal_status = BQ76920_WriteRegister(BQ76920_REG_OVP_THRESHOLD, ovp_reg, 2); // ... 配置其他阈值 // 5. 使能保护功能 uint8_t sys_ctrl2[2] = {0x00, 0x00}; sys_ctrl2[0] |= (1 << 5); // 使能放电过流保护 sys_ctrl2[0] |= (1 << 4); // 使能充电过流保护 // ... 其他使能位 hal_status = BQ76920_WriteRegister(BQ76920_REG_SYS_CTRL2, sys_ctrl2, 2); // 6. 配置ADC,开始转换 uint8_t adc_ctrl[2] = {0x00, 0x00}; adc_ctrl[0] = 0x30; // 例如,设置ADC自动模式,每250ms转换一次 hal_status = BQ76920_WriteRegister(BQ76920_REG_ADC_CTRL, adc_ctrl, 2); return (hal_status == HAL_OK) ? BQ76920_OK : BQ76920_ERROR; }实操心得:初始化失败,十有八九是I2C通信问题。务必先用逻辑分析仪或示波器抓一下I2C波形,看起始信号、地址、应答位是否正常。BQ76920的I2C地址通常是0x08(7位地址)。另外,上电后给芯片的复位引脚(如果有)一个明确的下拉脉冲,有时能解决一些玄学问题。
2. 数据读取与处理: 需要定期读取电压、电流、温度等数据。数据读取后,需要根据数据手册中的公式进行转换。
float BQ76920_ReadCellVoltage(uint8_t cell_num) { uint8_t reg_addr = BQ76920_REG_VC1_H + (cell_num * 2); // 电压寄存器地址是连续的 uint8_t v_data[2]; float voltage; if (BQ76920_ReadRegister(reg_addr, v_data, 2) != HAL_OK) { return 0.0f; } // 合并两个字节,数据是补码形式 int16_t raw_val = (v_data[0] << 8) | v_data[1]; // 转换公式:电压(V) = raw_val * 1.0mV (对于BQ76920) voltage = raw_val * 0.001f; // 加入简单的软件滤波,例如一阶低通滤波 static float filtered_voltage[MAX_CELLS] = {0}; float alpha = 0.2f; // 滤波系数,越小越平滑,响应越慢 filtered_voltage[cell_num] = alpha * voltage + (1 - alpha) * filtered_voltage[cell_num]; return filtered_voltage[cell_num]; }电流读取则需要注意符号(充电为负,放电为正)和量程。温度读取通常需要配置外部热敏电阻的电路参数,并在代码中根据查表法或公式计算温度值。
4.3 BMS核心状态机与保护逻辑
这是整个系统的“大脑决策层”。我采用了一个基于状态机(State Machine)的设计,使逻辑清晰,易于维护。
定义几个核心状态:
typedef enum { BMS_STATE_INIT, // 初始化 BMS_STATE_IDLE, // 空闲(未连接充电器或负载) BMS_STATE_DISCHARGING, // 放电中 BMS_STATE_CHARGING, // 充电中 BMS_STATE_FAULT, // 故障(保护触发) BMS_STATE_SLEEP // 睡眠(低功耗) } BMS_State_t;在主循环或定时器中断中,周期性地执行BMS_Run()函数:
void BMS_Run(void) { // 1. 读取所有传感器数据(电压、电流、温度) BMS_UpdateMeasurements(); // 2. 执行保护检查 BMS_ProtectionCheck(); // 3. 根据当前状态和检查结果,执行状态转移和动作 switch (g_bms.state) { case BMS_STATE_IDLE: if (g_bms.current > IDLE_TO_DISCHARGE_THRESHOLD) { g_bms.state = BMS_STATE_DISCHARGING; BMS_EnableDischargeFET(); // 闭合放电MOSFET } else if (g_bms.current < IDLE_TO_CHARGE_THRESHOLD) { // 充电电流为负 g_bms.state = BMS_STATE_CHARGING; BMS_EnableChargeFET(); // 闭合充电MOSFET } break; case BMS_STATE_DISCHARGING: // 检查是否应停止放电(如负载移除) if (fabs(g_bms.current) < CURRENT_DEADBAND) { g_bms.state = BMS_STATE_IDLE; BMS_DisableDischargeFET(); } // 其他状态内的逻辑... break; case BMS_STATE_FAULT: // 故障处理,如锁定、需要外部复位等 BMS_HandleFault(); break; // ... 其他状态处理 } // 4. 更新系统数据,如SOC(电量状态)估算 BMS_UpdateSOC(); // 5. 执行被动均衡(如果需要) BMS_DoCellBalancing(); }保护检查函数BMS_ProtectionCheck()是关键,它需要判断各种故障条件。这里以过压保护为例:
void BMS_ProtectionCheck(void) { bool fault_occurred = false; // 检查每一节电芯电压 for (int i = 0; i < TOTAL_CELLS; i++) { if (g_bms.cell_voltage[i] > OVP_THRESHOLD) { g_bms.fault_code |= FAULT_CELL_OVP; fault_occurred = true; // 可以记录是哪一节电芯触发的 g_bms.fault_cell = i; } if (g_bms.cell_voltage[i] < UVP_THRESHOLD) { g_bms.fault_code |= FAULT_CELL_UVP; fault_occurred = true; } } // 检查总电流 if (g_bms.current > DISCHARGE_OCP_THRESHOLD) { g_bms.fault_code |= FAULT_DISCH_OCP; fault_occurred = true; } if (g_bms.current < CHARGE_OCP_THRESHOLD) { // 充电电流为负值 g_bms.fault_code |= FAULT_CHG_OCP; fault_occurred = true; } // 检查温度 if (g_bms.temperature > OTP_THRESHOLD || g_bms.temperature < UTP_THRESHOLD) { g_bms.fault_code |= FAULT_OTP; fault_occurred = true; } if (fault_occurred) { g_bms.state = BMS_STATE_FAULT; BMS_DischargeFET_OFF(); // 立即关闭放电回路 BMS_ChargeFET_OFF(); // 立即关闭充电回路 // 可以触发报警,如点亮故障灯,发送故障码等 } }重要提示:保护阈值不要设置得“太紧”。例如,锂电池单节标准电压是4.2V,但过压保护点可以设在4.25V或4.28V,留出一定的缓冲区间,防止电压测量噪声或瞬间波动导致误保护。同样,欠压保护点也不要正好是3.0V,可以设在2.8V或2.9V。具体的阈值需要根据电芯的规格书和应用场景来仔细确定。
4.4 通信与调试接口
为了方便调试和集成,UART通信几乎是必须的。我实现了一个简单的命令行接口(CLI),通过串口助手发送指令,可以读取状态、参数,甚至修改某些配置(需谨慎)。
// 在串口中断或主循环中解析命令 void BMS_UART_RxCallback(uint8_t rx_data) { static char rx_buffer[64]; static int index = 0; if (rx_data == '\r' || rx_data == '\n') { // 回车或换行视为命令结束 rx_buffer[index] = '\0'; BMS_CLI_ParseCommand(rx_buffer); index = 0; memset(rx_buffer, 0, sizeof(rx_buffer)); } else if (index < sizeof(rx_buffer) - 1) { rx_buffer[index++] = rx_data; } } void BMS_CLI_ParseCommand(char* cmd) { if (strcmp(cmd, "read volt") == 0) { printf("Cell Voltages: "); for (int i = 0; i < TOTAL_CELLS; i++) { printf("C%d: %.3fV ", i+1, g_bms.cell_voltage[i]); } printf("\r\n"); } else if (strcmp(cmd, "read current") == 0) { printf("Current: %.3fA\r\n", g_bms.current); } else if (strcmp(cmd, "read status") == 0) { printf("State: %d, SOC: %.1f%%, Fault: 0x%04X\r\n", g_bms.state, g_bms.soc, g_bms.fault_code); } else if (strncmp(cmd, "set ovp ", 8) == 0) { float val = atof(cmd + 8); // 这里需要做参数范围检查和安全验证! OVP_THRESHOLD = val; printf("OVP set to %.3fV\r\n", val); } else { printf("Unknown command: %s\r\n", cmd); printf("Supported: read volt, read current, read status, set ovp X.XXX\r\n"); } }5. 开发调试全流程与避坑指南
从画板子到代码跑通,每一步都可能遇到“坑”。这里把我印象最深的几个问题和解决方法记录下来。
5.1 硬件调试:上电前的生死检查
- 目视与通断检查:PCB到手后,先别急着上电。用放大镜仔细检查有无短路、虚焊、连锡,特别是电源网络和BQ76920的采样引脚。用万用表蜂鸣档检查所有VCC和GND之间是否短路。
- 分步上电:不要一次性接上电池。先用可调电源,从低电压(比如5V)给3.3V LDO输入端供电,测量3.3V输出是否正常,STM32能否下载程序。然后再逐步接入电池电压。
- BQ76920通信测试:写一个最简单的I2C扫描程序,看是否能读到0x08地址的设备。如果读不到,检查:
- I2C上拉电阻(通常4.7kΩ)是否焊上。
- BQ76920的VDD电压是否在允许范围内。
- SDA, SCL线路是否被其他器件意外拉低。
- 特别注意:BQ76920的I2C引脚电平由其VDD决定(可能是3.3V或5V),必须与STM32的I/O电平兼容。如果不兼容,需要电平转换。
5.2 软件调试:从寄存器到保护逻辑
- 寄存器读写验证:先不写复杂逻辑,就写一个函数循环读取BQ76920的器件ID(Device ID)寄存器。这是验证通信链路是否正常的最直接方法。如果读出的ID不对,检查I2C时序(用逻辑分析仪)、地址(7位地址是0x08,写地址0x10,读地址0x11)和读写协议(BQ76920使用子命令机制,写寄存器需要先写子命令地址,再写数据)。
- 电压读数跳变:如果读出的电压值不稳定,跳动很大:
- 硬件层面:检查采样走线是否受到干扰,电源滤波电容是否足够且靠近芯片引脚。模拟地(AGND)和数字地(DGND)的布局单点连接是否合理。
- 软件层面:加入软件滤波,如一阶低通滤波(如上文代码所示)。适当降低ADC的采样速率(在ADC_CTRL寄存器中配置),牺牲一点速度换取稳定性。
- 电流读数不准或为零:
- 检查采样电阻的焊接和选型是否正确。
- 检查BQ76920的
SYS_CTRL1寄存器中,电流ADC是否被使能。 - 确认电流读数的转换公式。电流寄存器值是有符号的补码,需要正确转换为有符号整数再计算成安培数。量程(Range)寄存器的设置也会影响转换系数。
- 保护功能不动作或误动作:
- 不动作:检查保护阈值寄存器是否配置正确,单位是否是mV/mA。检查
SYS_CTRL2寄存器中相应的保护功能是否被使能(Enabled)。检查芯片的CHG/DSG引脚输出是否正常,驱动电路能否有效开关MOSFET。 - 误动作:通常是阈值设置太接近正常工作点,或者传感器数据噪声太大。首先用滤波后的数据做保护判断。其次,可以引入“去抖”机制,例如连续N个周期(如3-5个)都触发保护条件,才执行保护动作,避免单次噪声干扰。
- 不动作:检查保护阈值寄存器是否配置正确,单位是否是mV/mA。检查
5.3 系统集成与老化测试
当单个功能都调通后,需要进行系统级测试。
- 充放电循环测试:接上电子负载和可编程电源,模拟真实的充放电过程。观察在不同电流下,电压、电流测量是否准确,保护点是否正确触发。
- 边界条件测试:
- 将某节电池电压单独调高,测试过压保护。
- 模拟负载短路(在安全限流条件下),测试短路保护(SCD)响应速度。
- 将电池包置于高低温环境(如用电吹风或冰袋),测试温度保护。
- 功耗与睡眠测试:如果设备有低功耗要求,需要测试BMS在睡眠模式下的电流。BQ76920本身有低功耗模式,STM32也可以进入Stop模式。确保唤醒机制(如按键、充电器插入)工作正常。
- 通信压力测试:长时间运行,通过UART持续发送读取命令,看系统是否会死机或数据异常。这有助于发现潜在的堆栈溢出、内存泄漏或看门狗问题。
6. 项目源码结构与使用指南
我的项目源码托管在GitHub上,结构清晰,注释也比较详细。这里简单介绍一下核心文件和使用方法。
获取与编译:
- 使用Git克隆仓库,或者直接下载ZIP包。
- 使用STM32CubeIDE、Keil MDK或IAR等IDE打开项目。
- 主要硬件配置在
Drivers/BSP/Inc/bsp.h中,如使用的I2C端口、UART端口、引脚定义等,需要根据你自己的PCB进行修改。 - 电池参数(如串数、容量、保护阈值)在
Application/Inc/bms_config.h中集中配置。这是你移植时最需要修改的地方。
关键配置文件bms_config.h示例:
#ifndef __BMS_CONFIG_H #define __BMS_CONFIG_H // 电池包配置 #define TOTAL_CELLS (3) // 电池串联节数 #define BATTERY_CAPACITY_AH (5.0f) // 电池容量,安时 // 保护阈值 (务必根据电芯规格书调整!) #define CELL_OVP_THRESHOLD (4.25f) // 单节过压保护点 (V) #define CELL_UVP_THRESHOLD (2.80f) // 单节欠压保护点 (V) #define CELL_OVP_RECOVER (4.15f) // 过压恢复点 (V) #define CELL_UVP_RECOVER (3.00f) // 欠压恢复点 (V) #define DISCHARGE_OCP_THRESHOLD (15.0f) // 放电过流 (A) #define CHARGE_OCP_THRESHOLD (-5.0f) // 充电过流 (A, 负值) #define SHORT_CIRCUIT_THRESHOLD (50.0f) // 短路保护 (A) #define OTP_THRESHOLD (60.0f) // 过温保护 (摄氏度) #define UTP_THRESHOLD (-10.0f) // 低温保护 (摄氏度) // 电流检测参数 (根据采样电阻调整) #define SHUNT_RESISTOR (0.005f) // 采样电阻阻值 (欧姆) #define CURRENT_ADC_GAIN (20.0f) // BQ76920内部PGA增益 (根据配置) // 系统参数 #define VOLTAGE_FILTER_ALPHA (0.2f) // 电压滤波系数 #define CURRENT_FILTER_ALPHA (0.3f) // 电流滤波系数 #define SOC_UPDATE_INTERVAL_MS (1000) // SOC估算更新间隔 #endif /* __BMS_CONFIG_H */快速上手:
- 修改
bms_config.h适配你的电池。 - 检查
bsp.h中的引脚定义,确保与你的原理图一致。 - 编译并下载到STM32。
- 通过串口助手(波特率115200)连接板子,发送
read status等命令查看系统状态。 - 接上电池和负载,开始测试。
最后的建议:锂电池管理是安全攸关的系统。这个开源项目提供了一个完整的、经过验证的框架和思路,但请勿直接用于商业产品或对安全有极高要求的场合。在实际应用前,务必进行充分的测试和验证,特别是各种故障情况的模拟。建议在资深硬件工程师的指导下进行。希望这个项目能成为你探索电池管理世界的一块有用的垫脚石。如果在移植或使用中遇到问题,欢迎在项目仓库的Issues里讨论,共同完善它。
本文还有配套的精品资源,点击获取