一、硬件配置
  1. 核心电路设计

    • 信号线连接

      STM32引脚 TJA1050引脚 功能说明
      PA11 RXD CAN接收输入(需上拉)
      PA12 TXD CAN发送输出(推挽驱动)
    • 总线连接

      • TJA1050的CANH/CANL连接至总线,两端各接120Ω终端电阻

      • 总线共地,避免电位差干扰

  2. 关键参数

    • 供电要求:TJA1050需5V供电,与STM32共地

    • 波特率配置:典型值500kbps(APB1时钟36MHz,分频系数18)

    • 引脚重映射:默认PA11/PA12,需在CubeMX开启CAN_REMAP[1:0]=10


二、软件实现(STM32CubeMX + HAL库)
1. CubeMX配置流程
  1. 外设使能:勾选CAN1,模式选择Normal(正常模式)

  2. 波特率设置

    • APB1时钟:36MHz

    • 预分频系数:18

    • 时间段配置:SYNC_SEG=1tq, PRS=1tq, SBS1=2tq, SBS2=3tq

    • 最终波特率:36MHz/(18×(1+2+3))=500kbps

  3. 过滤器配置

    • 过滤器模式:Mask Mode

    • 过滤器尺度:32位

    • 过滤器ID:0x0000(接收所有标准ID)

  4. 中断配置:使能CAN_RX0_IRQn中断

2. 关键代码实现
// can.c
#include "can.h"

CAN_HandleTypeDef hcan1;

void MX_CAN1_Init(void)
{
  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 18;              // 分频系数
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; // 同步跳转宽度
  hcan1.Init.TimeSeg1 = CAN_BS1_2TQ;      // 时间段1
  hcan1.Init.TimeSeg2 = CAN_BS2_3TQ;      // 时间段2
  hcan1.Init.Mode = CAN_MODE_NORMAL;      // 正常模式
  hcan1.Init.AutoRetransmission = DISABLE;// 关闭自动重传
  HAL_CAN_Init(&hcan1);
}

// 过滤器配置
void CAN_Filter_Config(void)
{
  CAN_FilterTypeDef sFilterConfig;
  sFilterConfig.FilterBank = 0;           // 过滤器组0
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位尺度
  sFilterConfig.FilterIdHigh = 0x0000;    // 高16位
  sFilterConfig.FilterIdLow = 0x0000;     // 低16位
  sFilterConfig.FilterMaskIdHigh = 0x0000;// 掩码高16位
  sFilterConfig.FilterMaskIdLow = 0x0000; // 掩码低16位
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 分配到FIFO0
  HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
}

// CAN接收中断服务函数
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  HAL_CAN_IRQHandler(&hcan1);
}

// 接收回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
  CanRxMsgTypeDef RxMessage;
  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxMessage, RxData);
  printf("Received ID:0x%03X, Data:", RxMessage.StdId);
  for(int i=0; i<8; i++) printf("%02X ", RxData[i]);
  printf("\r\n");
}
3. 发送与接收函数
// 发送数据(标准帧)
void CAN_Send_Msg(uint32_t StdId, uint8_t *data, uint8_t len)
{
  CanTxMsgTypeDef TxMessage = {0};
  TxMessage.StdId = StdId;      // 标准ID
  TxMessage.IDE = CAN_ID_STD;   // 标准帧模式
  TxMessage.RTR = CAN_RTR_DATA; // 数据帧
  TxMessage.DLC = len;          // 数据长度
  memcpy(TxMessage.Data, data, len);
  
  uint32_t TxMailbox;
  HAL_CAN_AddTxMessage(&hcan1, &TxMessage, data, &TxMailbox);
}

// 接收数据(轮询模式)
void CAN_Recv_Msg(uint8_t *data)
{
  CanRxMsgTypeDef RxMessage;
  if(HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) > 0)
  {
    HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxMessage, data);
  }
}

三、调试与常见问题
  1. 信号验证

    • 使用示波器测量CAN_H/CAN_L差分电压:

      • 空闲状态:CAN_H=2.5V, CAN_L=2.5V(差分0V)

      • 显性电平:CAN_H=3.5V, CAN_L=1.5V(差分2V)

    • 逻辑分析仪捕获CAN帧结构(标识符+数据)

  2. 常见问题解决

    现象 可能原因 解决方案
    无法初始化 引脚未重映射 检查CubeMX的CAN_REMAP配置
    接收不到数据 过滤器未配置 设置接收所有ID(0x0000掩码)
    数据错误 总线终端电阻缺失 添加120Ω电阻至总线两端
    通信不稳定 电源噪声干扰 增加0.1μF陶瓷电容并联10μF电解电容

参考代码 STM32F103C8T6 CAN通讯 www.youwenfan.com/contentcsr/102049.html

四、扩展功能实现
  1. 多节点通信

    • 每个节点分配唯一ID(如0x100~0x1FF)

    • 示例:节点1发送数据至节点2

      // 节点1发送
      uint8_t data[8] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
      CAN_Send_Msg(0x100, data, 8);
      
      // 节点2接收
      CAN_Recv_Msg(RxData);
      if(RxMessage.StdId == 0x100) process_data(RxData);
      
  2. CAN总线波特率自适应

    // 动态切换波特率(需重新初始化CAN)
    void CAN_SetBaudRate(uint32_t baud)
    {
      hcan1.Instance->BTR = (SystemCoreClock/2)/(baud*(1+CAN_BS1_2TQ+CAN_BS2_3TQ));
      HAL_CAN_Stop(&hcan1);
      HAL_CAN_Init(&hcan1);
    }
    
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐