news 2026/8/10 13:24:06

STM32+BMS 嵌入式开发:ADC 电压温度采集与总线通信落地教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32+BMS 嵌入式开发:ADC 电压温度采集与总线通信落地教程

1. 引言:BMS 与嵌入式开发的结合

电池管理系统(BMS)是电动汽车、储能系统、无人机等设备的核心安全与性能保障单元。其核心任务之一是实时、精确地采集电池组中各个电芯的电压与温度,并通过可靠的总线将数据上报给主控制器。STM32 系列微控制器凭借其丰富的外设、出色的性能与完善的生态,成为实现 BMS 从机(或称“子板”、“采集板”)的理想选择。

本教程将手把手带您完成一个基于 STM32 的 BMS 数据采集与通信模块的软硬件开发全流程,重点涵盖:

  1. 硬件设计要点:ADC 采样电路、温度传感器电路、隔离与保护。
  2. 软件驱动开发:STM32CubeMX 配置、ADC 多通道扫描与 DMA 传输、温度传感器读取。
  3. 通信协议实现:基于 CAN 总线或 UART 的定制通信协议设计。
  4. 系统集成与测试:数据打包、校验、发送与上位机解析。

通过本篇教程,您将获得一个可直接用于项目原型的完整解决方案。

2. 硬件系统架构与关键电路设计

2.1 整体系统框图

一个典型的 BMS 从机模块包含以下核心部分:

[STM32 MCU] <-(SPI/I2C)-> [AFE 或 多路ADC] | V [电压采样网络] ----> [电池电芯] [温度传感器(NTC/PTC)] ----> [电芯或铜排]
  • MCU:STM32F103/F407 等系列,需具备足够数量的 ADC 通道和 CAN 外设。
  • 模拟前端 (AFE):对于高串数电池包,常采用专用 AFE 芯片(如 TI BQ76PL455A)进行电压采集,通过 SPI 与 MCU 通信。本教程为简化,直接使用 STM32 内部 ADC。
  • 采样电路:由精密电阻分压网络、滤波电容及保护器件(TVS、保险丝)组成。
  • 温度传感器:通常采用 NTC 热敏电阻,贴于电芯表面或 Busbar 上。
  • 通信接口:CAN 收发器(如 TJA1050)用于组网通信,或 UART 转隔离模块用于点对点通信。

2.2 ADC 电压采样电路设计

对于单节电芯(标称 3.6V),电压采样电路相对简单。关键设计在于精度安全抗干扰

电路示例与计算:
假设电芯电压最高为V_cell_max = 4.2V,STM32 ADC 参考电压V_ref = 3.3V
为将 4.2V 分压至 3.3V 以内,并留有余量,设定分压比K = R2 / (R1 + R2) = 3.0 / 4.2 ≈ 0.714
选取R1 = 10kΩ,则R2 = R1 * K / (1 - K) ≈ 10k * 0.714 / 0.286 ≈ 24.9kΩ,可取标称值24.9kΩ25kΩ

实际电压计算公式:
V_cell = ADC_Value * (V_ref / 4095) * ( (R1 + R2) / R2 )
= ADC_Value * (3.3 / 4095) * (34.9k / 24.9k)
≈ ADC_Value * 0.000805 * 1.402 ≈ ADC_Value * 0.001128

PCB 布局要点:

  1. 分压电阻尽量靠近 ADC 输入引脚。
  2. 在 ADC 输入引脚处添加一个0.1uF的滤波电容到地,以滤除高频噪声。
  3. 串联一个100Ω的小电阻,与滤波电容构成 RC 低通滤波器,并限制注入电流。
  4. 在采样线入口处放置 TVS 管(如 SMAJ5.0A)进行过压保护。

2.3 温度采样电路设计(NTC 热敏电阻)

NTC 的阻值随温度升高而降低。我们将其与一个精密参考电阻串联,构成分压电路,MCU 测量分压点电压。

电路示例:
VCC(3.3V) — [R_ref (10kΩ)] — [ADC_IN] — [NTC] — GND

温度计算流程:

  1. 读取电压V_ntc = ADC_Value * (V_ref / 4095)
  2. 计算 NTC 电阻R_ntc = R_ref * (V_ntc) / (VCC - V_ntc)
  3. 查表或公式计算温度:通常使用Steinhart-Hart 方程或其简化版(B 值公式)将电阻值转换为温度值。

3. 软件驱动开发:STM32CubeMX 与 HAL 库

3.1 工程创建与外设配置

  1. 打开 STM32CubeMX,选择您的目标 MCU。
  2. 配置 ADC
    • 启用ADC1(或ADC2,ADC3)。
    • 工作模式选择“Scan Conversion Mode”“Continuous Conversion Mode”
    • Parameter Settings中,设置合适的采样时间(如239.5 Cycles以提高精度)。
    • DMA Settings中,添加 DMA 请求,模式设为“Circular”,数据宽度都为Word
    • Pinout View中,将需要用到的 ADC 通道对应的 GPIO 引脚配置为Analog模式。
  3. 配置 CAN(如果使用):
    • 启用CAN1
    • 模式选择Normal
    • 配置波特率(如500kbps)。Time QuantaPrescaler需要根据时钟计算。
    • 自动重传Enable
  4. 配置 UART(如果使用):启用相应 USART,配置波特率(如115200),数据位8,停止位1,无校验。
  5. 生成代码:指定工程路径和 IDE(Keil/IAR/STM32CubeIDE),生成初始化代码。

3.2 ADC 多通道 DMA 采集代码实现

在生成的工程中,我们需要启动 ADC 的 DMA 采集,并处理数据。

// 在 main.c 的 /* USER CODE BEGIN PV */ 区域定义变量#defineADC_CHANNEL_NUM4// 假设采集4个电芯电压uint32_tadc_buffer[ADC_CHANNEL_NUM];// DMA 搬运的目标数组// 在 /* USER CODE BEGIN 2 */ 中启动 ADCHAL_ADC_Start_DMA(&hadc1,(uint32_t*)adc_buffer,ADC_CHANNEL_NUM);// 在 /* USER CODE BEGIN 4 */ 中编写 DMA 传输完成中断回调函数voidHAL_ADC_ConvCpltCallback(ADC_HandleTypeDef*hadc){if(hadc->Instance==ADC1){// adc_buffer 中已按配置顺序更新了所有通道的数据// 可以在此处设置一个标志位,通知主循环处理数据adc_data_ready_flag=1;}}// 主循环中处理数据if(adc_data_ready_flag){adc_data_ready_flag=0;for(inti=0;i<ADC_CHANNEL_NUM;i++){// 将原始 ADC 值转换为电压值cell_voltage[i]=adc_buffer[i]*3.3f/4095.0f*VOLTAGE_DIVIDER_RATIO;// 可以加入滤波算法,如滑动平均滤波}}

3.3 温度传感器读取与计算

// 假设 NTC 接在 ADC Channel 5floatread_temperature(void){uint32_tadc_value;floatvoltage,resistance,temperature;// 1. 读取 ADC 值 (可以使用单次转换或从 DMA 缓冲区获取)HAL_ADC_Start(&hadc1);HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);adc_value=HAL_ADC_GetValue(&hadc1);HAL_ADC_Stop(&hadc1);// 2. 计算电压和电阻voltage=adc_value*3.3f/4095.0f;resistance=REF_RESISTOR*voltage/(3.3f-voltage);// 10k 上拉// 3. 使用 B 值公式计算温度 (简化版,需根据具体 NTC 参数调整)// T = 1 / (1/T0 + 1/B * ln(R/R0))// T0=25°C=298.15K, R0 为 25°C 时的阻值,B 为 B 值常数floatT0=298.15;floatR0=10000.0;// 10k NTCfloatB=3950.0;temperature=1.0/(1.0/T0+log(resistance/R0)/B);temperature=temperature-273.15;// 开尔文转摄氏度returntemperature;}

4. 通信协议设计与实现

4.1 基于 CAN 总线的通信协议

CAN 总线具有高可靠性、多主、抗干扰强等特点,非常适合 BMS 网络。

定义报文 ID 与数据结构:
假设我们使用标准帧(11位 ID)

  • ID 分配:高 4 位表示帧类型,低 7 位表示从机地址。
    • 0x0X0: 心跳/状态帧 (主机 -> 从机)
    • 0x0X1: 数据请求帧 (主机 -> 从机)
    • 0x1X0: 电压温度数据帧 (从机 -> 主机)
    • 0x1X1: 报警帧 (从机 -> 主机)
  • 数据帧示例(0x1X0)
    Byte0-1: 电芯1电压 (uint16_t, 单位 0.1mV) Byte2-3: 电芯2电压 Byte4: 温度1 (int8_t, 单位 °C) Byte5: 温度2 Byte6: CRC8 校验 (从 Byte0 到 Byte5) Byte7: 帧尾 (0xAA)

代码实现(发送数据):

voidsend_cell_data_via_can(uint8_tslave_addr){CAN_TxHeaderTypeDef tx_header;uint8_ttx_data[8];uint32_ttx_mailbox;tx_header.StdId=0x100|slave_addr;// 组合成完整 IDtx_header.ExtId=0;tx_header.RTR=CAN_RTR_DATA;tx_header.IDE=CAN_ID_STD;tx_header.DLC=8;// 数据长度 8 字节tx_header.TransmitGlobalTime=DISABLE;// 填充数据uint16_tvol1=(uint16_t)(cell_voltage[0]*10000);// 转换为 0.1mVtx_data[0]=(vol1>>8)&0xFF;tx_data[1]=vol1&0xFF;// ... 填充其他电压温度数据tx_data[6]=calculate_crc8(tx_data,6);// 计算 CRCtx_data[7]=0xAA;if(HAL_CAN_AddTxMessage(&hcan1,&tx_header,tx_data,&tx_mailbox)!=HAL_OK){// 发送失败处理}}

4.2 基于 UART 的通信协议

对于点对点或简单系统,UART 也是常用选择。需要定义简单的帧结构来保证数据的完整性。

自定义帧格式:
[帧头 0xAA] [长度] [命令字] [数据...] [CRC] [帧尾 0x55]

代码实现(发送数据):

voidsend_cell_data_via_uart(void){uint8_ttx_buffer[32];uint8_tidx=0;tx_buffer[idx++]=0xAA;// 帧头uint8_tdata_len=1+2*4+1*2;// 命令字 + 4个电压(uint16) + 2个温度(int8)tx_buffer[idx++]=data_len;tx_buffer[idx++]=0x01;// 命令字:上报数据for(inti=0;i<4;i++){uint16_tvol=(uint16_t)(cell_voltage[i]*1000);// 转换为 mVtx_buffer[idx++]=(vol>>8)&0xFF;tx_buffer[idx++]=vol&0xFF;}for(inti=0;i<2;i++){tx_buffer[idx++]=(uint8_t)(temperature[i]);// 温度,假设在 -40~125°C 范围内}uint8_tcrc=calculate_crc8(&tx_buffer[1],idx-1);// 从长度开始计算tx_buffer[idx++]=crc;tx_buffer[idx++]=0x55;// 帧尾HAL_UART_Transmit(&huart1,tx_buffer,idx,100);}

5. 系统集成、测试与优化

5.1 数据打包与定时发送

在主循环或定时器中断中,周期性地执行采集、处理、发送流程。

// 在 main.c 的 while(1) 循环中while(1){// 1. 检查 ADC 数据就绪标志if(adc_data_ready_flag){process_adc_data();// 处理电压数据read_temperatures();// 读取温度adc_data_ready_flag=0;}// 2. 定时发送 (例如每 100ms)if(HAL_GetTick()-last_send_tick>100){send_cell_data_via_can(SLAVE_ADDR);// 或 via UARTlast_send_tick=HAL_GetTick();}// 3. 处理接收到的命令(如休眠、校准指令)check_and_handle_rx_command();HAL_Delay(1);}

5.2 上位机测试(以 CAN 为例)

可以使用USB-CAN 适配器配合PCAN-ViewZLG USBCAN配套软件或Python-can库进行测试。

  1. 连接硬件,上电。
  2. 在上位机软件中设置相同的 CAN 波特率。
  3. 监听 ID 为0x1X0的报文,检查数据解析是否正确。
  4. 可以发送请求帧 (0x0X1),测试从机的响应功能。

5.3 抗干扰与可靠性优化

  1. 软件滤波:对 ADC 采样值进行滑动平均滤波中值滤波,消除尖峰噪声。
  2. 硬件看门狗:启用 STM32 的独立看门狗(IWDG),防止程序跑飞。
  3. 通信重发机制:在 CAN/UART 发送失败后,加入重试逻辑。
  4. 数据校验:务必使用CRC校验,确保数据传输的完整性。
  5. 隔离设计:在采样电路与 MCU 之间、通信接口处使用光耦数字隔离器,提高系统抗共模干扰能力和安全性。

6. 总结

本教程详细介绍了从硬件选型、电路设计到软件驱动、通信协议实现的完整流程。STM32 HAL 库大大降低了开发门槛,而清晰的协议设计是系统稳定运行的关键。希望这篇教程能成为您进入 STM32 BMS 开发领域的坚实基石。在实际项目中,请务必根据具体的电池参数、安全法规和系统架构进行深入设计与充分测试。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/10 13:18:37

从零开始:Home Assistant OS完整安装指南与硬件兼容性解析

从零开始&#xff1a;Home Assistant OS完整安装指南与硬件兼容性解析 【免费下载链接】operating-system :beginner: Home Assistant Operating System 项目地址: https://gitcode.com/gh_mirrors/op/operating-system Home Assistant OS是一个专为智能家居设计的轻量级…

作者头像 李华
网站建设 2026/8/10 13:15:50

SQL-on-Hadoop技术解析:ClickHouse与Impala对比与实践

1. 为什么需要SQL-on-Hadoop解决方案 在数据爆炸式增长的时代&#xff0c;企业面临的最大挑战之一是如何高效处理海量数据。传统的关系型数据库在面对TB甚至PB级别的数据时往往力不从心&#xff0c;这正是Hadoop生态系统兴起的关键原因。但原生Hadoop的MapReduce编程模型对数据…

作者头像 李华
网站建设 2026/8/10 13:15:22

Python构建消费风险监控系统:规则引擎实战与风控应用

最近在整理消费维权案例时&#xff0c;发现几个非常典型且值得开发者借鉴的“坑”。无论是电商平台的商品信息审核、智能硬件的合规检测&#xff0c;还是企业宣传的合规性审查&#xff0c;背后都涉及到数据抓取、规则匹配、文本分析和风险预警等技术。本文将从技术实战角度&…

作者头像 李华
网站建设 2026/8/10 13:15:15

3分钟快速解锁加密音乐:Unlock-Music完全使用指南

3分钟快速解锁加密音乐&#xff1a;Unlock-Music完全使用指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地址: https://g…

作者头像 李华