尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

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

STM32+BMS 嵌入式开发:ADC 电压温度采集与总线通信落地教程 1. 引言BMS 与嵌入式开发的结合电池管理系统BMS是电动汽车、储能系统、无人机等设备的核心安全与性能保障单元。其核心任务之一是实时、精确地采集电池组中各个电芯的电压与温度并通过可靠的总线将数据上报给主控制器。STM32 系列微控制器凭借其丰富的外设、出色的性能与完善的生态成为实现 BMS 从机或称“子板”、“采集板”的理想选择。本教程将手把手带您完成一个基于 STM32 的 BMS 数据采集与通信模块的软硬件开发全流程重点涵盖硬件设计要点ADC 采样电路、温度传感器电路、隔离与保护。软件驱动开发STM32CubeMX 配置、ADC 多通道扫描与 DMA 传输、温度传感器读取。通信协议实现基于 CAN 总线或 UART 的定制通信协议设计。系统集成与测试数据打包、校验、发送与上位机解析。通过本篇教程您将获得一个可直接用于项目原型的完整解决方案。2. 硬件系统架构与关键电路设计2.1 整体系统框图一个典型的 BMS 从机模块包含以下核心部分[STM32 MCU] -(SPI/I2C)- [AFE 或 多路ADC] | V [电压采样网络] ---- [电池电芯] [温度传感器(NTC/PTC)] ---- [电芯或铜排]MCUSTM32F103/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.2VSTM32 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.001128PCB 布局要点分压电阻尽量靠近 ADC 输入引脚。在 ADC 输入引脚处添加一个0.1uF的滤波电容到地以滤除高频噪声。串联一个100Ω的小电阻与滤波电容构成 RC 低通滤波器并限制注入电流。在采样线入口处放置 TVS 管如 SMAJ5.0A进行过压保护。2.3 温度采样电路设计NTC 热敏电阻NTC 的阻值随温度升高而降低。我们将其与一个精密参考电阻串联构成分压电路MCU 测量分压点电压。电路示例VCC(3.3V) — [R_ref (10kΩ)] — [ADC_IN] — [NTC] — GND温度计算流程读取电压V_ntc ADC_Value * (V_ref / 4095)计算 NTC 电阻R_ntc R_ref * (V_ntc) / (VCC - V_ntc)查表或公式计算温度通常使用Steinhart-Hart 方程或其简化版B 值公式将电阻值转换为温度值。3. 软件驱动开发STM32CubeMX 与 HAL 库3.1 工程创建与外设配置打开 STM32CubeMX选择您的目标 MCU。配置 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模式。配置 CAN如果使用启用CAN1。模式选择Normal。配置波特率如500kbps。Time Quanta和Prescaler需要根据时钟计算。自动重传Enable。配置 UART如果使用启用相应 USART配置波特率如115200数据位8停止位1无校验。生成代码指定工程路径和 IDEKeil/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-InstanceADC1){// adc_buffer 中已按配置顺序更新了所有通道的数据// 可以在此处设置一个标志位通知主循环处理数据adc_data_ready_flag1;}}// 主循环中处理数据if(adc_data_ready_flag){adc_data_ready_flag0;for(inti0;iADC_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_valueHAL_ADC_GetValue(hadc1);HAL_ADC_Stop(hadc1);// 2. 计算电压和电阻voltageadc_value*3.3f/4095.0f;resistanceREF_RESISTOR*voltage/(3.3f-voltage);// 10k 上拉// 3. 使用 B 值公式计算温度 (简化版需根据具体 NTC 参数调整)// T 1 / (1/T0 1/B * ln(R/R0))// T025°C298.15K, R0 为 25°C 时的阻值B 为 B 值常数floatT0298.15;floatR010000.0;// 10k NTCfloatB3950.0;temperature1.0/(1.0/T0log(resistance/R0)/B);temperaturetemperature-273.15;// 开尔文转摄氏度returntemperature;}4. 通信协议设计与实现4.1 基于 CAN 总线的通信协议CAN 总线具有高可靠性、多主、抗干扰强等特点非常适合 BMS 网络。定义报文 ID 与数据结构假设我们使用标准帧11位 ID。ID 分配高 4 位表示帧类型低 7 位表示从机地址。0x0X0: 心跳/状态帧 (主机 - 从机)0x0X1: 数据请求帧 (主机 - 从机)0x1X0: 电压温度数据帧 (从机 - 主机)0x1X1: 报警帧 (从机 - 主机)数据帧示例0x1X0Byte0-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.StdId0x100|slave_addr;// 组合成完整 IDtx_header.ExtId0;tx_header.RTRCAN_RTR_DATA;tx_header.IDECAN_ID_STD;tx_header.DLC8;// 数据长度 8 字节tx_header.TransmitGlobalTimeDISABLE;// 填充数据uint16_tvol1(uint16_t)(cell_voltage[0]*10000);// 转换为 0.1mVtx_data[0](vol18)0xFF;tx_data[1]vol10xFF;// ... 填充其他电压温度数据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_tidx0;tx_buffer[idx]0xAA;// 帧头uint8_tdata_len12*41*2;// 命令字 4个电压(uint16) 2个温度(int8)tx_buffer[idx]data_len;tx_buffer[idx]0x01;// 命令字上报数据for(inti0;i4;i){uint16_tvol(uint16_t)(cell_voltage[i]*1000);// 转换为 mVtx_buffer[idx](vol8)0xFF;tx_buffer[idx]vol0xFF;}for(inti0;i2;i){tx_buffer[idx](uint8_t)(temperature[i]);// 温度假设在 -40~125°C 范围内}uint8_tcrccalculate_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_flag0;}// 2. 定时发送 (例如每 100ms)if(HAL_GetTick()-last_send_tick100){send_cell_data_via_can(SLAVE_ADDR);// 或 via UARTlast_send_tickHAL_GetTick();}// 3. 处理接收到的命令如休眠、校准指令check_and_handle_rx_command();HAL_Delay(1);}5.2 上位机测试以 CAN 为例可以使用USB-CAN 适配器配合PCAN-View、ZLG USBCAN配套软件或Python-can库进行测试。连接硬件上电。在上位机软件中设置相同的 CAN 波特率。监听 ID 为0x1X0的报文检查数据解析是否正确。可以发送请求帧 (0x0X1)测试从机的响应功能。5.3 抗干扰与可靠性优化软件滤波对 ADC 采样值进行滑动平均滤波或中值滤波消除尖峰噪声。硬件看门狗启用 STM32 的独立看门狗IWDG防止程序跑飞。通信重发机制在 CAN/UART 发送失败后加入重试逻辑。数据校验务必使用CRC校验确保数据传输的完整性。隔离设计在采样电路与 MCU 之间、通信接口处使用光耦或数字隔离器提高系统抗共模干扰能力和安全性。6. 总结本教程详细介绍了从硬件选型、电路设计到软件驱动、通信协议实现的完整流程。STM32 HAL 库大大降低了开发门槛而清晰的协议设计是系统稳定运行的关键。希望这篇教程能成为您进入 STM32 BMS 开发领域的坚实基石。在实际项目中请务必根据具体的电池参数、安全法规和系统架构进行深入设计与充分测试。
返回列表