LTC6803电压采集实战:STM32 SPI驱动与BMS级联隔离设计
简介面向LTC6803在电池管理系统BMS中的实际应用压缩包提供了一套完整的电压采集程序包内仅有2个文件——一个C源文件和一个头文件体积仅5KB却涵盖了芯片初始化、SPI通信、电压与温度读取等关键模块。目前已有632人学习下载。程序基于SPI协议实现主控与LTC6803的数据交互涉及寄存器配置、采样率设置、异常电压判断以及数据滤波处理可针对多节串联电池组进行实时监测适用电动汽车、储能系统等需高可靠电压监控的场景。LTC6803的2.5μV高分辨率、过欠压保护、自供电模式以及温度检测功能在代码中均有体现开发者还能借助LTC8584扩展更多通道构成更完整的BMS监测方案。整体代码短小精悍、模块划分清晰作为BMS开发的入门参考或直接移植都非常适合能帮助读者理解从底层通信到应用层数据处理的高精度电池监控完整流程。1. LTC6803 电压采集一块 12 节电池监测芯片如何撑起 BMS把 12 节串联锂电池每一节的电压差分地采回来是 BMS 电压采集单元最核心的活。LTC6803 一片最多测 12 节电芯转换结果存在 16 位寄存器里SPI 直连单片机逐节放电均衡也在这颗芯片上。它和后来的 LTC6804 最大的区别是没有内置 isoSPI跨板通信的隔离要在外围自己加很多工程师第一版程序读数乱跳根源就在这条链路上。下面按寻址与寄存器布局、STM32F103 上的最小采集程序、多片扩展与滤波模式、现场验证四段推进。适合正在用 STM32 写 BMS 从板程序、以及准备把 12 节以上电池组拆成多片 LTC6803 级联的开发者。标题里的 ltc8584 大概率是文件名笔误选型认准 LTC6803 系列即可。2. LTC6803 的命令长什么样寻址、命令码与 PEC 三段式2.1 四种后缀怎么选-1/-3 命令寻址-2/-4 引脚寻址LTC6803 按后缀分成四颗料LTC6803-1/-3 的设备地址写在命令字节里多片可以挂同一条 SPI 总线主机靠命令字里的地址位区分从机适合少片级联LTC6803-2/-4 用 A0-A3 四根引脚把地址硬件固定死一片一个片选接线直观但片选 GPIO 会随片数线性增长。此外 -3/-4 比 -1/-2 多了滤波 ADC 模式采样速度和噪声的取舍更灵活这也是新设计直接选 -3 的常见理由。单芯片起步阶段选 -1 或 -3 都行网上例程数量最多的是 -1教程密度决定了排错效率。实际项目里常见做法是不管后缀一律把地址定为 0单芯片场景下-1/-3 的命令字节地址位留空-2/-4 把 A0-A3 全部接地。这样换来同一套驱动代码在四颗料上都能跑差异只在多片时体现-1/-3 靠软件写命令地址-2/-4 靠布线给硬件地址。我一般建议优先选 -3既保留命令寻址的级联能力又拿到滤波模式成本和 -1 几乎拉不开差距。2.2 命令格式与 PEC为什么每个命令后面都要带一个 CRCLTC6803 的 SPI 报文是固定三段式1 字节命令码加 1 字节 PEC写配置或回读数据时数据段之后再补 1 字节 PEC。PEC 是多项式 x^8x^2x1、初始种子 0x41 的 CRC-8与 SMBus 的 CRC 同源。种子取 0x41 而不是 0x00是为了避免全零数据算出全零校验结果这样 PEC 还能顺手当“从机是否在线”的判定依据/* LTC6803 的 PEC 计算种子 0x41多项式 0x07逐字节异或后逐位反馈 */ uint8_t ltc6803_pec(uint8_t *data, uint8_t len) { uint8_t crc 0x41; /* 每段报文重新播种不能连续累加 */ for (uint8_t i 0; i len; i) { crc ^ data[i]; /* 先异或当前字节 */ for (uint8_t bit 0; bit 8; bit) { if (crc 0x80) crc (uint8_t)((crc 1) ^ 0x07); /* 最高位为 1 做多项式反馈 */ else crc 1; } } return crc; }这段代码的逻辑是先把本字节异或进 crc再按位做移位反馈。参数上要注意两点len 是当前段的字节数命令段传 1数据段传数据长度函数每次进来都用 0x41 重新播种不能在两个段之间复用上一次的 crc 值。注意命令段和数据段的 PEC 各自独立计算。发送 WRCFG 时命令段 1 字节、数据段 6 字节但两段的种子都是 0x41。最常见的移植错误是把 PEC 做成整包连续计算结果第一包能通过第二包起全部报错。常用命令码在数据手册里有一整张表工程上先记下面这几个就够命令命令码方向用途WRCFG0x01写写 6 字节配置寄存器RDCFG0x02读回读配置校验写入是否生效STCVAD0x10写启动 12 节电芯电压转换RDCVA/B/C/D0x04/0x06/0x08/0x0A读分四组回读 12 节电压STOWAD0x28写启动开路检测排查采样线断线STSAD0x20写自检转换定位 ADC 硬件故障表中的命令码是地址为 0 时的取值。用 -1/-3 级联时地址位按数据手册的位映射叠进命令字节地址写错的典型现象是回读全是 0xFF 且 PEC 不过靠这一条就能把寻址问题从信号完整性里摘出来。2.3 CFG 寄存器组全零能开机但均衡和关断要单独配WRCFG 发的是 6 字节配置寄存器加上数据段 PEC 共 7 字节。6 字节里CFG1 的 bit6:5 是 ADC 模式选择bit7 是关断控制后续字节放着 GPIO 配置和 12 个放电控制位DCC。大部分例程的初始配置就是六个 0x00对应 7kHz 模式、放电全关、GPIO 输出低这个配置在常温下能正常工作也是调通第一路电压前最稳妥的选择。uint8_t cfg[6] {0}; /* 7kHz 模式放电全部关闭不上电就均衡 */ uint8_t frame[9]; frame[0] 0x01; /* WRCFG地址 0 */ frame[1] ltc6803_pec(frame, 1); memcpy(frame[2], cfg, 6); frame[8] ltc6803_pec(frame[2], 6); /* 数据段独立算 PEC */ ltc6803_cs_low(); for (int i 0; i 9; i) spi_write(frame[i]); ltc6803_cs_high();这里 frame 的布局是命令码、命令 PEC、6 字节配置、数据 PEC一共 9 字节CS 必须在整个发送期间保持低电平。参数上要改的是 cfg 数组需要低功耗休眠时把 CFG1 的 bit7 置 1需要均衡某节电芯时把对应 DCC 位置 1。注意 DCC 打开期间均衡电流会流过测量路径读数偏低所以采集电压前必须先清 DCC 再启动转换这个顺序写进主循环就排掉了一大半现场问题。3. STM32F103 上的 LTC6803 最小采集程序从 SPI 初始化到 12 路电压解包3.1 SPI 初始化Mode 0、分频压到 1MHz 以下LTC6803 的 SCLK 上限是 1MHz这是数据手册给死的参数。网上不少例程直接拿 STM32F103 的 SPI 默认分频跑出几兆赫兹表现通常是“偶尔能读出来读多几轮就 PEC 报错”。SPI 初始化把引脚配成复用推挽模式选 Mode 0即 CPOL0、CPHA0数据在上升沿锁存、下降沿移出分频系数按 PCLK272MHz 选 /128得到约 562.5kHz留足沿余量/* SPI1PA5SCKPA6MISOPA7MOSI片选用普通 GPIO 手动控制 */ void ltc6803_spi_init(void) { RCC-APB2ENR | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_SPI1EN; GPIOA-CRL (GPIOA-CRL ~0xFFF00000) | 0x00B33333; SPI1-CR1 SPI_CR1_MSTR | (0x06 SPI_CR1_BR_Pos) /* BR0b110PCLK2/128562.5kHz */ | SPI_CR1_SSM | SPI_CR1_SSI; /* NSS 软件管理片选交给 GPIO */ SPI1-CR1 | SPI_CR1_SPE; }分频位 BR[2:0] 置 0b110 就是 /128四舍五入后仍低于 1MHz 上限。这里把 NSS 配成软件管理片选脚另用普通 GPIO 的原因是LTC6803 要求 CS 在整个报文期间保持低电平报文结束后再拉高硬件 NSS 在这种半双工时序里反而制造毛刺。初始化完成后可以先发一条 RDCFG能回出 7 字节说明 SPI 通路基本通了。提示量产板想省成本把分频提上去之前先确认 SPI 信号经过数字隔离器后沿没有变缓。隔离器引入的传播延时会让有效采样窗口变窄SCLK 余量只小不大。3.2 启动转换与四组回读STCVAD 之后要等不是发了就收STCVAD 命令只管“启动”ADC 跑完需要时间7kHz 模式下 12 节电芯全转换的典型时间在毫秒级。LTC6803 没有专门的 busy 引脚常见做法是延时取最大值再加余量工程上先用 20ms 固定延时跑通后再用示波器压时间/* 启动转换2 字节报文命令码 PECCS 低电平期间发完 */ void ltc6803_start_conv(void) { uint8_t frame[2]; frame[0] 0x10; /* STCVAD地址 0 */ frame[1] ltc6803_pec(frame, 1); ltc6803_cs_low(); for (int i 0; i 2; i) spi_write(frame[i]); ltc6803_cs_high(); delay_ms(20); /* 7kHz 模式留足转换与建立时间 */ }转换完成后12 节电芯的原始码值被拆进四个寄存器组每组 3 节、每节 16 位。回读分四次进行RDCVA 到 RDCVD 各收 6 字节数据加 1 字节 PEC命令覆盖电芯回读字节数数据格式RDCVA 0x04第 13 节7每节 2 字节LSB firstRDCVB 0x06第 46 节7同上RDCVC 0x08第 79 节7同上RDCVD 0x0A第 1012 节7同上/* 读 12 节电压原始码成功返回 0PEC 失败返回 -1 */ int ltc6803_read_cells(uint16_t cells[12]) { static const uint8_t rdcv[4] {0x04, 0x06, 0x08, 0x0A}; for (int g 0; g 4; g) { uint8_t cmd[2] {rdcv[g], 0}; uint8_t buf[7]; cmd[1] ltc6803_pec(cmd, 1); ltc6803_cs_low(); for (int i 0; i 2; i) spi_write(cmd[i]); for (int i 0; i 7; i) buf[i] spi_read(); /* 半双工读MISO 上的波形才是数据 */ ltc6803_cs_high(); if (ltc6803_pec(buf, 6) ! buf[6]) return -1; /* 数据段 PEC 不过整包丢弃 */ for (int i 0; i 3; i) { uint16_t v buf[i * 2] | (buf[i * 2 1] 8); /* LSB first */ cells[g * 3 i] v; } } return 0; }回读期间主机要把 MOSI 持续输出固定电平从机在这段时间只往 MISO 上推数据。解包时先收低字节再收高字节这是小端序和 LTC6804 保持一致如果你移植的驱动源头是早起 LTC6802 的汇编例程端序往往是反的表现是电压值和真实值差很多但不是毫无规律。PEC 不过时不要盲目重试三次以上先停下来抓波形否则会把线缆接触问题误判成算法问题。3.3 换算与上报码值乘 1.5mV端序先搞清楚LTC6803 的分辨率是 1.5mV/LSB16 位寄存器存的是原始码值但实际量程 0~5V 只用到约 3333 个码。换算成毫伏直接用乘加uint16_t mv cells[n] * 15 / 10; /* 码值 x 1.5mV先乘后除减少截断误差 */后续上报建议把 mv 结果放在 uint16_t 数组里主循环固定 100ms 轮询一次不要放在定时器中断里实时换算也不要每次循环都重新发 STCVAD。采集周期固定之后均衡算法里的电压变化率计算才不会被抖动干扰。整包电压要么在 BMS 主控里直接比较过压欠压门限要么走 Modbus RTU 上送给上位机看曲线两种方式都能用关键是把 12 路电压当作一个整体快照对外发布别逐路单独上报否则上位机拼包时总会差一个周期。4. 从 12 节到 96 节LTC6803 级联、SPI 隔离与 ADC 滤波模式怎么选4.1 多片级联的两种接法共用 CS 还是逐片片选电池包超过 12 节串联后方案就变成多片 LTC6803 叠加。工程上分两派一派用 -1/-3多颗芯片共用一条 SPI 总线靠命令字节里的地址位分别访问CS 共用一条线另一派用 -2/-4每片一个 CS主机通过片选轮询。前者省 GPIO、报文结构统一后者排查直观单点故障不会拖垮整条总线。我实际做过的储能项目里16 串和 24 串的从板都是两片 LTC6803 打底用 -3 的共用 CS 接法最省事。上电自检时逐地址发 RDCFG能收到回包的地址在系统里标记在线后续轮询只访问在线的片这个步骤要放在开机自检里做因为电池模组在维护现场会整组插拔固件不能假设第二片一定在。4.2 SPI 隔离放在哪一侧跨板通信先解决地环路LTC6803 没有 isoSPI跨板走 SPI 必须加数字隔离器。选型看三件事通道数、方向配比、隔离耐压。SPI 四条线里 SCK、MOSI、CS 是主机到从机方向MISO 是从机到主机方向所以至少需要一条反向通道常见的 4 通道 31 配置可以直接用。隔离器两侧的电源也必须完全分开两侧参考地之间除了隔离器内部寄生电容外不应该有任何导通回路。踩过一个具体现场读数在电芯均衡启动的瞬间整体偏高 30mV 以上定位到最后是隔离器两侧共地没彻底切开均衡电流在地环路上的压降被叠加进了采样参考。检查方法很简单量隔离器两侧参考地之间的直流阻抗应该接近开路。这个点在原理图评审阶段就要确认等 PCB 打样回来再改就要飞线了。4.3 ADC 三档采样节奏快扫、慢扫、滤波扫各干各的-3/-4 的 CFG1 里有两位 ADC 模式选择工程上当三档用参数见下表MD1:MD0采样节奏典型耗时用途007kHz 默认约 4ms/次常规巡检平衡功耗与速度0126kHz 快速约 1.5ms/次均衡开启前的快速快照102kHz 滤波约 12ms/次静态搁置时的终值确认111kHz 滤波约 24ms/次高精度分容、出厂校验滤波模式本质是 ADC 前端做多次采样平均代价是转换时间拉长。项目里典型节奏是正常运行用 7kHz 扫全组发现某节电压掉得快时切 26kHz 快扫确认是不是瞬时负载误报等电池组静置后再切 2kHz 滤波档做终值。模式切换的关键是写 CFG 之后必须重新发 STCVAD只改寄存器不重启转换采到的还是旧模式的数据uint8_t cfg[6]; ltc6803_read_cfg(cfg); /* 先读回当前配置 */ cfg[0] (cfg[0] ~0x60) | (md 5); /* MD 位写入 CFG1 的 bit6:5 */ ltc6803_write_cfg(cfg); ltc6803_start_conv(); /* 模式变了转换必须重新启动 */这里 md 取值 0~3对应上表四档。注意 -1/-2 没有滤波模式写入 10 或 11 不会生效移植代码时要做后缀判断。另外转换期间电池侧的基准退耦电容不要省用 X7R 介质、容值不小于 1µF否则低字节会随机跳动表现是电压在 1.5mV 的分辨率步进上来回抖查到最后往往不是程序问题。5. 现场最容易翻车的三个检查点LTC6803 的 SPI 波形、PEC 边界和移植差异5.1 CS 与 SCLK 的相对时序示波器两通道同时抓 CS 和 SCLK确认 CS 拉低到第一个 SCLK 上升沿之间至少留一个时钟周期的建立时间报文结束时 SCLK 停在空闲电平期间再拉高 CS。很多“第一包好、第二包坏”的问题其实是 CS 提前拉高把最后一字节 PEC 截断了。这个检查在冷启动抓包时看不到要等到连续跑 10 秒以上再抓时序裕量不足时故障是间歇性的。5.2 PEC 报错先查三处第一处是端序RDCV 回读先收到低字节第二处是分帧命令段和数据段的 PEC 各自从 0x41 种子重算第三处是 MISO 线上的负载。如果板子在 MISO 上加了 RC 滤波且串阻过大回读的最后一字节会慢半拍把容值降到百皮法以下或减小串阻即可。另外测试时不要把探头直接搭在 SDO 引脚上超过几分钟探头电容会和走线电容叠加改变信号边沿导致误判成芯片问题。5.3 从 LTC6804 例程移植的差异LTC6804 例程里的 PEC 算法和 RDCV 分组结构可以直接用但命令码不同启动转换的流程也不同。6803 的 STCVAD 不带 isoSPI 地址直接把启动命令对应到 RDCV 读取流程即可最容易漏的是把 6804 的滤波转换等待时间照搬到 6803 的快扫上白白浪费巡检周期。BMS 测试里最典型的判定是等压差在阈值附近反复横跳时先确认采样节奏是不是被旧的延时参数拖慢了。真要压时间就把 STCVAD 后的固定延时改成长度可调的宏再对着示波器的转换完成时刻把 20ms 一点点压下去——这一步做完整个巡检周期的余量才算真正到了你自己手里。本文还有配套的精品资源点击获取