首页 智能家居

STM32 CAN通信疑难杂症:TJA1050,波特率,USB扩展坞供电,逐一排查

分类:智能家居
字数: (5278)
阅读: (7683)
内容摘要:STM32 CAN通信疑难杂症:TJA1050,波特率,USB扩展坞供电,逐一排查,

最近在搞一个项目,用 STM32 控制器配合 TJA1050 CAN 收发器做 CAN 总线通信,结果死活连不上。波特率确认没问题,代码逻辑也反复检查,但就是收不到数据。更绝的是,调试过程中用到了 USB 扩展坞,结果问题变得更加诡异。这次就把整个排查过程和解决方案记录下来,希望能帮到大家。

问题场景重现:CAN分析仪无情显示无数据

硬件环境:

  • STM32F103C8T6 最小系统板
  • TJA1050 CAN 收发器模块
  • CAN 分析仪
  • USB 扩展坞

软件环境:

  • Keil MDK
  • 自定义的 CAN 通信协议

现象:

STM32 CAN通信疑难杂症:TJA1050,波特率,USB扩展坞供电,逐一排查
  • STM32 通过 TJA1050 发送 CAN 数据,CAN 分析仪显示无数据接收。
  • 使用 USB 扩展坞给 STM32 供电后,问题更加不稳定,有时能收到零星数据,有时完全没反应。

底层原理深度剖析:波特率、时序、供电噪声一个都不能少

  1. 波特率与时序

    CAN 总线通信对波特率精度要求很高。STM32 的 CAN 控制器需要配置正确的时钟源和分频系数,才能保证实际波特率与目标波特率一致。否则,接收端可能无法正确采样数据。如果用了 RTOS,需要确认时钟初始化有没有被其他任务干扰。此外,CAN 控制器的采样点位置也需要根据总线长度和节点数量进行调整,一般在 75% 左右。

  2. TJA1050 工作模式

    STM32 CAN通信疑难杂症:TJA1050,波特率,USB扩展坞供电,逐一排查

    TJA1050 有高速模式和低速模式,需要根据实际应用场景选择合适的工作模式。同时,需要注意 TJA1050 的使能引脚(通常是 Standby 引脚),确保其处于正常工作状态。

  3. 供电问题

    这是这次排查中最坑的地方。USB 扩展坞的供电质量参差不齐,一些劣质扩展坞可能会引入大量的噪声,影响 STM32 和 TJA1050 的正常工作。特别是在进行高速 CAN 通信时,电源噪声的影响更加明显。此外,USB 扩展坞的供电能力也可能不足,导致 STM32 工作不稳定。类似的情况也可能出现在使用面包板搭建电路时,面包板的接触电阻和分布电容可能会引入干扰。

    STM32 CAN通信疑难杂症:TJA1050,波特率,USB扩展坞供电,逐一排查

代码/配置解决方案:逐一击破

  1. 波特率配置

    // STM32 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, ENABLE);
    
        // 配置 CAN 引脚,PA11(CAN_RX)  PA12(CAN_TX)
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
        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;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        // 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 优先级模式
    
        // 波特率设置。1M波特率时,AP=0,TS1=12,TS2=2,BS=1
        CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; // 正常模式
        CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;       // 重新同步跳跃宽度1个时间单位
        CAN_InitStructure.CAN_BS1 = CAN_BS1_12tq;      // 时间段1为12个时间单位
        CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;       // 时间段2为2个时间单位
        CAN_InitStructure.CAN_Prescaler = 1;            // 分频系数(Fdiv)为1,最终波特率=Fpclk1/(Prescaler*(TS1+TS2+1))=36M/(1*(12+2+1))=1M
    
        CAN_Init(CAN1, &CAN_InitStructure);
    
        // CAN 过滤器初始化
        CAN_FilterInitStructure.CAN_FilterNumber = 0; // 过滤器组0
        CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; // 标识符屏蔽模式
        CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; // 32位宽
        CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;             // 32位ID高位
        CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;              // 32位ID低位
        CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;           // 32位MASK高位
        CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;            // 32位MASK低位
        CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; // 过滤器0关联到FIFO0
        CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;          // 使能过滤器
        CAN_FilterInit(&CAN_FilterInitStructure);
    
        // 使能 CAN 中断
        CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); // FIFO0 消息挂号中断使能
        NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;         // CAN1 RX0 中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   // 抢占优先级 1
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 子优先级 0
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              // 使能中断
        NVIC_Init(&NVIC_InitStructure);
    }
    
  2. TJA1050 使能引脚

    确保 TJA1050 的 Standby 引脚拉低,使其处于正常工作模式。

    STM32 CAN通信疑难杂症:TJA1050,波特率,USB扩展坞供电,逐一排查
    // 初始化 TJA1050 使能引脚
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能 GPIOB 时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 假设 PB0 连接 TJA1050 的 Standby 引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 拉低 Standby 引脚,使能 TJA1050
    
  3. 更换供电方式

    尝试使用质量更好的 USB 电源适配器,或者直接使用开发板自带的电源接口供电。如果条件允许,可以使用线性稳压电源,提供更纯净的电源。

  4. 增加滤波电容

    在 STM32 和 TJA1050 的电源引脚附近增加滤波电容,可以有效抑制电源噪声。建议使用 100nF 和 10uF 的电容并联。

    // 在电源引脚附近增加滤波电容
    // C1: 100nF, C2: 10uF
    

实战避坑经验总结

  1. 优先排除硬件问题:使用万用表检查 STM32、TJA1050 和 CAN 总线的连接是否正确,电源电压是否正常。
  2. 波特率校准至关重要:使用 CAN 分析仪测量实际波特率,并与目标波特率进行对比,确保误差在允许范围内。必要时,调整 STM32 的时钟配置。
  3. 供电是隐藏的雷:尽量避免使用劣质 USB 扩展坞供电。如果必须使用,尝试增加滤波电容,或者更换质量更好的电源适配器。
  4. 示波器是好帮手:使用示波器观察 CAN 总线上的信号波形,可以帮助判断是否存在噪声干扰或其他问题。重点关注信号的上升沿和下降沿是否平滑,是否存在毛刺。
  5. CAN分析仪的配置:有些CAN分析仪需要配置正确的波特率,才能正常接收数据,不要忽略这个配置。

最后,遇到类似问题,不要急于否定自己的代码。仔细分析问题现象,逐一排除可能的原因,才能最终找到解决方案。希望这篇文章能帮助大家少走弯路。

STM32 CAN通信疑难杂症:TJA1050,波特率,USB扩展坞供电,逐一排查

转载请注明出处: 键盘上的咸鱼

本文的链接地址: http://m.acea2.store/blog/112378.SHTML

本文最后 发布于2026-04-19 05:37:26,已经过了8天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 红豆沙 2 天前
    滤波电容是个好习惯,能有效降低电源噪声,提高系统的稳定性。建议大家养成良好习惯。