基于STM32F103的BMS通信控制的核心代码框架,涵盖SPI通信(用于电池监测芯片)、CAN通信(用于整车通信)以及数据处理的基本结构。
1. 硬件接口定义
c
// bms_config.h
#ifndef __BMS_CONFIG_H
#define __BMS_CONFIG_H
// SPI引脚定义(连接AFE芯片,如LTC6804)
#define SPI_CS_GPIO_PORT GPIOA
#define SPI_CS_PIN GPIO_Pin_4
#define SPI_AFE_SPI SPI1
// CAN引脚定义
#define CAN_TX_PIN GPIO_Pin_12
#define CAN_RX_PIN GPIO_Pin_11
#define CAN_GPIO_PORT GPIOA
#define CAN_REMAP GPIO_Remap1_CAN1 // 使用重映射功能
// AFE芯片寄存器地址定义
#define AFE_READ_CELL_VOLTAGE 0x04
#define AFE_READ_TEMPERATURE 0x08
#define AFE_START_CONVERSION 0x10
// CAN消息ID定义(基于自定义协议)
#define BMS_STATUS_ID 0x1806E5F4
#define BMS_VOLTAGE_ID 0x1801E5F4
#define BMS_TEMPERATURE_ID 0x1802E5F4
#define CHARGER_CMD_ID 0x1803E5F4
// 安全阈值
#define CELL_OVP_THRESHOLD 4200 // 4.2V
#define CELL_UVP_THRESHOLD 2800 // 2.8V
#define TEMP_OVP_THRESHOLD 60 // 60°C
#endif
2. SPI通信模块(用于AFE芯片)
c
// spi_afe.c
#include "stm32f10x.h"
#include "bms_config.h"
// SPI初始化
void SPI_AFE_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
// 2. 配置SPI引脚
// PA5-SCK, PA6-MISO, PA7-MOSI
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 配置片选引脚
GPIO_InitStructure.GPIO_Pin = SPI_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_CS_GPIO_PORT, &GPIO_InitStructure);
// 4. SPI参数配置
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; // 9MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
SPI_CS_HIGH(); // 默认不选中
}
// SPI读写函数
uint8_t SPI_ReadWriteByte(uint8_t data) {
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, data);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(SPI1);
}
// 从AFE读取电芯电压
void AFE_ReadCellVoltages(uint16_t *voltages, uint8_t cell_count) {
uint8_t cmd[4];
uint8_t rx_buf[32];
// 1. 发送读取命令
cmd[0] = AFE_READ_CELL_VOLTAGE;
cmd[1] = 0x00; // 起始地址
cmd[2] = cell_count * 2; // 数据长度(每个电压2字节)
SPI_CS_LOW();
for(int i = 0; i < 3; i++) {
SPI_ReadWriteByte(cmd[i]);
}
// 2. 读取电压数据
for(int i = 0; i < cell_count * 2; i++) {
rx_buf[i] = SPI_ReadWriteByte(0xFF);
}
SPI_CS_HIGH();
// 3. 转换数据(假设AFE返回的数据格式为16位电压值,单位mV)
for(int i = 0; i < cell_count; i++) {
voltages[i] = (rx_buf[i*2] << 8) | rx_buf[i*2+1];
}
}
// 发送配置命令到AFE
void AFE_SendConfig(uint8_t *config_data) {
uint8_t cmd = 0x01; // 写配置命令
SPI_CS_LOW();
SPI_ReadWriteByte(cmd);
for(int i = 0; i < 6; i++) { // 假设配置寄存器为6字节
SPI_ReadWriteByte(config_data[i]);
}
SPI_CS_HIGH();
}
3. CAN通信模块
c
// can_communication.c
#include "stm32f10x.h"
#include "bms_config.h"
// CAN初始化
void CAN_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
// 2. 配置CAN引脚
GPIO_InitStructure.GPIO_Pin = CAN_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(CAN_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = CAN_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(CAN_GPIO_PORT, &GPIO_InitStructure);
// 3. CAN参数配置
CAN_InitStructure.CAN_TTCM = DISABLE; // 非时间触发模式
CAN_InitStructure.CAN_ABOM = ENABLE; // 自动离线管理
CAN_InitStructure.CAN_AWUM = ENABLE; // 自动唤醒模式
CAN_InitStructure.CAN_NART = DISABLE; // 禁止报文自动重传
CAN_InitStructure.CAN_RFLM = DISABLE; // 接收FIFO不锁定
CAN_InitStructure.CAN_TXFP = DISABLE; // 发送优先级由标识符决定
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; // 正常工作模式
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; // 同步跳转宽度
CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq; // 时间段1
CAN_InitStructure.CAN_BS2 = CAN_BS2_4tq; // 时间段2
CAN_InitStructure.CAN_Prescaler = 36; // 波特率: 36MHz/(1+9+4)/36 = 250Kbps
CAN_Init(CAN1, &CAN_InitStructure);
// 4. CAN过滤器配置
CAN_FilterInitStructure.CAN_FilterNumber = 0;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
// 5. 使能CAN中断
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// 发送BMS状态信息
void CAN_SendBMSStatus(uint8_t soc, uint8_t soh, uint16_t pack_voltage,
int16_t current, uint8_t fault_status) {
CanTxMsg TxMessage;
uint8_t data[8];
// 填充数据
data[0] = soc; // SOC 0-100%
data[1] = soh; // SOH 0-100%
data[2] = pack_voltage >> 8; // 总电压高8位
data[3] = pack_voltage & 0xFF; // 总电压低8位
data[4] = current >> 8; // 电流高8位
data[5] = current & 0xFF; // 电流低8位
data[6] = fault_status; // 故障状态
data[7] = 0x00; // 保留
// 配置发送消息
TxMessage.StdId = BMS_STATUS_ID;
TxMessage.ExtId = 0x00;
TxMessage.IDE = CAN_ID_STD; // 标准帧
TxMessage.RTR = CAN_RTR_DATA; // 数据帧
TxMessage.DLC = 8; // 数据长度8字节
for(int i = 0; i < 8; i++) {
TxMessage.Data[i] = data[i];
}
// 发送消息
CAN_Transmit(CAN1, &TxMessage);
}
// CAN接收中断处理
void USB_LP_CAN1_RX0_IRQHandler(void) {
CanRxMsg RxMessage;
if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) {
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
// 处理接收到的消息
switch(RxMessage.StdId) {
case CHARGER_CMD_ID:
// 处理充电命令
CAN_HandleChargerCommand(RxMessage.Data);
break;
// 可以添加其他消息ID的处理
}
CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
}
}
// 处理充电命令
void CAN_HandleChargerCommand(uint8_t *data) {
uint8_t command = data[0];
uint16_t voltage_limit = (data[1] << 8) | data[2];
uint16_t current_limit = (data[3] << 8) | data[4];
switch(command) {
case 0x01: // 启动充电
BMS_EnableCharging(voltage_limit, current_limit);
break;
case 0x02: // 停止充电
BMS_DisableCharging();
break;
case 0x03: // 设置充电参数
BMS_SetChargeParameters(voltage_limit, current_limit);
break;
}
}
4. 主控制器逻辑
c
// main.c
#include "stm32f10x.h"
#include "bms_config.h"
#include "spi_afe.h"
#include "can_communication.h"
// 全局变量
uint16_t cell_voltages[12]; // 12节电芯电压
int16_t temperatures[6]; // 6个温度传感器
uint8_t fault_status = 0;
uint8_t soc = 100; // 初始SOC
uint32_t last_update_time = 0;
// 系统初始化
void System_Init(void) {
// 1. 时钟初始化
SystemInit();
// 2. 外设初始化
SPI_AFE_Init();
CAN_Init();
// 3. 定时器初始化(用于定时任务)
TIM3_Init();
// 4. 配置AFE芯片
uint8_t afe_config[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
AFE_SendConfig(afe_config);
}
// 电池数据采集任务
void BMS_DataAcquisition_Task(void) {
// 1. 读取电芯电压
AFE_ReadCellVoltages(cell_voltages, 12);
// 2. 读取温度(假设AFE也支持温度读取)
// AFE_ReadTemperatures(temperatures, 6);
// 3. 安全检查
for(int i = 0; i < 12; i++) {
if(cell_voltages[i] > CELL_OVP_THRESHOLD) {
fault_status |= 0x01; // 过压故障
BMS_ShutdownCharge(); // 关闭充电
}
if(cell_voltages[i] < CELL_UVP_THRESHOLD) {
fault_status |= 0x02; // 欠压故障
BMS_ShutdownDischarge(); // 关闭放电
}
}
}
// SOC估算函数
void BMS_SOC_Estimation(void) {
static uint32_t capacity_remaining = 10000; // 剩余容量,单位mAh
static int32_t current_integral = 0;
// 简单的安时积分法
int16_t current = Get_Current_Sensor(); // 从电流传感器读取
// 积分计算(假设每100ms执行一次)
current_integral += current * 100; // 电流单位mA,时间单位s
if(current_integral >= 3600) { // 3600mA*1s = 1mAh
capacity_remaining -= 1;
current_integral -= 3600;
} else if(current_integral <= -3600) {
capacity_remaining += 1;
current_integral += 3600;
}
soc = (capacity_remaining * 100) / 10000; // 计算百分比
soc = (soc > 100) ? 100 : soc;
soc = (soc < 0) ? 0 : soc;
}
// 主循环
int main(void) {
System_Init();
while(1) {
// 1. 数据采集
BMS_DataAcquisition_Task();
// 2. SOC计算
BMS_SOC_Estimation();
// 3. 计算总电压
uint16_t total_voltage = 0;
for(int i = 0; i < 12; i++) {
total_voltage += cell_voltages[i];
}
// 4. 每100ms发送一次CAN状态信息
if(SystemTick - last_update_time > 100) {
CAN_SendBMSStatus(soc, 100, total_voltage, 0, fault_status);
last_update_time = SystemTick;
}
// 5. 被动均衡控制
BMS_CellBalance();
// 延时
Delay_ms(10);
}
}
// 被动均衡函数
void BMS_CellBalance(void) {
uint16_t max_voltage = 0;
uint16_t min_voltage = 0xFFFF;
// 找出最高和最低电压
for(int i = 0; i < 12; i++) {
if(cell_voltages[i] > max_voltage) max_voltage = cell_voltages[i];
if(cell_voltages[i] < min_voltage) min_voltage = cell_voltages[i];
}
// 如果压差超过阈值,启动均衡
if((max_voltage - min_voltage) > 20) { // 20mV阈值
for(int i = 0; i < 12; i++) {
if(cell_voltages[i] > (max_voltage - 5)) { // 高于平均值的电芯
AFE_EnableBalance(i); // 开启对应电芯的均衡开关
} else {
AFE_DisableBalance(i);
}
}
} else {
AFE_DisableAllBalance(); // 关闭所有均衡
}
}
参考代码 stm32f103通信电池中的BMS控制 www.youwenfan.com/contentcsu/56981.html
5. 关键点说明
- 安全机制:代码中应包含电压、温度保护,以及通信超时监测
- 滤波算法:实际应用中需要对ADC采样数据进行滤波(如滑动平均、卡尔曼滤波)
- 故障诊断:需要实现完善的故障诊断和存储机制
- 通信协议:CAN通信协议需与充电桩或整车控制器保持一致
- 实时性:关键保护功能需要在中断中实现,确保快速响应