一、引言:为什么工程师必须掌握CAN总线?
在完成SPI教程后,许多读者问:“STM32还有哪些工业级通信协议值得学习?” 答案无疑是CAN总线。作为汽车电子神经脉络和工业控制骨干网络,CAN总线具有:
多主仲裁机制:无中心节点冲突自动解决
抗干扰能力:差分信号(CANH/CANL)可承受±36V共模电压
错误检测率99.9%:CRC校验+ACK应答+帧格式检查
传输距离:40米@1Mbps,10公里@5Kbps
据2023年汽车电子报告,单辆燃油车平均搭载120个CAN节点,电动车高达200+节点
二、CAN协议核心机制解析
2.1 物理层:工业环境的生存之道
// 典型CAN收发器电路(TJA1050)
_______
CAN_TX --| TXD | 120Ω
| |----- CAN_H -----||----> 总线
| TJA | ||
MCU | 1050 |----- CAN_L -----||
CAN_RX --| RXD | 120Ω
|______|
关键参数:
显性电平:CANH=3.5V, CANL=1.5V (差分2V)
隐性电平:CANH=CANL=2.5V (差分0V)
终端电阻必须放置总线两端(阻抗匹配防反射)
2.2 数据帧:高效传输的秘密
# CAN 2.0B扩展帧结构(29位ID)
| SOF | ID[28:18] | SRR | IDE | ID[17:0] | RTR | r0 | DLC | Data[0-8] | CRC | DEL | ACK | EOF |
核心字段:
仲裁场:29位ID(优先级数值越小越高)
控制场:DLC=0~8(数据长度码)
数据场:最大64位(CAN FD可达64字节)
2.3 非破坏性仲裁机制
三、STM32 bxCAN外设深度剖析
3.1 邮箱系统:高效数据管理
typedef struct {
__IO uint32_t TIR; // 标识符+请求类型
__IO uint32_t TDTR; // 数据长度+时间戳
__IO uint32_t TDLR; // 数据低4字节
__IO uint32_t TDHR; // 数据高4字节
} CAN_TxMailBox_TypeDef; // 发送邮箱寄存器
// 接收FIFO结构
typedef struct {
__IO uint32_t RIR;
__IO uint32_t RDTR;
__IO uint32_t RDLR;
__IO uint32_t RDHR;
} CAN_FIFOMailBox_TypeDef;
3.2 过滤器配置:精准数据接收
32位掩码模式配置示例:
// 接收ID范围:0x100 ~ 0x10F
uint32_t FilterId = 0x100 << 21; // 标准ID左移21位
uint32_t FilterMask = 0x7F0 << 21; // 高7位必须匹配
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterIdHigh = FilterId >> 16;
sFilterConfig.FilterIdLow = FilterId & 0xFFFF;
sFilterConfig.FilterMaskIdHigh = FilterMask >> 16;
sFilterConfig.FilterMaskIdLow = FilterMask & 0xFFFF;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
四、硬件实战:双机通信系统搭建
4.1 材料清单
4.2 接线图
[STM32A] [总线] [STM32B]
CAN_TX--->TXD | |
CAN_RX<---RXD | |
| | |
+--CAN_H----+---------------+
| |
+--CAN_L----+---------------+
| | |
GND----------GND------------GND
注意:终端电阻仅加在总线两端的收发器上!
五、CubeMX配置详解
5.1 位时序计算(500Kbps示例)
APB1时钟 = 42MHz
预分频器 = 6
时间量子tq = 6 / 42MHz = 142.86ns
位时间 = 14tq (推荐配置)
Sync_Seg = 1tq
Prop_Seg = 2tq
Phase_Seg1 = 6tq
Phase_Seg2 = 5tq
采样点 = (1+2+6)/14 ≈ 78.6% (符合汽车标准)
六、HAL库代码实现
6.1 CAN初始化
CAN_HandleTypeDef hcan;
void CAN_Init(void) {
hcan.Instance = CAN1;
hcan.Init.Prescaler = 6;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_6TQ;
hcan.Init.TimeSeg2 = CAN_BS2_5TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
hcan.Init.AutoBusOff = DISABLE;
hcan.Init.AutoWakeUp = DISABLE;
hcan.Init.AutoRetransmission = ENABLE; // 自动重传
hcan.Init.ReceiveFifoLocked = DISABLE;
hcan.Init.TransmitFifoPriority = DISABLE;
HAL_CAN_Init(&hcan);
// 启动CAN
HAL_CAN_Start(&hcan);
}
6.2 数据发送函数
#define TX_ID_STD 0x101 // 标准帧ID
#define TX_ID_EXT 0x1800A001 // 扩展帧ID
void CAN_SendMessage(uint8_t* data, uint8_t len, uint32_t id, uint32_t ide) {
CAN_TxHeaderTypeDef TxHeader;
uint32_t TxMailbox;
if(ide == CAN_ID_STD) {
TxHeader.StdId = id;
TxHeader.IDE = CAN_ID_STD;
} else {
TxHeader.ExtId = id;
TxHeader.IDE = CAN_ID_EXT;
}
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.DLC = len;
TxHeader.TransmitGlobalTime = DISABLE;
// 发送到邮箱(超时100ms)
HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailbox);
}
6.3 中断接收(FIFO0)
// 中断回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8];
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData);
// 打印接收数据
printf("ID: 0x%lX, DLC: %d, Data: ",
(RxHeader.IDE == CAN_ID_STD) ? RxHeader.StdId : RxHeader.ExtId,
RxHeader.DLC);
for(int i=0; i<RxHeader.DLC; i++)
printf("%02X ", RxData);
printf("\n");
}
七、双机通信实验
7.1 测试场景设计
7.2 抗干扰压力测试
// 在总线上注入噪声(实验室方法)
1. 使用函数发生器在CANH-GND间注入100KHz正弦波
2. 幅值从0.5V逐步增加到2.5V
3. 监控错误计数器:
HAL_CAN_GetError(&hcan, CAN_ERROR_CNT_REG);
八、高级调试技巧
8.1 使用CAN分析仪诊断
# 使用candump工具监听(Linux环境)
$ candump can0 -t a -x
can0 101 [1] 55 # 标准帧ID=0x101, 数据0x55
can0 1800A001 [8] A1 B2 C3 D4 E5 F6 # 扩展帧
can0 ERROR [0] // 错误帧
8.2 常见故障排查表
九、工程化建议
9.1 提升通信可靠性
// 错误处理增强代码
void CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {
uint32_t esr = hcan->Instance->ESR;
if(esr & CAN_ESR_BOFF) {
// 总线关闭状态,需软件恢复
HAL_CAN_ResetErrorState(hcan);
}
if(esr & CAN_ESR_EPVF) {
// 错误被动状态,建议重启通信
HAL_CAN_Stop(hcan);
CAN_Init();
}
}
9.2 CANopen协议集成准备
// COB-ID分配示例
#define NMT_ID 0x000 // 网络管理帧
#define PDO1_TX_ID 0x181 // 过程数据对象
#define SDO_RX_ID 0x601 // 服务数据对象
十、附录:关键资源
官方文档:
ISO11898-1:2015 CAN协议标准
STM32F4xx参考手册
工具链:
PCAN-View:官方CAN分析软件
BusMaster:开源CAN总线工具
————————————————
版权声明:本文为CSDN博主「好像起雾了呢」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_63522060/article/details/148785578
|
|