[应用相关] STM32学习笔记:深入浅出解析CAN总线

[复制链接]
1209|22
Jiangxiaopi 发表于 2025-9-6 22:10 | 显示全部楼层 |阅读模式
一、引言:为什么工程师必须掌握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 非破坏性仲裁机制

2952568bbc6d3a9d15.png


三、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 材料清单

667368bbc6c2cdae6.png


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 测试场景设计

1369268bbc6adcfe6c.png


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 常见故障排查表

2506368bbc6a1b7770.png


九、工程化建议
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

uiint 发表于 2025-9-9 11:01 | 显示全部楼层
具备完善的错误检测、标定和故障隔离功能
deliahouse887 发表于 2025-9-9 18:23 | 显示全部楼层
STM32的CAN控制器能够自动处理错误帧和过载帧。
beacherblack 发表于 2025-9-10 14:47 | 显示全部楼层
CAN总线具有高可靠性、实时性强、抗干扰能力好等优点,是嵌入式系统中重要的通信方式之一。
kkzz 发表于 2025-9-10 16:15 | 显示全部楼层
CAN总线作为一种高度可靠的串行通信协议,在工业控制和汽车电子领域应用广泛。
minzisc 发表于 2025-9-10 16:50 | 显示全部楼层
设置CAN的工作模式、波特率、同步跳跃宽度等参数
1988020566 发表于 2025-9-10 19:41 | 显示全部楼层
STM32系列微控制器大多内置CAN控制器
kkzz 发表于 2025-9-10 21:40 | 显示全部楼层
速率125kbps时传输距离可达500m,满足大多数工业场景需求。
10299823 发表于 2025-9-13 10:52 | 显示全部楼层
STM32的CAN接口通过CAN_TX和CAN_RX引脚连接外部CAN收发器(如TJA1050),收发器负责将CAN控制器的逻辑信号转换为差分信号,实现与CAN总线的物理连接。
youtome 发表于 2025-9-13 15:44 | 显示全部楼层
总线上的所有节点均可主动发送数据(无中心节点),通过​​仲裁机制​​解决冲突。
ulystronglll 发表于 2025-9-13 16:41 | 显示全部楼层
所有节点必须配置相同波特率              
abotomson 发表于 2025-9-13 20:18 | 显示全部楼层
通过CAN发送邮箱发送数据,通过接收邮箱接收数据。
claretttt 发表于 2025-9-13 21:10 | 显示全部楼层
总线两端需并联120Ω终端电阻              
timfordlare 发表于 2025-9-13 21:47 | 显示全部楼层
采用CAN_H和CAN_L双绞线传输差分信号,抗电磁干扰能力极强,适合工业和汽车环境。
juliestephen 发表于 2025-9-13 22:39 | 显示全部楼层
各节点共地,减少地电位差              
lzbf 发表于 2025-9-14 08:00 | 显示全部楼层
CAN总线具备错误检测、通知和恢复功能,以及故障隔离能力
earlmax 发表于 2025-9-14 09:00 | 显示全部楼层
合理设置中断优先级,避免被高优先级中断长时间阻塞
tifmill 发表于 2025-9-14 10:02 | 显示全部楼层
通过标识符实现消息优先级仲裁              
nomomy 发表于 2025-9-14 11:19 | 显示全部楼层
差分信号传输,适合工业环境              
sheflynn 发表于 2025-9-14 12:43 | 显示全部楼层
基于ID优先级的冲突解决机制。多个节点同时发送时,ID小的报文优先传输,优先级低的自动退让,数据完整性不受影响。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

250

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部