【STM32 CAN通信实战手册】原理与代码详解,手把手玩转CAN总线通信

[摘要]
CAN(Controller Area Network)是广泛应用于工业控制、汽车电子等领域的可靠通信协议。本文基于STM32F1系列微控制器,深入解析CAN总线原理,并提供完整的配置代码和实验流程,帮助开发者快速掌握CAN通信核心技术。


一、CAN总线基础原理

1.1 CAN协议核心特点

  • 多主结构:总线上所有节点地位平等,均可主动发送数据

  • 非破坏性仲裁:通过ID优先级解决总线冲突

  • 高可靠性:CRC校验、错误检测与自动重发机制

  • 双线差分信号:CAN_H和CAN_L组成抗干扰传输线

  • 1.2 CAN帧格式(标准帧)

    字段 长度 说明
    SOF 1 bit 帧起始
    ID(11位) 11 bits 报文标识符
    RTR 1 bit 远程传输请求标志
    IDE 1 bit 标识符扩展位(0=标准帧)
    r0 1 bit 保留位
    DLC 4 bits 数据长度码(0-8字节)
    Data Field 0-8字节 数据内容
    CRC 15 bits 循环冗余校验码
    ACK 2 bits 应答
    EOF 7 bits 帧结束

    1.3 STM32 CAN控制器(bxCAN)

  • 支持CAN 2.0A/B协议

  • 3个发送邮箱

  • 2个接收FIFO,每个FIFO 3级深度

  • 可配置位时间参数

  • 28个过滤器组(STM32F103)


  • 二、硬件设计

    2.1 典型电路连接

    STM32 CAN_TX --> TJA1050 TXD
    STM32 CAN_RX <-- TJA1050 RXD
    TJA1050 CAN_H -- 120Ω -- CAN_H
    TJA1050 CAN_L -- 120Ω -- CAN_L

    2.2 关键参数计算

    波特率计算公式
    波特率 = APB1时钟 / (Prescaler * (BS1 + BS2 + 1))
    例如:APB1=36MHz,目标波特率500kbps
    设置Prescaler=6, BS1=5, BS2=3
    实际波特率 = 36MHz / (6*(5+3+1)) = 500kbps


    三、软件配置(基于STM32CubeMX+HAL库)

    3.1 CubeMX配置步骤

    1. 选择CAN模式:NormalLoopback(自测试)

    2. 配置参数:

    3. Prescaler: 分频系数

    4. Time Quantum: 1/(APB1时钟/Prescaler)

    5. BS1: 时间段1(5-20 Tq)

    6. BS2: 时间段2(1-16 Tq)

    7. 启用CAN中断(可选)

    3.2 过滤器配置

    CAN_FilterTypeDef filter;
    
    filter.FilterBank = 0;
    filter.FilterMode = CAN_FILTERMODE_IDMASK;
    filter.FilterScale = CAN_FILTERSCALE_32BIT;
    filter.FilterIdHigh = 0x123 << 5;  // 标准ID左移5位
    filter.FilterMaskIdHigh = 0x7FF <<5;
    filter.FilterFIFOAssignment = CAN_RX_FIFO0;
    filter.FilterActivation = ENABLE;
    HAL_CAN_ConfigFilter(&hcan, &filter);

    四、代码实现

    4.1 CAN初始化

    void MX_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_5TQ;
      hcan.Init.TimeSeg2 = CAN_BS2_3TQ;
      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);
    }

    4.2 发送数据

    void CAN_SendMessage(uint32_t id, uint8_t* data, uint8_t len)
    {
      CAN_TxHeaderTypeDef txHeader;
      uint32_t txMailbox;
      
      txHeader.StdId = id;
      txHeader.RTR = CAN_RTR_DATA;
      txHeader.IDE = CAN_ID_STD;
      txHeader.DLC = len;
      txHeader.TransmitGlobalTime = DISABLE;
      
      if(HAL_CAN_AddTxMessage(&hcan, &txHeader, data, &txMailbox) != HAL_OK)
      {
        Error_Handler();
      }
    }

    4.3 接收数据(中断方式)

    // 启动CAN接收
    HAL_CAN_Start(&hcan);
    HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
    
    // 接收回调函数
    void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
    {
      CAN_RxHeaderTypeDef rxHeader;
      uint8_t rxData[8];
      
      HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxData);
      
      printf("Received ID: 0x%03X, Data: ", rxHeader.StdId);
      for(int i=0; i<rxHeader.DLC; i++){
        printf("%02X ", rxData[i]);
      }
      printf("\n");
    }

    五、实验验证

    5.1 硬件连接

  • 两个STM32开发板通过CAN收发器连接

  • 终端电阻配置:总线两端各接120Ω电阻

  • 5.2 测试结果

    发送端发送:ID=0x123, Data=AA 55 01 02
    接收端显示:Received ID: 0x123, Data: AA 55 01 02

    六、常见问题排查

    1. 无法进入中断

    2. 检查NVIC中断使能

    3. 确认过滤器配置正确

    4. 验证HAL_CAN_Start()已调用

    5. 波特率不匹配

    6. 使用示波器测量实际波特率

    7. 重新计算时间参数

    8. 发送失败

    9. 检查CAN控制器是否进入Bus-Off状态

    10. 使用CAN分析仪监控总线活动


    七、扩展应用

  • CANopen协议栈移植

  • 多节点组网通信

  • 汽车诊断协议(ISO-TP)实现

  • 作者:DOMINICHZL

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32 CAN通信实战手册】原理与代码详解,手把手玩转CAN总线通信

    发表回复