STM32 CAN模块工作原理及实战应用详解

目录

概述

一、CAN模块核心原理

1. CAN协议基础

2. STM32 CAN控制器结构

3. 波特率配置

二、CAN模块配置步骤(基于HAL库)

1. 初始化CAN外设

2. 配置过滤器

3. 启动CAN通信

三、数据收发实现

1. 发送数据帧

2. 接收数据帧(中断方式)

四、高级应用场景

1. CANopen协议集成

2. 双CAN冗余设计

3. 总线诊断与错误处理

五、调试与优化技巧

1. 硬件调试要点

2. 软件调试工具

3. 性能优化策略

总结


概述

CAN模块(Controller Area Network)是一种面向现场总线通信的串行通信协议,通过CAN总线可以连接多个控制器和设备,实现实时的数据通信。在STM32微控制器中,CAN模块通常由以下几个主要部分组成:CAN控制器(CAN Controller),CAN收发器(CAN Transceiver),CAN过滤器(CAN Filter)。本文详细介绍STM32 CAN模块实现原理与应用方法。

一、CAN模块核心原理

1. CAN协议基础

  • 多主架构:任意节点可主动发送,通过仲裁机制解决冲突

  • 差分信号:CAN_H与CAN_L电压差表示逻辑(显性电平≈2V,隐性≈0V)

  • 帧类型

  • 数据帧:携带应用数据(标准帧11位ID,扩展帧29位ID)

  • 远程帧:请求数据发送

  • 错误帧:节点检测错误时发送

  • 过载帧:延迟下一帧发送

  • 2. STM32 CAN控制器结构

    
    
    typedef struct {
      __IO uint32_t MCR;     // 主控制寄存器
      __IO uint32_t MSR;     // 主状态寄存器
      __IO uint32_t TSR;     // 发送状态寄存器
      __IO uint32_t RF0R;    // 接收FIFO0寄存器
      __IO uint32_t RF1R;    // 接收FIFO1寄存器
      __IO uint32_t IER;     // 中断使能寄存器
      // ... 其他寄存器
    } CAN_TypeDef;
  • 双接收FIFO:FIFO0和FIFO1各3级缓存

  • 3个发送邮箱:支持优先级排序发送

  • 过滤器组:最多28组(F4系列),可配置为屏蔽或列表模式

  • 3. 波特率配置

  • 计算公式

    BaudRate = CAN Clock(Prescaler)×(BS1+BS2+1)BaudRate=(Prescaler)×(BS1+BS2+1)CAN Clock​
  • 典型配置(500kbps,APB1时钟42MHz):

    hcan.Init.Prescaler = 6;
    hcan.Init.TimeSeg1 = CAN_BS1_13TQ; // BS1 = 13 Tq
    hcan.Init.TimeSeg2 = CAN_BS2_2TQ;  // BS2 = 2 Tq
    hcan.Init.SJW = CAN_SJW_1TQ;       // 同步跳转宽度

  • 二、CAN模块配置步骤(基于HAL库)

    1. 初始化CAN外设

    
    CAN_HandleTypeDef hcan;
    
    void CAN_Init(void)
    {
      hcan.Instance = CAN1;
      hcan.Init.Mode = CAN_MODE_NORMAL;       // 正常模式
      hcan.Init.AutoBusOff = ENABLE;          // 自动总线关闭恢复
      hcan.Init.AutoWakeUp = DISABLE;         // 禁止自动唤醒
      hcan.Init.AutoRetransmission = ENABLE;  // 自动重传
      hcan.Init.ReceiveFifoLocked = DISABLE;  // FIFO不锁定
      hcan.Init.TimeTriggeredMode = DISABLE;  // 非时间触发模式
      
      if (HAL_CAN_Init(&hcan) != HAL_OK) {
        Error_Handler();
      }
    }

    2. 配置过滤器

    
    
    CAN_FilterTypeDef filter;
    
    void CAN_Filter_Config(void) 
    {
      filter.FilterBank = 0;                   // 使用过滤器组0
      filter.FilterMode = CAN_FILTERMODE_IDMASK; // 屏蔽模式
      filter.FilterScale = CAN_FILTERSCALE_32BIT;
      filter.FilterIdHigh = 0x123 << 5;        // 标准ID 0x123,左移5位对齐
      filter.FilterIdLow = 0x0000;
      filter.FilterMaskIdHigh = 0x7FF << 5;    // 检查所有标准ID位
      filter.FilterMaskIdLow = 0x0000;
      filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 匹配的报文存入FIFO0
      filter.FilterActivation = ENABLE;
      filter.SlaveStartFilterBank = 14;        // 双CAN时分配过滤器组
    
      HAL_CAN_ConfigFilter(&hcan, &filter);
    }

    3. 启动CAN通信

    
    
    HAL_CAN_Start(&hcan);
    HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // 使能接收中断

    三、数据收发实现

    1. 发送数据帧

    
    
    CAN_TxHeaderTypeDef tx_header;
    uint8_t tx_data[8] = {0x01, 0x02, 0x03, 0x04};
    uint32_t tx_mailbox;
    
    void CAN_SendMessage(void) 
    {
      tx_header.StdId = 0x123;              // 标准ID
      tx_header.ExtId = 0x00;               // 扩展ID(标准帧时设为0)
      tx_header.RTR = CAN_RTR_DATA;         // 数据帧
      tx_header.IDE = CAN_ID_STD;           // 标准ID格式
      tx_header.DLC = 4;                    // 数据长度4字节
      tx_header.TransmitGlobalTime = DISABLE;
    
      if (HAL_CAN_AddTxMessage(&hcan, &tx_header, tx_data, &tx_mailbox) != HAL_OK) {
        // 处理发送失败
      }
    }

    2. 接收数据帧(中断方式)

    
    
    void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) 
    {
      CAN_RxHeaderTypeDef rx_header;
      uint8_t rx_data[8];
      
      HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);
      
      if(rx_header.StdId == 0x123) { // 检查ID
        // 处理接收数据
      }
    }

    四、高级应用场景

    1. CANopen协议集成

  • 对象字典映射:将CAN ID与PDO/SDO映射

    // PDO通信参数配置
    CO_OD_configure(CO->SDO, 0x1400, 0x01, 0x00000200 + 0x123); // PDO1映射到ID 0x123
  • 心跳管理:周期性发送节点状态

    void Send_Heartbeat(void) 
    {
         uint8_t hb_msg[1] = {0x05}; // 运行状态
         CAN_SendMessage(0x700 + node_id, hb_msg, 1);
    }
  • 2. 双CAN冗余设计

  • 硬件连接:两个CAN控制器并联,共用总线

  • 故障切换逻辑

    
    
    if(CAN1_Status == ERROR) {
      HAL_CAN_Stop(&hcan1);
      HAL_CAN_Start(&hcan2); // 切换到CAN2
    }
  • 3. 总线诊断与错误处理

  • 错误计数器监控

    uint32_t err_code = hcan.Instance->ESR;
    uint8_t rec = (err_code & CAN_ESR_REC) >> 24; // 接收错误计数器
    uint8_t tec = (err_code & CAN_ESR_TEC) >> 16; // 发送错误计数器
  • 总线状态判断

  • Error Active:TEC/REC < 128

  • Error Passive:TEC/REC ≥ 128

  • Bus Off:TEC ≥ 256


  • 五、调试与优化技巧

    1. 硬件调试要点

  • 终端电阻:总线两端需接120Ω电阻

  • 信号质量检测

  • 示波器测量CAN_H与CAN_L差分信号

  • 确保显性电平1.5-3V,隐性电平<0.5V

  • 2. 软件调试工具

  • CAN分析仪:使用PCAN-USB或周立功CAN卡捕获报文

  • STM32CubeMonitor:实时监控CAN总线负载率

  • 3. 性能优化策略

  • DMA传输:使用DMA处理大批量数据

    HAL_CAN_Start_DMA(&hcan, CAN_RX_FIFO0);
  • 邮箱优先级:重要数据使用高优先级邮箱发送

    tx_header.TxPriority = CAN_TXPRIORITY_HIGH; // 设置发送优先级

  • 总结

    STM32 CAN模块为工业控制、汽车电子等场景提供可靠通信解决方案,开发时需注意:

  • 正确配置波特率:确保所有节点时钟参数一致

  • 合理使用过滤器:减少CPU中断负载

  • 错误处理机制:监控ESR寄存器,实现故障恢复

  • 协议栈集成:结合CANopen等高层协议提升开发效率

  • 示例代码基于STM32 HAL库实现,实际开发中需根据具体型号调整寄存器配置。对于高实时性要求场景,可结合FreeRTOS任务管理CAN通信,确保关键报文及时处理。

    作者:mftang

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 CAN模块工作原理及实战应用详解

    发表回复