首页 大数据

STM32 CAN通信疑难杂症:TJA1050握手失败,USB扩展坞竟是罪魁祸首?

分类:大数据
字数: (6447)
阅读: (7129)
内容摘要:STM32 CAN通信疑难杂症:TJA1050握手失败,USB扩展坞竟是罪魁祸首?,

最近在搞一个项目,使用 STM32 进行 CAN 总线通信,采用 TJA1050 作为 CAN 收发器。理论上应该非常简单的东西,结果卡了很久,各种波特率、滤波器设置、STM32 芯片配置都检查了无数遍,数据就是发不出去。后来发现,问题竟然出在一个小小的 USB 扩展坞上,简直是绝了!

问题场景重现:CAN分析仪的迷惑行为

我用的是周立功的 CAN 分析仪,能正常收发数据。但是 STM32 这边,用示波器看 CAN_H 和 CAN_L 的波形,波形是有的,但就是没法和设备建立通信。用 CAN 分析仪监控 STM32 发送的数据,完全看不到。一开始怀疑是 STM32 程序的问题,各种调试,甚至重新写了 CAN 的初始化代码,依然无效。波特率、仲裁场、数据场等等都用 CAN 分析仪确认过,和程序里设置的完全一致。

STM32 CAN通信疑难杂症:TJA1050握手失败,USB扩展坞竟是罪魁祸首?

底层原理深度剖析:TJA1050与CAN总线的握手协议

CAN 通信需要 CAN 控制器和 CAN 收发器协同工作。STM32 内部集成了 CAN 控制器,而 TJA1050 负责物理层的信号收发。CAN 控制器负责处理 CAN 协议的各种帧类型(数据帧、遥控帧、错误帧、过载帧),并进行位时序控制(同步段、传播段、相位缓冲段 1、相位缓冲段 2)。

STM32 CAN通信疑难杂症:TJA1050握手失败,USB扩展坞竟是罪魁祸首?

TJA1050 作为一个物理层器件,负责将 CAN 控制器发出的逻辑信号转换为差分信号,并通过 CAN_H 和 CAN_L 线发送到 CAN 总线上。同时,它也负责接收 CAN 总线上的差分信号,并将其转换为逻辑信号传递给 CAN 控制器。如果 STM32 和 TJA1050 之间的连接有问题,或者 TJA1050 的供电有问题,都会导致通信失败。

STM32 CAN通信疑难杂症:TJA1050握手失败,USB扩展坞竟是罪魁祸首?

代码/配置解决方案:基础配置检查与优化

首先,必须确保 STM32 的 CAN 初始化配置正确。这里贴一段示例代码:

STM32 CAN通信疑难杂症:TJA1050握手失败,USB扩展坞竟是罪魁祸首?
// CAN 初始化函数
void CAN_Config(void)
{
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  // 使能 CAN 时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

  // 配置 CAN 引脚:PA11 (CAN_RX) and PA12 (CAN_TX)
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; // CAN_RX
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; // CAN_TX
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_PinRemapConfig(GPIO_Remap_CAN1, ENABLE); // CAN 端口重映射

  // CAN 单元初始化
  CAN_InitStructure.CAN_TTCM = DISABLE; // 时间触发通信模式
  CAN_InitStructure.CAN_ABOM = DISABLE; // 自动离线管理
  CAN_InitStructure.CAN_AWUM = DISABLE; // 自动唤醒模式
  CAN_InitStructure.CAN_NART = DISABLE; // 禁止报文重传
  CAN_InitStructure.CAN_RFLM = DISABLE; // 接收 FIFO 锁定模式
  CAN_InitStructure.CAN_TXFP = DISABLE; // 发送 FIFO 优先级
  CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; // 正常模式
  CAN_InitStructure.CAN_SJW  = CAN_SJW_1tq; // 同步跳转宽度 1 个时间单元
  CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq; // 时间段 1 为 8 个时间单元
  CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq; // 时间段 2 为 7 个时间单元
  CAN_InitStructure.CAN_Prescaler = 3; // 分频系数 (设置波特率,这里 36MHz/ (1+8+7)/3 = 500kbps)
  CAN_Init(CAN1, &CAN_InitStructure);

  // CAN 过滤器配置
  CAN_FilterInitStructure.CAN_FilterNumber = 0; // 过滤器编号
  CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; // 屏蔽位模式
  CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; // 32 位
  CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; // 过滤器 ID 高 16 位
  CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; // 过滤器 ID 低 16 位
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; // 屏蔽 ID 高 16 位
  CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000; // 屏蔽 ID 低 16 位
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0; // 过滤器关联到 FIFO0
  CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; // 使能过滤器
  CAN_FilterInit(&CAN_FilterInitStructure);

  // 使能 CAN RX 中断
  CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

  // 配置 NVIC 中断控制器
  NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; // CAN RX0 中断通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
  NVIC_Init(&NVIC_InitStructure);
}
// 中断处理函数
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  CanRxMsg RxMessage;
  CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
  // 处理接收到的 CAN 数据
  // ...
}

代码中,CAN_Prescaler 参数非常重要,它决定了 CAN 总线的波特率。务必根据实际需求进行调整。另外,CAN 过滤器的配置也需要仔细检查,确保能够接收到目标 ID 的数据。

实战避坑经验总结:USB 扩展坞的罪与罚

经过一系列的排查,我发现问题竟然出在 USB 扩展坞上!我把 STM32 的 ST-Link 下载器插在了 USB 扩展坞上,然后 ST-Link 再连接到 STM32 开发板。换句话说,STM32 的供电和调试都通过 USB 扩展坞。但是,这个 USB 扩展坞的供电能力不足,导致 STM32 工作不稳定,CAN 收发器 TJA1050 的工作电压也跟着波动,最终导致 CAN 通信失败。将 ST-Link 直接插到电脑的 USB 接口上,问题立刻解决!

总结一下几个关键点:

  • 供电问题: 确保 STM32 和 TJA1050 的供电稳定可靠。尽量避免使用劣质的 USB 扩展坞,特别是那些供电能力不足的扩展坞。
  • 接地问题: 确保 STM32、TJA1050 和 CAN 总线的地线连接良好,避免出现地线环路。
  • 波特率匹配: 确保 STM32、CAN 分析仪和其他 CAN 设备使用相同的波特率。
  • 终端电阻: CAN 总线的两端需要连接 120 欧姆的终端电阻,以防止信号反射。
  • 示波器调试: 使用示波器观察 CAN_H 和 CAN_L 的波形,可以帮助你判断 CAN 总线上是否存在问题。

这个坑踩得真是印象深刻,以后再遇到类似问题,一定要先排除供电问题!

STM32 CAN通信疑难杂症:TJA1050握手失败,USB扩展坞竟是罪魁祸首?

转载请注明出处: 代码一只喵

本文的链接地址: http://m.acea1.store/blog/317578.SHTML

本文最后 发布于2026-04-28 04:12:27,已经过了0天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 起床困难户 1 小时前
    周立功的CAN分析仪确实好用,但是遇到这种供电问题也无力回天啊。
  • 佛系青年 5 天前
    这问题太坑了,我之前也遇到过类似的情况,排查了好久才发现是 USB 供电的问题,简直无语。
  • 铲屎官 1 天前
    CAN 总线通信真是细节决定成败,一个小小的电阻或者供电问题都可能导致通信失败。