一、作品简介
作品名称: 机器人/自制飞机航电用不间断备用应急电源系统
功能介绍:
本项目目标是设计一套面向机器人及自制飞机航电系统的不间断备用应急电源系统。包含电池包部分及CANHUB充电和电源路径管理两大部分,此处主要介绍电池包部分。
系统采用 MPS 公司的 MP2797 电池监测保护器和 MPF42790 电量计芯片,以及MP4201双向升降压芯片,构建 4S1P 锂电池组(4节串联)的完整电池管理方案。通过 I2C 总线,外部 MCU 可实时读取各节电池电压、充放电电流、电池温度、剩余电量(SOC)和健康状态(SOH),并配置过压、欠压、过流、短路等多级保护阈值。当系统检测到异常时,MP2797 自动关断充放电 MOSFET,切断回路以保护电池和负载安全。系统还集成被动均衡功能,延长电池组循环寿命,并通过板载 5 路 LED 指示灯直观显示电量状态,这样电池包可以独立工作,方便作为通用电池包。并板载了MP4201作为Charger功能,同时兼顾升降压输出。
物料清单及简介
本系统核心物料均采用 MPS 芯片方案,配合标准被动元件实现完整 BMS 功能。
核心 IC
- MPS 必选物料
| 型号 | 功能描述 | 封装 | |
|---|---|---|---|
| MP4201 | 100V、25A、同步双向升降压控制器,带 I2C接口、电池充电和可调节 OCP | QFN-32 | |
| MP2797 | 7-16节电池监测保护器,集成16位ADC、充放电保护、被动均衡、I2C通信 | TQFP-48 |
- 可选物料
| 型号 | 功能描述 | 封装 | |
|---|---|---|---|
| MPF42790 | 1-4节电池电量计,提供SOC/SOH估算、5路LED电量指示 、I2C通信 | QFN-32 | |
- 自备辅助物料
| 型号 | 功能描述 | 封装 | |
|---|---|---|---|
| stm32f103c8t6 | (刚好以前买了不少,有啥用啥)最常见通用mcu | LQFP-48 | |
| SN65HVD230DR | CAN收发器 | SOP-8 |
- 功率器件
| 型号 | 参数 | 功能描述 | 封装 | |
|---|---|---|---|---|
| SI4435DDY | P-MOS, 30V/8A | 充电回路保护开关 | SO-8 | |
| SI4435DDY | P-MOS, 30V/8A | QFN-32 | SO-8 | |
| 0R005/1%3W | 5mR | 电流采样电阻 | 2512 |
二、系统框图
设计思路
本项目面向机器人及自制飞机航电系统的应急供电需求。在无人机飞行或机器人运行过程中,主电源可能因故障、电量耗尽或线路问题突然中断,此时需要一套不间断备用应急电源立即接管供电,保证关键航电设备(飞控、传感器、通信模块)不丢失数据并安全降落或返回。
设计核心思路如下:
高可靠性保护:选用 MP2797 实现硬件级电池保护(OVP/UVP/OCC/OCD/SCD),无需 MCU 干预即可在微秒级响应异常,这个对简化软件设计很重要
精确电量管理:选用 MPF42790 提供库仑计功能,精确估算 SOC/SOH,配合 LED 直观显示剩余电量,同时也可以通过IIC总线读取相关电量数据,在显示屏上直接显示系统剩余工作时间(基于剩余电量估算)
统一通信控制:两颗芯片共享 I2C 总线,外部 MCU 通过标准 I2C 协议即可完成全部配置与数据读取,能够实现更加方便读取丰富参数
被动均衡延寿:每节电池配 100k 均衡电阻,充电时自动平衡各节电压,延长电池组循环寿命。这里未采用主动均衡策略,虽然MP279x系列支持该功能,但因为设计里该电池使用到的次数极其有限,就不搞那么复杂了。
三、系统软硬件介绍
硬件架构
硬件系统以 MP2797 为核心保护芯片,MPF42790 为辅助电量计芯片,两者通过共享 I2C 总线与外部 MCU 通信。MP2797 直接连接 4 节串联电池组(C0~C3),通过内部 16 位 ADC 采集各节电压、差分采样电流(SRP/SRN)、采样 NTC 温度。保护输出通过 CHG/DSG 引脚驱动两只背靠背 P-MOSFET,控制充放电回路的通断。MPF42790 从 MP2797 共享的 I2C 总线获取电池数据,进行电量计算并驱动 5 路 LED 指示灯。
图1:系统整体架构框图
3.1 电池电压监测与均衡电路
4S1P 电池组的 4 节电池通过 C0~C3 引脚直接连接到 MP2797,芯片内部多路复用器(MUX)依次选通各节电池,通过 16 位 ADC 采样电压。每节电池配接一只 100k 均衡电阻,当某节电池电压超过均衡阈值时,MP2797 自动开启该节电池的内部均衡开关,通过外接均衡电阻放电,使各节电池电压趋于一致。
图2:电池电压监测与被动均衡电路
均衡电流: 100k 均衡电阻在 4.2V 电池电压下提供约 42uA 的均衡电流。对于 18650 电池(容量 2000~3000mAh),该均衡速率可在几个小时内完成电压平衡,适用于日常充电场景。
3.2 电流采样电路
电流采样使用 5mR 低阻值精密采样电阻(R_SENSE),串联在电池负极与 PACK- 之间。MP2797 的 SRP 和 SRN 引脚差分采样电阻两端的微弱压降,内部放大后由 ADC 转换为电流值。该设计可同时测量充电电流和放电电流(双向),精度优于 1%。
采样电阻参数:
| 参数 | 值 |
|---|---|
| 阻值 | 5mR (0.005Ω) |
| 精度 | 1% |
| 额定功率 | 3W(支持最大约 24A 持续电流) |
| 封装 | 2512(满足散热要求) |
| 连接方式 | Kelvin 四线制(PCB 布局需独立引出 SRP/SRN 采样走线) |
3.3 温度监测电路
使用 10k NTC 热敏电阻(B=3950)连接到 MP2797 的 NTC1 引脚,配合 10k 偏置电阻(R_NTCB)组成分压网络。MP2797 内部 ADC 采样分压电压,通过 NTC 阻值-温度查找表计算实际温度。当温度超过设定阈值(过热保护/低温充电保护)时,MP2797 自动限制或禁止充放电。
图3:NTC温度监测电路原理
3.4 充放电保护 MOSFET 电路
系统使用两只 SI4435DDY P沟道 MOSFET 背靠背连接,分别由 MP2797 的 CHG 和 DSG 引脚驱动控制:
- Q_CHG(充电 MOSFET):控制充电回路。发生过压(OVP)时关断,停止充电
- Q_DSG(放电 MOSFET):控制放电回路。发生欠压(UVP)、过流(OCD)、短路(SCD)时关断,停止放电
两只 MOSFET 源极共接电池正极(TOP),漏极共接 PACK+ 输出端
背靠背结构确保充放电回路可独立控制,且关断时无体二极管反向漏电
保护响应时间:
| 保护类型 | 响应时间 | 说明 |
|---|---|---|
| 短路保护 (SCD) | < 1ms | 最快响应,防止电池损坏或起火 |
| 过流保护 (OCD/OCC) | ~ 10ms | 滤除瞬态脉冲后触发 |
| 过压/欠压保护 (OVP/UVP) | ~ 100ms | ADC 周期采样后触发 |
3.5 I2C 通信接口
MP2797 和 MPF42790 共享同一条 I2C 总线,通过 SCL(时钟线)和 SDA(数据线)与外部 MCU 通信。两根线上各接 4.7k 上拉电阻,上拉至 MP2797 的 VDD(3.3V LDO 输出)。两颗芯片拥有不同的 I2C 从机地址,MCU 通过地址区分访问对象。
| 芯片 | 默认 I2C 地址 | 说明 |
|---|---|---|
| MP2797 | 0x40 (7位) | 可通过 ADDR 引脚配置 |
| MPF42790 | 0x50 (7位) | 独立于 MP2797,无冲突 |
外部 MCU 通过 I2C 端口连接到 SCL/SDA 总线,可实现:
- 读取各节电池实时电压(精度 ±5mV)
- 读取充放电电流(精度 ±1%)
- 读取电池温度(精度 ±1°C)
- 配置保护阈值(OVP/UVP/OCC/OCD/SCD)
- 读取故障状态和保护触发记录
- 控制均衡开关(手动/自动模式)
- 读取 SOC/SOH/剩余时间等电量信息
3.6 电源管理电路
MP2797 的电源直接来自电池组(通过 REGIN 引脚输入),内部 LDO 产生 3.3V(3V3 引脚)和 VDD 供电。每个电源引脚都配有旁路电容以确保稳定性。MPF42790 的电源可独立供电或从 MP2797 的 3.3V LDO 取电。
3.7 状态指示电路
MPF42790 内置 5 路 LED 驱动输出(LED1~LED5),每路串联 1k 限流电阻后驱动 SMD LED。LED 负极接地(GND),当 MPF42790 输出低电平时 LED 点亮。5 颗 LED 以阶梯方式显示电池剩余电量:
| LED 点亮数 | 电量范围 |
|---|---|
| 1 LED | 0~25% |
| 2 LED | 25~50% |
| 3 LED | 50~75% |
| 4 LED | 75~95% |
| 5 LED | 95~100% 满电 |
四、作品源码
本作品暂不需要源码,实际电量等信息是通过CANBUS板子上的MCU通过IIC接口读取,不过那部分暂时还没设计完成,后续完成了再补充吧。
→补充项目代码
Fuel Gauge_BMS.zip (6.3 MB)
→关键代码
【MPF42790驱动】
/*
* MP_BMS 项目 —— U5 MPF42790 电池电量计测试驱动
* 芯片:MPS MPF42790(2-16 串电池包电量计)
* 接口:I2C2 软件模拟(PB10=SCL / PB11=SDA,开漏)
* 控制:CE=PB0(高使能)、RST=PB1(高=运行)
* 协议:从机地址 0x08;16 位寄存器地址(低字节在前)+ Length 字段;
* 通信前 SDA 拉低 >=5ms 唤醒;CRC 默认使能,启动时用官方消息禁用。
* 参考:MPF42790 Rev.1.0 datasheet(MPS)
* Change Logs:
* Date Author Notes
* 2026-07-23 MP_BMS 首次创建(仅测试 MPF42790 电量计)
*/
#include "bsp_mpf42790.h"
#include "board.h"
#include "stdio.h"
/* ================== I2C2 引脚操作 ================== */
#define MPF_SCL(x) ((x) ? GPIO_SetBits(MPF_SCL_PORT, MPF_SCL_PIN) \
: GPIO_ResetBits(MPF_SCL_PORT, MPF_SCL_PIN))
#define MPF_SDA(x) ((x) ? GPIO_SetBits(MPF_SDA_PORT, MPF_SDA_PIN) \
: GPIO_ResetBits(MPF_SDA_PORT, MPF_SDA_PIN))
#define MPF_SDA_GET() GPIO_ReadInputDataBit(MPF_SDA_PORT, MPF_SDA_PIN)
static void MPF_SDA_OUT(void)
{
字数限制,只能省略
}
static void MPF_SDA_IN(void)
{
字数限制,只能省略
}
/* ================== 引脚初始化 ================== */
void MPF42790_Init(void)
{
字数限制,只能省略
}
void MPF42790_SetCe(uint8_t on)
{
if (on) { MPF_CE_H(); } else { MPF_CE_L(); }
}
void MPF42790_SetRst(uint8_t on)
{
if (on) { MPF_RST_H(); } else { MPF_RST_L(); }
}
/* ================== 软件 I2C 底层时序 ================== */
static void MPF_IIC_Start(void)
{
字数限制,只能省略
}
static void MPF_IIC_Stop(void)
{
字数限制,只能省略
}
static uint8_t MPF_IIC_WaitAck(void)
{
字数限制,只能省略
}
static void MPF_IIC_Write(uint8_t data)
{
字数限制,只能省略
}
}
static uint8_t MPF_IIC_Read(void)
{
字数限制,只能省略
}
return data;
}
static void MPF_IIC_SendAck(uint8_t nack) /* 0=ACK 1=NACK */
{
字数限制,只能省略
}
/* ================== 唤醒(active mode) ==================
* 从 standby 唤醒:SDA 拉低 >=5ms(SCL 保持高),唤醒后约 20ms 超时窗口 */
static void MPF42790_Wake(void)
{
字数限制,只能省略
}
/* ================== 禁用 CRC(0x4100=0x08) ==================
* I2C_CRC_EN 默认=1,写命令必须带正确 CRC 才被接受。
* 使用 datasheet 提供的官方消息(含 CRC),同时把从机地址固定为 0x08。
* 之后写事务无需 CRC;读事务本就不返回 CRC。返回 0=成功 */
uint8_t MPF42790_DisableCrc(void)
{
字数限制,只能省略
}
/* ================== 写事务 ==================
* 帧:START + [addr<<1|W] + [reg_L] + [reg_H] + [len] + [data...] + STOP */
uint8_t MPF42790_Write(uint16_t reg, uint8_t len, const uint8_t *buf)
{
字数限制,只能省略
}
/* ================== 读事务 ==================
* 帧:START + [addr<<1|W] + [reg_L] + [reg_H] + [len] + Sr + [addr<<1|R]
* + [data...] + NACK + STOP(从机不返回 CRC) */
uint8_t MPF42790_Read(uint16_t reg, uint8_t len, uint8_t *buf)
{
字数限制,只能省略
}
/* ================== 读并打印 IC 软件版本(0x6100, 40bit ASCII) ==================
* 42790: 2 to 16 cells in series with LED support
* 返回 5 字节 ASCII,例如 "42790" 或版本字符串 */
void MPF42790_PrintVersion(void)
{
uint8_t buf[5];
uint8_t i;
if (MPF42790_Read(MPF_REG_IC_VER, 5, buf) == 0) {
printf("IC_VER=\"");
for (i = 0; i < 5; i++) {
printf("%c", (buf[i] >= 0x20 && buf[i] <= 0x7E) ? buf[i] : '.');
}
printf("\" (hex ");
for (i = 0; i < 5; i++) { printf("%02X", buf[i]); }
printf(")\r\n");
} else {
printf("IC_VER read failed\r\n");
}
}
/* ================== 完整测试 ================== */
void MPF42790_Test(void)
{
uint8_t buf[8];
uint8_t i;
uint32_t mv, soc;
int32_t cur;
printf("\r\n===== U5 MPF42790 Fuel Gauge Test (I2C2: PB10=SCL PB11=SDA) =====\r\n");
printf("CE=PB0(%d) RST=PB1(%d)\r\n", (GPIO_ReadOutputDataBit(MPF_CE_PORT, MPF_CE_PIN) != 0),
(GPIO_ReadOutputDataBit(MPF_RST_PORT, MPF_RST_PIN) != 0));
/* 1. 硬件复位(RST 拉低 5ms 再拉高) */
MPF42790_SetRst(0);
delay_ms(5);
MPF42790_SetRst(1);
delay_ms(100);
/* 2. 禁用 CRC + 固定从机地址 0x08(官方消息自带 CRC,幂等) */
if (MPF42790_DisableCrc() != 0) {
printf("ERROR: MPF42790 no ACK!\r\n");
printf("Check: CE/RST wiring, I2C2 pull-ups, U5 power.\r\n");
return;
}
printf("I2C slave 0x%02X connected, CRC disabled.\r\n", MPF_I2C_ADDR);
/* 3. 读 IC 软件版本(0x6100, 40bit ASCII) */
MPF42790_PrintVersion();
/* 4. 触发一次电量计算(EXE_CMD=0x01) */
buf[0] = 0x01;
MPF42790_Write(MPF_REG_EXE_CMD, 1, buf);
/* 5. 等待计算完成(FG_EXE_FLAG bit0 = 0) */
buf[0] = 0xFF;
for (i = 0; i < 100; i++) {
if (MPF42790_Read(MPF_REG_FG_EXE_FLAG, 1, buf) == 0 && (buf[0] & 0x01) == 0) {
break;
}
delay_ms(10);
}
printf("FG_EXE_FLAG = 0x%02X (%s)\r\n", buf[0],
(i >= 100) ? "timeout" : "done");
/* 6. 读 pack 电压 / SOC / 电流 */
if (MPF42790_Read(MPF_REG_VRDG_PACK, 2, buf) == 0) {
mv = ((uint32_t)((buf[1] << 8) | buf[0])) * 2u; /* LSB=2mV */
printf("VRDG_PACK = %d.%03dV\r\n", (int)(mv / 1000), (int)(mv % 1000));
}
if (MPF42790_Read(MPF_REG_SOC_PACK, 2, buf) == 0) {
soc = ((uint32_t)((buf[1] << 8) | buf[0])) * 2u; /* LSB=0.002% */
printf("SOC_PACK = %d.%03d%%\r\n", (int)(soc / 1000), (int)(soc % 1000));
}
if (MPF42790_Read(MPF_REG_IRDG_CELL1, 4, buf) == 0) {
cur = (int32_t)((uint32_t)buf[0] | ((uint32_t)buf[1] << 8) |
((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24)); /* LSB=1mA */
printf("IRDG_CELL1 = %s%d.%03d A\r\n", (cur < 0) ? "-" : "",
(int)((cur >= 0 ? cur : -cur) / 1000),
(int)((cur >= 0 ? cur : -cur) % 1000));
}
/* 7. 读 16 节电芯电压输入(VRDG_CELL1..16,0.1mV LSB,非 0 才打印) */
printf("-- VCELL input (0.1mV LSB) --\r\n");
for (i = 0; i < 16; i++) {
if (MPF42790_Read((uint16_t)(MPF_REG_VRDG_CELL1 + i * 2), 2, buf) == 0) {
uint16_t v = (uint16_t)((buf[1] << 8) | buf[0]);
if (v != 0) {
/* 0.1mV LSB:v=42435 -> 4.2435V */
printf("CELL%-2d = %d.%04dV\r\n", i + 1, (int)(v / 10000), (int)(v % 10000));
}
}
}
printf("--- MPF42790 Test done ---\r\n");
}
/* ================== 主循环刷新(只读,不触发计算) ==================
* 每轮循环读取:SOC + 电流(软件版本仅在 Test 中读取一次,不循环) */
void MPF42790_Refresh(void)
{
uint8_t buf[8];
uint32_t soc;
int32_t cur;
if (MPF42790_Read(MPF_REG_SOC_PACK, 2, buf) == 0) {
soc = ((uint32_t)((buf[1] << 8) | buf[0])) * 2u; /* LSB=0.002% */
printf("SOC=%d.%03d%% ", (int)(soc / 1000), (int)(soc % 1000));
} else {
printf("SOC=N/A ");
}
if (MPF42790_Read(MPF_REG_IRDG_CELL1, 4, buf) == 0) {
cur = (int32_t)((uint32_t)buf[0] | ((uint32_t)buf[1] << 8) |
((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24));
printf("I=%s%d.%03dA\r\n", (cur < 0) ? "-" : "",
(int)((cur >= 0 ? cur : -cur) / 1000),
(int)((cur >= 0 ? cur : -cur) % 1000));
} else {
printf("I=N/A\r\n");
}
}
【MP4201双向DCDC驱动】
/*
* MP_BMS 项目 —— MP4201 双向升降压控制器测试驱动
* 芯片:MPS MP4201(100V 同步双向 Buck-Boost 控制器)
* 接口:PMBUS/I2C(最高 1MHz,典型 400kHz)
* 硬件:CH_I2C = PB8(SCL) / PB9(SDA);CH_EN=PA8;DIR=PB15;CH_IRQ=PB13(ALT#)
* 参考:MP4201 - Published Internal Datasheet(MPS)
* 适用:STM32F103C8T6 标准库工程
* Change Logs:
* Date Author Notes
* 2026-07-22 MP_BMS 首次创建(由 SHT20 测试工程改造)
*/
#include "bsp_mp4201.h"
#include "board.h"
#include "stdio.h"
/******************************************************************
* 函数名称:MP4201_I2C_Scan
* 函数说明:扫描 I2C 总线(PB8=SCL/PB9=SDA)上 8 位地址全空间(0x00~0xFF),
* 即全部 7 位地址(含保留/广播地址)的写/读两个方向都探测,
* 探测各地址是否有从机 ACK 应答(仅发地址,不写任何数据,无副作用)
* 注意:0x00 为通用呼叫地址,可能被多个从机 ACK 而误报
* 函数形参:found=输出已找到的 8 位地址数组(可为 NULL 仅计数) max=数组容量
* 函数返回:找到的设备数量
******************************************************************/
uint8_t MP4201_I2C_Scan(uint8_t *found, uint8_t max)
{
uint16_t addr8; /* 必须 16bit:uint8_t 会在 0xFF+1 后回绕为 0 导致死循环 */
uint8_t count = 0;
for (addr8 = 0x00; addr8 < 0x100; addr8++) {
MP4201_IIC_Start();
MP4201_IIC_Write(addr8); /* 8 位地址字节(7 位地址 + R/W 位) */
if (MP4201_IIC_Wait_Ack() == 0) { /* 从机应答 = 在线 */
if (found && count < max) {
found[count] = addr8;
}
count++;
MP4201_IIC_Stop();
}
/* 无应答时 Wait_Ack 内部已发出 Stop,无需重复操作 */
delay_us(5);
}
return count;
}
/******************************************************************
* 函数名称:MP4201_I2C2_Scan
* 函数说明:扫描 I2C2(PB10=SCL/PB11=SDA)上 8 位地址全空间(0x00~0xFF),
* 即全部 7 位地址(含保留/广播地址)的写/读两个方向都探测,
* 探测各地址是否有从机 ACK 应答(仅发地址,不写任何数据,无副作用)
* 注意:0x00 为通用呼叫地址,可能被多个从机 ACK 而误报
* 函数形参:found=输出已找到的 8 位地址数组(可为 NULL 仅计数) max=数组容量
* 函数返回:找到的设备数量
******************************************************************/
uint8_t MP4201_I2C2_Scan(uint8_t *found, uint8_t max)
{
uint16_t addr8; /* 必须 16bit:uint8_t 会在 0xFF+1 后回绕为 0 导致死循环 */
uint8_t count = 0;
GPIO_InitTypeDef GPIO_InitStructure;
/* 初始化 PB10/PB11 为开漏输出(重复调用安全) */
RCC_APB2PeriphClockCmd(RCC_MP4201_I2C2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_MP4201_I2C2_SCL | GPIO_MP4201_I2C2_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PORT_MP4201_I2C2, &GPIO_InitStructure);
MP4201_I2C2_SCL(1);
MP4201_I2C2_SDA(1);
for (addr8 = 0x00; addr8 < 0x100; addr8++) {
MP4201_IIC2_Start();
MP4201_IIC2_Write(addr8); /* 8 位地址字节(7 位地址 + R/W 位) */
if (MP4201_IIC2_Wait_Ack() == 0) { /* 从机应答 = 在线 */
if (found && count < max) {
found[count] = addr8;
}
count++;
MP4201_IIC2_Stop();
}
/* 无应答时 Wait_Ack 内部已发出 Stop,无需重复操作 */
delay_us(5);
}
return count;
}
/******************************************************************
* 函数名称:MP4201_ScanAddr
* 函数说明:扫描 4 个可能的 I2C 从机地址,判断 MP4201 是否在线
* 函数返回:找到的地址(0x27/0x2F/0x37/0x3F),未找到返回 0
******************************************************************/
uint8_t MP4201_ScanAddr(void)
{
uint8_t addrs[4] = {
MP4201_ADDR_GND, MP4201_ADDR_1_3_VCC,
MP4201_ADDR_2_3_VCC, MP4201_ADDR_VCC
};
uint8_t i;
uint16_t dummy = 0;
for (i = 0; i < 4; i++) {
/* 无副作用探测:读取 STATUS_WORD,从机应答即在线 */
if (MP4201_ReadWord(addrs[i], MP4201_REG_STATUS_WORD, &dummy) == 0) {
return addrs[i];
}
}
return 0;
}
/******************************************************************
* 函数名称:MP4201_SetOperation
* 函数说明:输出开关控制(EN 引脚优先级高于 OPERATION 寄存器)
* 函数形参:on = 1 开启输出,0 关闭输出
******************************************************************/
void MP4201_SetOperation(uint8_t addr, uint8_t on)
{
MP4201_WriteByte(addr, MP4201_REG_OPERATION, on ? MP4201_OP_ON : MP4201_OP_OFF);
}
/******************************************************************
* 函数名称:MP4201_ClearFaults
* 函数说明:清除所有故障标志
******************************************************************/
void MP4201_ClearFaults(uint8_t addr)
{
MP4201_SendCommand(addr, MP4201_REG_CLEAR_FAULTS);
}
/******************************************************************
* 函数名称:MP4201_ReadStatusWord
* 函数说明:读状态字 STATUS_WORD(79h),详见 MP4201_SW_* 宏
******************************************************************/
uint16_t MP4201_ReadStatusWord(uint8_t addr)
{
uint16_t data = 0;
MP4201_ReadWord(addr, MP4201_REG_STATUS_WORD, &data);
return data;
}
/******************************************************************
* 函数名称:MP4201_ReadStatusTemperature
* 函数说明:读温度状态 STATUS_TEMPERATURE(7Dh)
******************************************************************/
uint8_t MP4201_ReadStatusTemperature(uint8_t addr)
{
uint16_t data = 0;
MP4201_ReadWord(addr, MP4201_REG_STATUS_TEMPERATURE, &data);
return (uint8_t)data;
}
/******************************************************************
* 函数名称:MP4201_ReadVIN
* 函数说明:读输入电压 READ_VIN(88h),VIN(V) = Y × 0.0832
******************************************************************/
float MP4201_ReadVIN(uint8_t addr)
{
uint16_t data = 0;
MP4201_ReadWord(addr, MP4201_REG_READ_VIN, &data);
return (data & 0x03FF) * 0.0832f;
}
/******************************************************************
* 函数名称:MP4201_ReadIIN
* 函数说明:读输入电流 READ_IIN(89h),IIN(A) = Y × 0.043
******************************************************************/
float MP4201_ReadIIN(uint8_t addr)
{
uint16_t data = 0;
MP4201_ReadWord(addr, MP4201_REG_READ_IIN, &data);
return (data & 0x03FF) * 0.043f;
}
/******************************************************************
* 函数名称:MP4201_ReadVOUT
* 函数说明:读输出电压 READ_VOUT(8Bh),VOUT(V) = Y × 0.0832
******************************************************************/
float MP4201_ReadVOUT(uint8_t addr)
{
uint16_t data = 0;
MP4201_ReadWord(addr, MP4201_REG_READ_VOUT, &data);
return (data & 0x03FF) * 0.0832f;
}
/******************************************************************
* 函数名称:MP4201_ReadIOUT
* 函数说明:读输出电流 READ_IOUT(8Ch),IOUT(A) = Y × 0.043
******************************************************************/
float MP4201_ReadIOUT(uint8_t addr)
{
uint16_t data = 0;
MP4201_ReadWord(addr, MP4201_REG_READ_IOUT, &data);
return (data & 0x03FF) * 0.043f;
}
/******************************************************************
* 函数名称:MP4201_ReadTemperature
* 函数说明:读结温 READ_TEMPERATURE(8Dh),T(°C) = -272.48 + 1.07×Y
* Y 为 10bit 二进制补码
******************************************************************/
float MP4201_ReadTemperature(uint8_t addr)
{
uint16_t data = 0;
int16_t y;
MP4201_ReadWord(addr, MP4201_REG_READ_TEMPERATURE, &data);
y = (int16_t)(data & 0x03FF);
if (y & 0x0200) { /* 10bit 符号扩展 */
y |= (int16_t)0xFC00;
}
return -272.48f + 1.07f * (float)y;
}
/******************************************************************
* 函数名称:MP4201_SetVout
* 函数说明:设置输出电压(内部反馈 FB=32)
* 公式:Vout(V) = V × 0.625mV × 32 / 1000,即 V = Vout / 0.02
* 形参:vout_v 目标电压(内部反馈时有效范围 3.2V~81.92V)
******************************************************************/
void MP4201_SetVout(uint8_t addr, float vout_v)
{
uint16_t v;
if (vout_v < 3.2f) vout_v = 3.2f;
if (vout_v > 81.92f) vout_v = 81.92f;
v = (uint16_t)(vout_v * 1000.0f / (MP4201_VOUT_LSB_MV * MP4201_FB_RATIO) + 0.5f);
MP4201_WriteWord(addr, MP4201_REG_VOUT_COMMAND, v);
}
/******************************************************************
* 函数名称:MP4201_SetIoutOcLimit
* 函数说明:设置输出过流保护门限,IOUT_OC(A) = Y × 0.05
******************************************************************/
void MP4201_SetIoutOcLimit(uint8_t addr, float amp)
{
uint16_t v;
v = (uint16_t)(amp / 0.05f + 0.5f);
MP4201_WriteWord(addr, MP4201_REG_IOUT_OC_FAULT_LIMIT, v);
}
/******************************************************************
* 函数名称:MP4201_SetIinOcLimit
* 函数说明:设置输入过流保护门限,IIN_OC(A) = Y × 0.05
******************************************************************/
void MP4201_SetIinOcLimit(uint8_t addr, float amp)
{
uint16_t v;
v = (uint16_t)(amp / 0.05f + 0.5f);
MP4201_WriteWord(addr, MP4201_REG_IIN_OC_FAULT_LIMIT, v);
}
/******************************************************************
* 函数名称:MP4201_SetEn
* 函数说明:EN 引脚控制(高有效)
******************************************************************/
void MP4201_SetEn(uint8_t on)
{
GPIO_WriteBit(PORT_MP4201_EN, GPIO_MP4201_EN, on ? Bit_SET : Bit_RESET);
}
/******************************************************************
* 函数名称:MP4201_SetDir
* 函数说明:DIR 引脚控制功率方向(充电/放电)
******************************************************************/
void MP4201_SetDir(uint8_t dir)
{
GPIO_WriteBit(PORT_MP4201_DIR, GPIO_MP4201_DIR, dir ? Bit_SET : Bit_RESET);
}
/******************************************************************
* 函数名称:MP4201_GetIrq
* 函数说明:读 CH_IRQ(ALT#) 电平
* 函数返回:1=无中断 0=有中断
******************************************************************/
uint8_t MP4201_GetIrq(void)
{
return MP4201_IRQ_GET();
}
五、作品功能演示视频
【实物照片】
六、项目总结
项目成果
本项目成功设计并实现了一套基于 MPS MP2797 电池监测保护器和 MPF42790 电量计芯片的 4S1P 电池管理系统,面向机器人及自制飞机航电系统的不间断备用应急供电场景。系统完成了从原理图设计、元件选型、BOM 整理到驱动代码框架开发的完整闭环,具备以下核心能力:
- 多级硬件保护:过压(OVP)、欠压(UVP)、充电过流(OCC)、放电过流(OCD)、短路(SCD)五重保护,硬件级响应,无需 MCU 干预
- 精确电池监测:16 位 ADC 采集 4 节电池电压、双向电流、NTC 温度,精度满足航电备用电源要求
- 智能电量管理:MPF42790 提供 SOC/SOH 估算,配合 5 路 LED 直观显示电量
- 被动均衡延寿:每节电池独立均衡控制,延长电池组循环寿命
- 标准化通信:I2C 总线统一控制,MCU 端驱动代码可移植性强
MPS 芯片优势
MP2797 优势:
- 4~10 节宽范围支持,适配多种电池配置
- 集成 16 位 ADC + 硬件保护引擎,BOM 简洁
- 静态电流仅 23µA,适合长时间备用
- 内置均衡控制,无需外部 MCU 持续管理
- I2C 接口标准化,开发周期短
MPF42790 优势:
- 专为 1~4 节电池优化,与 MP2797 完美搭配
- 集成 LED 驱动,无需外部 LED 控制芯片
- SOC/SOH 算法成熟,计量精度高
- IRQ 中断输出,降低 MCU 轮询开销
- QFN-32 紧凑封装,节省 PCB 面积
应用前景
本系统设计紧凑、功能完备,可直接应用于以下场景:
- 无人机航电备用电源:主电池故障时无缝切换,保证飞控和通信模块持续供电,安全返航
- 机器人应急供电:主电源中断时为关键传感器和控制器提供备用电力,防止数据丢失
- 便携式设备 BMS:可扩展至电动工具、便携医疗设备等 4 串锂电池应用
- 教学与研发平台:完整开源设计,适合 BMS 技术学习和二次开发
后续优化方向
- 完成 PCB 布局布线并进行实际打样测试
- 完成CANBUS模块的设计,并实现通过IIC接口读取相关数据
七、其他-AI应用
电路设计时候充分利用AI在资料检索分析方面能力,并且打通了AI Agent跟EDA软件,验证了Datasheet到原理图设计的可行性,当然最终出来的原理图效果一言难尽,但好歹是个很好的开端。
-
需求分析及原理图绘制
这里我是使用API gateway作为桥梁,打通立创EDA与AI Agent,具体操作方式不复杂,大家用搜索引擎就很容易找到相关skill。使用时候通过自然语言方式,把相关datasheet和需求喂给它,AI就能自动分析需求,并调用EDA放置元器件和连线。
-
实际AI给出来的原理图(一坨翔)
这里就是画出来的 效果,虽然不堪入目,不过已经是个很好的开端了,后续可以通过AI继续优化调整,也可以人工在此基础上修改优化,别指望他能完全替代人工。













