目录

STM32-CAN模块原理与应用详解

STM32 CAN模块原理与应用详解


概述

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通信,确保关键报文及时处理。