第10章 CAN通信(BMS)
约 519 字大约 2 分钟
2026-07-21
10.1 CubeMX设置
在BMS项目工程中配置CAN外设:
- 使用PB8/PB9作为CAN_RX/CAN_TX
- 波特率配置(如500kbps)
- 工作模式:Normal模式

10.2 接口层
Int_Can.h
#ifndef __INT_CAN_H__
#define __INT_CAN_H__
#include "can.h"
#define CAN_ID_CHARGE 0x01 // 充电开关 CAN_ID
#define CAN_ID_DISCHARGE 0x02 // 放电开关 CAN_ID
// 定义CAN接收消息结构体
typedef struct
{
uint32_t StdId;
uint32_t ExtId;
uint8_t IDE;
uint8_t DLC;
uint8_t Data[8];
} CAN_RxMsgTypeDef;
void Int_CAN_Init(void);
void Int_CAN_Send(uint32_t std_id, uint8_t *tx_data, uint32_t tx_len);
void Int_CAN_Receive(CAN_RxMsgTypeDef *rx_msg_arr, uint32_t *rx_len);
#endifInt_Can.c
#include "Int_Can.h"
void Int_CAN_Init(void)
{
// 1. 配置CAN过滤器(标识符列表模式,只接收充电/放电控制指令)
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 标识符列表模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; // 16位位宽
sFilterConfig.FilterIdHigh = CAN_ID_CHARGE << 5; // 充电开关CAN_ID
sFilterConfig.FilterIdLow = CAN_ID_DISCHARGE << 5; // 放电开关CAN_ID
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
// 2. 启动CAN
HAL_CAN_Start(&hcan);
}
void Int_CAN_Send(uint32_t std_id, uint8_t *tx_data, uint32_t tx_len)
{
while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) == 0);
CAN_TxHeaderTypeDef sTxHeader;
sTxHeader.StdId = std_id;
sTxHeader.RTR = CAN_RTR_DATA;
sTxHeader.IDE = CAN_ID_STD;
sTxHeader.DLC = tx_len;
uint32_t tx_mailbox;
HAL_CAN_AddTxMessage(&hcan, &sTxHeader, tx_data, &tx_mailbox);
}
void Int_CAN_Receive(CAN_RxMsgTypeDef *rx_msg_arr, uint32_t *rx_len)
{
*rx_len = HAL_CAN_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0);
if (*rx_len == 0) return;
for (uint32_t i = 0; i < *rx_len; i++) {
CAN_RxHeaderTypeDef sRxHeader;
HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &sRxHeader, rx_msg_arr[i].Data);
rx_msg_arr[i].StdId = sRxHeader.StdId;
rx_msg_arr[i].ExtId = sRxHeader.ExtId;
rx_msg_arr[i].IDE = sRxHeader.IDE;
rx_msg_arr[i].DLC = sRxHeader.DLC;
}
}10.3 应用层
App_Task.c - CAN任务
// CAN任务的函数实现
void vCanTaskFunc(void *pvParameters)
{
DEBUG_PRINTLN("CAN任务启动!");
Int_CAN_Init(); // CAN模块初始化
CAN_RxMsgTypeDef rx_msg_arr[3];
uint32_t rx_len = 0;
while (1)
{
Int_CAN_Receive(rx_msg_arr, &rx_len);
if (rx_len > 0) {
// 处理接收到的CAN消息
if (rx_msg_arr[0].StdId == CAN_ID_CHARGE) {
DEBUG_PRINTLN("接收到充电控制消息 %d\n", rx_msg_arr[0].Data[0]);
App_Bat_Charge(rx_msg_arr[0].Data[0]);
}
else if (rx_msg_arr[0].StdId == CAN_ID_DISCHARGE) {
DEBUG_PRINTLN("接收到放电控制消息 %d\n", rx_msg_arr[0].Data[0]);
App_Bat_Discharge(rx_msg_arr[0].Data[0]);
}
}
vTaskDelay(1000); // 每秒轮询一次
}
}10.4 通信协议定义
通过CAN总线发送充放电控制指令:
| 命令 | CAN ID | 数据 | 说明 |
|---|---|---|---|
| 充电开启 | 0x01 | 0x01 | 1字节,非0即开启 |
| 充电关闭 | 0x01 | 0x00 | 1字节,0即关闭 |
| 放电开启 | 0x02 | 0x01 | 1字节,非0即开启 |
| 放电关闭 | 0x02 | 0x00 | 1字节,0即关闭 |
文档生成于: 2026-07-21
