两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片详解

中颖 SH367306 AFE 芯片详解:两轮车换电 BMS 的模拟前端

基于量产 60V 20 串 BMS(STM32F072 + SH367306 × 2),从寄存器到数据流,完整拆解这片 AFE 的硬件能力、软件驱动与工程细节。


一、为什么需要 AFE?

BMS 的主控 MCU(本项目为 STM32F072)是一个纯数字芯片------它没有高压模拟前端,无法直接测量 60V 电池包的每一节电芯电压。所以需要一个**模拟前端(AFE,Analog Front End)**来完成:

  • 每节电芯的电压采集(最高 4.2V × 20 串 = 84V 共模电压,MCU 的 ADC 根本扛不住)
  • 电流采样(0.5mΩ 采样电阻上的 μV 级差分信号)
  • 电芯均衡(内置均衡 MOSFET 驱动)
  • 硬件短路保护(μs 级,不依赖 MCU 软件)
  • 充放电 MOSFET 驱动

SH367306 是**中颖电子(SinoWealth)**为锂电池保护板设计的专用 AFE,单颗最多管理 10 串电芯。本项目是 20 串,所以用了两片级联。


二、硬件连接全景

复制代码
                    STM32F072 (Cortex-M0, 48MHz)
                         │
         ┌───────────────┼───────────────┐
         │               │               │
    TWI1 (PB6/PB7)  TWI2 (PB10/PB11)  TIM16_CH1 (PB1)
    I2C @ 400kHz    I2C @ 400kHz      GPIO 模拟 PWM
         │               │               │
         ▼               ▼               ▼
   ┌──────────┐   ┌──────────┐        CTLD 引脚
   │SH367306 #1│   │SH367306 #2│   (限流硬件控制)
   │ 0x1B     │   │ 0x1B     │
   │ Cell 1-10│   │ Cell 11-20│
   └────┬─────┘   └────┬─────┘
        │              │
   ┌────┴────┐    ┌───┴─────┐
   │TS1: MOS │    │TS1: 预充│
   │TS2: 环境│    │TS2: 参考│
   │SRP/SRN  │    │SRP/SRN  │ ← 同一条采样电阻
   │CHG/DSG  │    │CHG/DSG  │ ← 并联驱动同一对 MOS
   └─────────┘    └─────────┘

四根关键连线:

信号 方向 作用
TWI (I2C) MCU ↔ AFE 读写寄存器、获取采样数据、控制均衡
ALARM AFE → MCU 短路/过压/看门狗硬件故障中断
CTLD MCU → AFE 放电限流 PWM,硬件直连,不经过 I2C
WAKEUP MCU → AFE 休眠/唤醒控制

三、I2C 通信:不是普通 I2C

SH367306 的 I2C 从机地址是 0x1B (7-bit),写地址 0x36,读地址 0x37

3.1 传输格式

复制代码
写操作:START + 0x36 + RegAddr + Data + STOP
读操作:START + 0x36 + RegAddr + RESTART + 0x37 + [HiByte][LoByte] + STOP

每次读取固定 2 字节。电压/电流/温度数据均为低 12 位有效,高 4 位是标志位。

3.2 三层容错

驱动代码中对 I2C 通信做了三层容错:

第一层 --- 读写重试Sh367306_1_Drv.c:137-186):

c 复制代码
// 每次读写失败最多重试 TRY_TIMES(5) 次
while (times++ < TRY_TIMES) {
    result = Twi1Drv_Write(SlaveAdd << 1, WrAddr, 1, &WrBuf);
    if (result == 1) break;  // 成功立即返回
}

第二层 --- 写入验证Sh367306_1_Drv.c:195-223):

c 复制代码
// 写入后回读,确认寄存器值确实被写入
while (RegWriteFlg) {
    AfeIf_Write(RdAddr, Data);
    AfeIf_Read(RdAddr, 2, &Buffer);
    if (Buffer[0] == Data) break;     // 读写一致,OK
    if (++RegWriteFlg > 20) return 0; // 最多重试 20 次
}

第三层 --- 运行时回读校验Sh367306_1_Drv.c:1041-1049):

c 复制代码
// 每 4s 检测一次 SCONF1 是否与初始化值一致
if (s_usCTLDPinChek % 100 == 1) {
    AfeIf_Read(SCONF1, 2, &DataBuff);
    if (DataBuff[0] != g_Afe1Sconfig1.Data) {
        AfeIf_RegWrite(SCONF1, g_Afe1Sconfig1.Data); // 被干扰了,回写修复
    }
}

为什么要这么做?BMS 的工作环境极其恶劣------大电流 PWM、MOSFET 开关的 EMI、振动------I2C 数据被干扰或 AFE 寄存器被静电打翻的事时有发生。三层容错保证在这种环境下数据依然可靠。


四、寄存器全图谱

SH367306 的寄存器分为三类:状态标志、系统配置、采样数据

4.1 状态标志寄存器

寄存器 地址 位域
FLAG1 0x00 TWI_INT | WDT | OV(过压) | SC(短路) | Reserved
FLAG2 0x01 VADC(电压采样完成) | CADC(电流采样完成) | RST | Reserved
BSTATUS 0x02 CHGR(充电器插入) | LOAD(负载接入) | CHGING | DSGING | CHG(MOS状态) | DSG(MOS状态)

FLAG1 和 FLAG2 是锁存标志 --- 置位后不会自动清零,MCU 需要向 SCONF1.LTCLR 写 1→0 来手动清除。

4.2 系统配置寄存器

寄存器 地址 核心功能
INT_EN 0x03 中断使能:TWI/WDT/VADC/CADC/CD/OV/SC 各独立开关
SCONF1 0x04 硬件保护使能(SC_EN/WDT_EN/CTLD_EN) + LTCLR 清除锁存
SCONF2 0x05 CHG_C(充电MOS) / DSG_C(放电MOS) / ALARM_C / RESET_PF
SCONF3 0x06 VADC_EN / CADC_EN / 转换周期 / 分辨率选择
SCONF4 0x07 均衡开关 CB6 ~ CB10(电芯 6~10)
SCONF5 0x08 均衡开关 CB1 ~ CB5(电芯 1~5)
SCONF6 0x09 短路保护:阈值(SCV) / 延时(SCT) / 恢复延时(RST) / 增益(RSNS)
SCONF7 0x0A 看门狗溢出时间(WDTT) / 过压延时(OVT) / 充放电选择(CHS)
SCONF8 0x0B OVD_8/OVD_9 过压检测延时
SCONF9 0x0C OVD_0~OVD_7 过压检测延时
SCONF10 0x0D 引脚功能配置 / 低功耗模式

4.3 采样数据寄存器

寄存器 地址 内容 有效位
REGCELL1 ~ REGCELL10 0x0E ~ 0x20 10 路电芯电压 ADC 值 12-bit
REGTS1 ~ REGTS2 0x22 ~ 0x24 2 路外部 NTC 温度 ADC 值 12-bit
REGTEMP1 ~ REGTEMP2 0x26 ~ 0x28 2 路内部芯片温度 ADC 值 12-bit
REGCUR 0x2A 电流 ADC 值(bit12 = 方向:1=放电 0=充电) 16-bit

五、电芯电压采集:从 ADC 到 mV

5.1 采样时序

SH367306 内部有一个自动扫描的 VADC,按 SCONF3.SCAN_C 配置的周期循环采样 10 路电芯电压。每完成一轮,FLAG2.VADC 置位。

c 复制代码
// 项目配置
g_Afe1Sconfig3.B.SCAN_C_0 = 0;   // VADC 转换周期 = 最快
g_Afe1Sconfig3.B.SCAN_C_1 = 0;
g_Afe1Sconfig3.B.SCAN_C_2 = 0;
g_Afe1Sconfig3.B.VADC_EN  = 1;   // VADC 使能

这意味着 MCU 不需要主动触发每次电压采样------只需要等 FLAG2.VADC == 1,然后一口气读完 10 路电压。

5.2 电压换算公式

c 复制代码
// AfeIf_Calculate.c
CellVoltage_mV = (1000 × ADC_Value × 6 / 4096) - Offset

// 1000: 单位转换为 mV
// 6:    基准电压 6V(AFE 内部 VREF,对应 0~5V 量程)
// 4096: 12-bit ADC 满量程
// Offset: 芯片 1 偏移 3mV,芯片 2 偏移 5mV(补偿 PCB 走线压降)

例如 ADC 读数为 2048:

复制代码
CellVoltage = 1000 × 2048 × 6 / 4096 - 3 = 2997mV ≈ 3.0V

5.3 Cell1 的特殊校准

Cell1 的 B- 采样线通常最长,线上的压降不可忽略。本项目在工厂模式运营模式下用了两种不同的校准策略:

工厂模式AfeIf_Calculate.c:199-216)--- 在线自校准:

c 复制代码
// 电流 > 6A 时,Cell1 电压 = (总压 - Cell1) / 19(用其他 19 节的平均值作为 Cell1 的参考)
if (abs(Current) > 6000) {
    if (abs(CellVoltage[0] - AvgOfOther19) < 150mV) {
        CellVoltage[0] = AvgOfOther19;  // 偏差 <150mV 则自动校准
    }
}

运营模式AfeIf_Calculate.c:219-226)--- 固定系数补偿:

c 复制代码
// 6020 电池包:B- 线压降 0.50mV/A
CellVoltage[0] -= Current × 50 / 100000;

// 6030 电池包:B- 线压降 0.33mV/A
CellVoltage[0] -= Current × 33 / 100000;

六、电流采集:比电压复杂 10 倍

电流是 BMS 所有决策的基础------SOC 估算、故障保护、模式切换都依赖它。SH367306 的 CADC(Current ADC)是整颗芯片中最精密的模拟电路。

6.1 物理链路

复制代码
采样电阻 (0.5mΩ, 两端焊接在 PCB 大铜皮上)
    │
    ├── SRP 引脚 (Kelvin 连接, 采样电阻正端)
    │
    └── SRN 引脚 (Kelvin 连接, 采样电阻负端)
            │
            ▼
    SH367306 内部 PGA (可编程增益放大器)
            │
            ▼
    16-bit ΣΔ ADC
            │
            ▼
    REGCUR 寄存器

6.2 换算公式

c 复制代码
// AfeIf_Calculate.c: CalculateCurrent()

// 第一步:方向判断 + 补码转换
if (CADC_Value bit12 == 1)  // 放电方向
    RawValue = -((0x10000 - CADC_Value) & 0x1FFF);
else                         // 充电方向
    RawValue = CADC_Value & 0x1FFF;

// 第二步:零点偏移 + 温漂补偿
CorrectedValue = RawValue - ZeroOffset + TempDrift;

// 第三步:量纲转换
Current_mA = CorrectedValue × (50mV / 4096) / 0.5mΩ
           = CorrectedValue × 100A / 4096
           ≈ CorrectedValue × 24.4mA/LSB

6.3 零点自学习:上电后自动找"零电流"

上电初始化时,假设电池处于静止状态(无充放电),MCU 自动执行零点自学习(Sh367306_1_Drv.c:880-933):

复制代码
1. 等待 CADC 采样完成(FLAG2.CADC == 1)
2. 读取 REGCUR,计算零点偏移
3. 连续多次采样(2~30 次),取两次不同值的均值
4. 零点偏移限制在 ±10 LSB 以内(约 ±240mA)
5. 超时 200S 未完成则报 AFE 故障

这个自学习的巧妙之处在于:它取两次不同值的均值,而不是所有采样的均值。这样即使有一个异常点,也不会拉偏零点。

6.4 温漂补偿:电流零点会随温度漂移

采样电阻和 AFE 内部运放都有温度系数。电流零点在 -25°C 和 +75°C 之间可能漂移好几 A。驱动代码中有一张温度→偏移补偿表Sh367306_1_Drv.c:679-728):

c 复制代码
int8_t GetTheTempOffset(int16_t ChipTemp) {
    // 低温漂负方向
    if (ChipTemp > -44 && ChipTemp <= -40) return -6;
    if (ChipTemp <= -30) return -5;
    if (ChipTemp <= -20) return -4;
    if (ChipTemp <= -10) return -3;
    if (ChipTemp <=   0) return -2;
    if (ChipTemp <=  10) return -1;
    // 常温不漂
    if (ChipTemp >  10 && ChipTemp < 35) return 0;
    // 高温漂正方向
    if (ChipTemp >=  75) return +4;
    if (ChipTemp >=  65) return +3;
    if (ChipTemp >=  55) return +2;
    if (ChipTemp >=  35) return +1;
    return 0;
}

补偿精度:每个 LSB ≈ 24.4mA,低温最大补偿 -6 LSB ≈ -146mA,高温最大补偿 +4 LSB ≈ +98mA。

6.5 电流滤波

原始电流数据还要经过两级滤波(AfeIf_Calculate.c:286-339):

复制代码
原始电流
    │
    ├─ 相邻两次差值 > 30mA → 异常跳变,丢弃旧值
    │
    ├─ 两次采样取平均值
    │
    ├─ 充/放分向校准系数(默认 1.015,可在 ±20% 标定)
    │    放电方向 = 原始值 × ChgCurFactor / 1000
    │    充电方向 = 原始值 × DsgCurFactor / 1000
    │
    └─ |Current| < 250mA → 强制归零(消除噪声)

七、温度采集:NTC 查表

每个 SH367306 有两个外部 NTC 输入(TS1/TS2),本项目中的分配:

传感器 物理位置 测量对象
AFE1 TS1 MOS 管散热片旁 MOS 温度
AFE1 TS2 电池包内部空间 环境温度
AFE2 TS1 预充电阻旁 预充电阻温度
AFE2 TS2 PCB 板上 10K 参考 温度参考校验

NTC 类型为 10KΩ B=3435,搭配 10KΩ 上拉电阻接到 AFE 内部基准电压。

7.1 ADC → 电阻值

c 复制代码
// AfeIf_Calculate.c
R_NTC = (10000 × 10 × ADC_Value) / (4096 - ADC_Value)
//       ↑ 10K 上拉电阻    ↑ 12-bit ADC 满量程

7.2 电阻值 → 温度

191 点 NTC RT 表(-45°C ~ +145°C),线性插值查表(AfeIf_Calculate.c:46-88):

c 复制代码
// 查表定位
for (i = 1; i < 191; i++) {
    if (R_NTC < Table[i]) continue;  // 还没找到
    else break;                       // 找到了!R_NTC 在 Table[i-1] 和 Table[i] 之间
}

// 线性插值
Temp = i × 10 - 10 × (R_NTC - Table[i]) / (Table[i-1] - Table[i]);
return Temp - 450;  // 偏移 -45°C(表的第 0 点对应 -45°C)

7.3 分段校准

查表得到的温度还要经分段校准(AfeIf_Calculate.c:98-119):

c 复制代码
if (Temp < -43°C)      → 不校准(超出线性范围)
else if (Temp < -25°C)  → +2°C
else if (Temp < 0°C)    → +1°C
else                     → 不校准

八、硬件短路保护:不依赖 MCU 的最后防线

这是 SH367306 最"硬"的功能------完全不经过 MCU 软件

复制代码
采样电阻电压 > SCV 阈值 (200mV ≈ 400A @ 0.5mΩ)
    │
    ├─ 硬件延时 SCT (50μs) 去抖确认
    │
    ├─ AFE 硬件自动清零 SCONF2.DSG_C → 断开放电 MOS
    │
    ├─ FLAG1.SC 锁存置位
    │
    └─ ALARM 引脚输出中断信号 → MCU 进入 AfeIf_AlarmPin() ISR

为什么是 50μs?

  • 太快(如 5μs)→ 正常负载突变的浪涌电流会误触发
  • 太慢(如 500μs)→ MOSFET 在短路电流下已经开始损坏
  • 50μs 是一个经验折中------足够避开浪涌,又快到能救 MOSFET 的命

MCU 侧的软件二次确认

MCU 收到 ALARM 中断后,并不直接采信------而是做软件去抖(Sh367306_1_Drv.c:300-360):

c 复制代码
if (FLAG1.SC == 1) {
    Cnt++;
    ShortCircuitPreChg_Cnt++;
    ClearFlg();  // 清除 AFE 锁存,允许硬件重新判断

    if (Cnt >= 12) {           // 连续 12 次 = 持续约 600ms
        SCStatus = 1;          // 确认真实短路
        Cnt = 0;
    }
}

if (Time > 14) {               // 14 个周期没达到 12 次
    Cnt = 0;                   // 重置 --- 刚才可能是干扰
}

这个 12/14 的阈值设计很有意思:如果每周期都触发短路,12 个周期就锁定;如果有间歇(比如 14 个周期只触发了 10 次),就重置。这避免了在某些"接近短路但不完全是"的工况下误锁。


九、电芯均衡:交错控制防止局部过热

SH367306 内置 10 路均衡 MOSFET 驱动,通过 SCONF4SCONF5 两个寄存器控制。

9.1 为什么交错?

如果相邻两节电芯同时开启均衡(例如 Cell1 和 Cell2),它们的均衡电流都流过 Cell2 的采样线,导致 Cell2 电压读数偏高 20-30mV。更糟的是,相邻均衡 MOSFET 同时导通会在局部产生热点。

9.2 交错实现

c 复制代码
// BalanceOpen() --- Sh367306_1_Drv.c
if (i % 2 == 0) {
    // 偶数周期:只开奇数电芯 (bit 0,2,4,6,8)
    SCONF4 = Config & 0x55;  // 0b01010101
    SCONF5 = Config & 0x55;
} else {
    // 奇数周期:只开偶数电芯 (bit 1,3,5,7,9)
    SCONF4 = Config & 0xAA;  // 0b10101010
    SCONF5 = Config & 0xAA;
}

9.3 均衡与电压采样互斥

均衡开启时,均衡电流流过电芯采样线,电压读数不准。所以驱动代码做了一个关键设计------均衡开启和电压读取分时进行Sh367306_1_Drv.c:1070-1099):

复制代码
周期  操作
 0    空闲
 1    空闲
 2    GetVadcData() + BalanceOpen(奇通道)   ← 先读电压,再开均衡
 3    空闲
 4    空闲
 5    空闲
 6    BalanceOpen(偶通道)                   ← 只开均衡,不读电压
 7    空闲
 8    空闲
 9    空闲
10    BalanceClose()                        ← 关均衡
11    清除 VADC 标志,准备下一轮

11 个周期 × 40ms = 440ms 一个完整循环。均衡开启的最大占空比约 50%(交错后每个通道的实际导通时间)。


十、CTLD 引脚:放电限流的硬件捷径

CTLD(Current Limit Discharge)是 SH367306 一个非常巧妙的设计。

10.1 为什么不走 I2C?

一次 I2C 读写大约 1ms。如果要通过 I2C 来实现 PWM 关断放电 MOS:

  • PWM 周期至少得是 I2C 延迟的 10 倍以上 → PWM 频率只能做到 100Hz
  • 每个周期都要发起一次 I2C 通信 → MCU 被 I2C 中断淹没

CTLD 是一个纯硬件引脚------拉低即关断放电 MOS,拉高即导通。MCU 只需翻转 GPIO,不经过任何通信协议。

10.2 驱动代码

c 复制代码
// 拉低 → 关断放电 MOS(限流生效)
static void CURRENTLIMITPIN_GPIO_OUT_L() {
    Afe1_LimitCurrPwm_GPIO_Port->BSRR = Afe1_LimitCurrPwm_Pin;
}

// 拉高 → 恢复导通
static void CURRENTLIMITPIN_GPIO_OUT_H() {
    Afe1_LimitCurrPwm_GPIO_Port->BRR = Afe1_LimitCurrPwm_Pin;
}

10.3 波形生成

在 100µs 的 TIM16 中断中:

c 复制代码
void AfeIf_CurrentLimit() {
    if (TimeCnt < DutyCycle)  CURRENTLIMITPIN_GPIO_OUT_L();  // 前 N 个 tick 关断
    else                      CURRENTLIMITPIN_GPIO_OUT_H();  // 后面导通

    TimeCnt++;
    if (TimeCnt >= 33) TimeCnt = 0;  // 周期 = 33 × 100µs = 3.3ms ≈ 303Hz
}

CTLD 让 BMS 可以用一个普通的 GPIO + 定时器就实现 303Hz 的 PWM 限流,不需要额外的 MOSFET 驱动电路,也不需要高速通信总线。


十一、上电初始化:长达 2 秒的精密流程

SH367306 的上电初始化是本项目中最长的单段代码(Sh367306_1_Drv.c:736-959),大约 200 行,耗时 2~3 秒。

复制代码
 0ms   TWI 接口初始化
 0ms   WAKEUP 引脚拉高
 0ms   写 SCONF2=0x00(先关 MOS,确保安全)
 0ms   延时 800ms(等 AFE 内部振荡器起振)
 800ms CTLD 限流引脚初始化
 800ms 配置寄存器初始化(RegisterInit)
        ├─ SCONF1: SC_EN=1, WDT_EN=1, CTLD_EN=1
        ├─ SCONF3: VADC_EN=1, CADC_EN=1
        ├─ SCONF6: 短路 50μs/200mV, 恢复 32ms, 增益 100mV
        ├─ SCONF7: WDT ≈ 10s, OVT=0
        └─ INT_EN: VADC_INT=1, CADC_INT=1, SC_INT=1
 800ms 依次写入 SCONF1/2/3/6/7 + INT_EN
       任一写入失败 → 故障标志置位
1000ms 清除锁存标志
1000ms 关闭所有均衡
1000ms 延时 2s
3000ms 循环等待 VADC 和 CADC 首次采样完成
        ├─ VADC: 10 路电压全在 0.5V~5.0V → OK
        ├─ CADC: 零点自学习 2~30 次取均值
        └─ 超时 200s → 报 AFE 故障
3000ms 零点偏移 + 芯片温度补偿
3000ms 初始化完成

这个流程有几个值得注意的点:

  1. 先关 MOS 再初始化:防止初始化过程中 MOS 意外导通
  2. 800ms 延时:等 AFE 内部 LDO 和振荡器稳定,不能省略
  3. 寄存器回读验证:每个配置寄存器写入后都回读,不是 fire-and-forget
  4. 零点学习多次取均值:不是读一次就完,而是反复采集直到两次不同值

十二、低功耗休眠

MCU 进入休眠前,AFE 也要同步休眠(Sh367306_1_Drv.c:1103-1116):

c 复制代码
// 1. 关断 CHG/DSG MOS
g_Afe1Sconfig2.B.CHG_C = 0;
g_Afe1Sconfig2.B.DSG_C = 0;
ChgAndDsgCtrl();

// 2. 关闭所有均衡
BalanceClose();

// 3. WAKEUP 引脚拉低 → AFE 进入 PowerDown
AfeDeWakeup();

// 4. 写入低功耗寄存器
EnterLowPower();  // SCONF10=0x33, SCONF1=0x20

休眠后 AFE 的静态功耗从 mA 级降到 μA 级。唤醒时只需要拉高 WAKEUP 引脚,然后重新走初始化流程。


十三、双芯片数据融合

两片 SH367306 的数据在 AfeIf_Calculate.cCalculateValueRunnable() 中统一处理:

c 复制代码
void AfeIf_CalculateValueRunnable(void) {
    CalculateVoltage();       // 20 路电压 → CellVoltage_mV[0..19]
    CalculateTemperature();   // 4 路 NTC → MOS温度 / 环境温度 / 预充电阻温度 / 参考温度
    CalculateCurrent();       // AFE1 电流 → CurrentRaw_mA
    CalculateVolMaxMin();     // 最高/最低单体电压
    MosFETState();            // CHG/DSG MOS 状态
    BalanceState();           // 20 路均衡状态
    Afe_StatusDignose();      // AFE1 故障 | AFE2 故障
}

关键设计:电流只用 AFE1。两片 AFE 的 SRP/SRN 并联到同一个采样电阻,但只用 AFE1 的 CADC 数据。AFE2 的 CADC 虽然也在运行,但不参与电流计算------避免两片芯片的零点偏移不同导致数据矛盾。


十四、工程经验总结

14.1 为什么要用两片 SH367306 而不是一片 20 串的芯片?

选型是 2021 年做的。当时国产 20 串 AFE 的选择很少,中颖的 SH367306(10 串)是经过市场验证的成熟方案。两片 10 串比一片未经验证的 20 串更可靠。而且两片独立供电、独立通信,单颗故障不会导致全部 20 串数据丢失。

14.2 最容易被忽视的坑

均衡时不能读电压。 SH367306 内部只有一个 ADC,均衡电流会干扰采样结果。如果均衡和采样同时进行,电压读数可能偏差 50mV 以上------在 3.6V 满充附近,50mV 足够把一节正常电芯误判为过压。

电流零点漂移。 0.5mΩ 采样电阻在 30A 时只有 15mV 压降,而 AFE 内部的运放失调电压就可能达到几个 μV。温度从 -20°C 变到 60°C 时,失调电压漂移几个 μV 就可能对应几百 mA 的零点偏移。温漂补偿表是必须的。

I2C 在强干扰下不可靠。 MOSFET 开关的 EMI 会耦合到 I2C 线上。三层容错(重试+验证+回读修复)是量产代码和实验室代码的最大区别。


十五、关键参数速查

参数 数值 说明
管理串数 10 串/片 本项目 2 片级联 = 20 串
I2C 地址 0x1B 两片共用总线(硬件地址固定,通过片选区分)
电压采样范围 0.5V ~ 5.0V 12-bit,分辨率 ~1.47mV
电流采样电阻 0.5mΩ 本项目选型
电流分辨率 ~24.4mA/LSB 50mV 量程 @ 0.5mΩ
短路保护响应 50μs 200mV 阈值 ≈ 400A
短路恢复延时 32ms 硬件自动恢复尝试
看门狗周期 ~10s 超时硬件复位 AFE
均衡方式 内置 MOSFET 驱动 交错控制,50% 占空比
休眠功耗 μA 级 WAKEUP 引脚拉低
NTC 类型 10KΩ B=3435 191 点 RT 表

本文基于 STM32F072 + SH367306 × 2 两轮车换电 BMS 量产代码(APP-V02.01.20)分析,所有代码引用均可追溯到源文件对应行号。

相关推荐
wuyk55515 小时前
24. C 语言模块化:不是拆几个.c 文件那么简单
c语言·开发语言·stm32·单片机
hyhsandy18031 天前
STM32F103 TIM学习笔记
笔记·stm32·学习
GuHenryCheng1 天前
【ESP32】ESP-IDF开发环境搭建(cursor)
git·stm32·单片机·学习
小心亦新1 天前
STM32学习10---串口
stm32·嵌入式硬件·学习
wuyk5551 天前
25. 函数指针表:用查表替代 switch-case,打造高效可维护的嵌入式状态机
c语言·stm32·单片机·mcu·51单片机
灯厂码农1 天前
STM32三大通信协议详解——UART、I2C、SPI
stm32·单片机·嵌入式硬件
逐步前行1 天前
HAL_IIC (EEPROM)
stm32·单片机
wuyk5552 天前
21. 嵌入式面试避坑指南:sizeof 是关键字,不是函数!
c语言·开发语言·stm32·单片机·嵌入式硬件