一、STM32F407 CAN 控制器简介
STM32F407 包含 双CAN控制器(CAN1和CAN2),支持 CAN 2.0B 协议,最高速率1 Mbps。DMA(直接内存访问)可用于高效处理CAN数据的收发,减少CPU负担。
二、HAL库配置CAN+DMA的关键步骤
- 初始化CAN外设
c
CAN_HandleTypeDef hcan1;
// CAN初始化配置
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 16; // 分频系数,波特率= APB1_CLK / (Prescaler * (BS1 + BS2 + SJW))
hcan1.Init.Mode = CAN_MODE_NORMAL; // 工作模式:正常/环回/静默
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_4TQ; // BS1时间段
hcan1.Init.TimeSeg2 = CAN_BS2_3TQ; // BS2时间段
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = ENABLE; // 自动重传
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
HAL_CAN_Init(&hcan1);
- 配置DMA传输
c
// 配置CAN发送DMA(以发送为例)
DMA_HandleTypeDef hdma_can1_tx;
hdma_can1_tx.Instance = DMA1_Stream6; // 根据数据手册选择DMA流
hdma_can1_tx.Init.Channel = DMA_CHANNEL_0; // 对应CAN1_TX的DMA通道
hdma_can1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_can1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_can1_tx.Init.MemInc = DMA_MINC_ENABLE; // 内存地址递增
hdma_can1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; // 外设数据对齐(32位)
hdma_can1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_can1_tx.Init.Mode = DMA_NORMAL; // 单次传输模式
hdma_can1_tx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_can1_tx);
__HAL_LINKDMA(&hcan1, hdmatx, hdma_can1_tx); // 将DMA与CAN句柄绑定
// 启用CAN TX DMA请求
SET_BIT(hcan1.Instance->CAN_TI0R, CAN_TI0R_TXRQ); // 可选,部分HAL版本自动处理
- 启动CAN并激活DMA接收
c
// 启动CAN控制器
HAL_CAN_Start(&hcan1);
// 配置接收滤波器(简化示例)
CAN_FilterTypeDef filter;
filter.FilterIdHigh = 0x0000;
filter.FilterMaskIdHigh = 0x0000;
filter.FilterScale = CAN_FILTERSCALE_32BIT;
filter.FilterMode = CAN_FILTERMODE_IDMASK;
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
HAL_CAN_ConfigFilter(&hcan1, &filter);
// 启动DMA接收(循环模式)
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // 启用接收中断
HAL_CAN_Receive_DMA(&hcan1, CAN_FIFO0); // 启动DMA接收,指定FIFO
- 发送数据
c
CAN_TxHeaderTypeDef tx_header;
uint8_t tx_data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
tx_header.StdId = 0x123; // 标准ID
tx_header.ExtId = 0x00; // 扩展ID(标准帧时设为0)
tx_header.RTR = CAN_RTR_DATA; // 数据帧
tx_header.IDE = CAN_ID_STD; // 标准帧
tx_header.DLC = 8; // 数据长度
tx_header.TransmitGlobalTime = DISABLE;
// 启动DMA发送
HAL_CAN_AddTxMessage(&hcan1, &tx_header, tx_data, (uint32_t*)&hcan1.pTxMsg);
- 中断和回调函数
c
// DMA传输完成回调
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan) {
// 发送完成处理
}
// 接收数据回调
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
CAN_RxHeaderTypeDef rx_header;
uint8_t rx_data[8];
HAL_CAN_GetRxMessage(hcan, CAN_FIFO0, &rx_header, rx_data);
// 处理接收数据
}
三、优缺点分析
优点:
降低CPU负载
DMA直接处理数据搬运,适合高频CAN通信(如1000+帧/秒),释放CPU资源用于其他任务。
高实时性
DMA传输无需CPU干预,减少中断延迟,提升系统响应速度。
数据吞吐量大
适合多帧连续传输场景(如汽车CAN总线日志采集)。
缺点:
配置复杂度高
需精准配置DMA流、通道、优先级,并处理硬件冲突(如DMA通道与其他外设共用)。
调试困难
DMA错误(如内存溢出、外设未就绪)可能导致数据丢失,需结合调试工具(如逻辑分析仪)排查。
资源限制
STM32F407的DMA流数量有限,多外设使用时需合理分配。
潜在的竞争条件
若使用循环DMA模式,需确保缓冲区管理正确,避免数据覆盖。
四、关键注意事项
DMA通道与流的选择
参考《STM32F4xx参考手册》的DMA请求映射表,避免冲突(如CAN1_TX通常映射到DMA1 Stream6)。
内存对齐与缓冲区大小
CAN数据帧为32位(Mailbox结构),确保发送/接收缓冲区的地址对齐到4字节。
错误处理
实现HAL_CAN_ErrorCallback处理总线错误、DMA传输错误等异常情况。
总线负载管理
避免DMA传输速率过高导致CAN总线拥塞,需根据波特率计算最大理论帧率。
五、适用场景
高实时性控制:如电机控制、机器人通信。
大数据量传输:如车载诊断系统(OBD-II)日志上传。
低功耗应用:CPU可进入低功耗模式,由DMA处理通信。
通过合理配置,CAN+DMA方案能显著提升系统性能,但需在复杂性和效率之间权衡。
3413

被折叠的 条评论
为什么被折叠?



