3、心跳调试技巧:用CAN分析仪抓包,处理超时,排查故障

心跳机制这东西,配置起来看着简单,真到现场调试的时候,坑可不少。我这些年经手过不少CANopen项目,从伺服驱动器到IO模块,心跳问题几乎占了通讯故障的一半。说白了,心跳就是“我还在,你放心”的信号。一旦丢了,系统就得做出反应。

这一节,咱们就聊聊怎么用CAN分析仪抓心跳包、怎么处理超时、以及那些常见的坑怎么绕过去。

3.1 用CAN分析仪抓心跳包——别靠猜

调试心跳,第一件事就是看波形。别靠猜,别靠日志打印,直接上分析仪。我个人习惯用PCAN-View或者周立功的ZCANPro,抓几秒钟数据,什么都清楚了。

3.1.1 抓包步骤

  1. 连接硬件:分析仪接到CAN总线上,终端电阻确认接好(120Ω,两端都要有)。
  2. 设置过滤:心跳报文是生产者主动发送的,COB-ID = 0x700 + Node-ID。比如节点1的心跳,COB-ID就是0x701。
  3. 开始抓取:让设备运行起来,观察报文是否按预期周期出现。
  4. 检查数据域:心跳报文只有1个字节数据,表示节点状态。0x00=启动中,0x04=停止,0x05=运行,0x7F=预操作。
小技巧:抓包时把时间戳精度调到微秒级。我曾经遇到一个案子,心跳周期设了100ms,但实际间隔在98ms到105ms之间抖动,用毫秒级时间戳根本看不出来。

3.1.2 正常心跳长什么样?

下面是一个正常心跳流的例子。节点1(Node-ID=1)的心跳COB-ID=0x701,数据=0x05(运行状态),周期100ms。

时间戳          COB-ID   DLC  数据
0.000000        0x701    1     05
0.100123        0x701    1     05
0.200045        0x701    1     05
0.300078        0x701    1     05
0.400112        0x701    1     05

看到没?间隔稳定在100ms左右,数据一直是0x05。这就是健康的心跳。

3.2 心跳超时处理——系统怎么知道“你死了”?

心跳超时,指的是消费者在规定时间内没收到生产者的心跳报文。这个规定时间就是心跳超时时间,计算公式很简单:

心跳超时时间 = 心跳生产周期 × 心跳消费因子

比如:生产周期100ms,消费因子3,超时时间就是300ms。

一旦超时,消费者会怎么做?这取决于你配置的错误行为。CANopen定义了以下几种:

错误行为代码 含义 典型场景
0 无动作(仅记录) 调试阶段,先看看再说
1 停止发送PDO 从站故障,主站停止输出
2 停止所有通讯 安全关键系统,直接断联
3 进入预操作状态 需要手动恢复的场景

我记得有一次做AGV小车项目,心跳超时设了500ms,消费因子设了5。结果车子一转弯,CAN总线受干扰丢了几帧,系统直接急停。后来我把消费因子改成10,超时时间变成1秒,问题就解决了。说白了,超时时间要留余量,别卡得太死。

3.3 常见故障排查——这些坑我都踩过

下面这几个问题,是我在实际项目中反复遇到的。你如果也碰到类似情况,直接对照排查就行。

3.3.1 心跳报文时有时无

现象:抓包看到心跳报文断断续续,有时候几秒才来一帧。
原因:大概率是CAN总线负载太高,心跳报文优先级不够,被其他报文挤掉了。
排查方法:

  • 用分析仪看总线负载率,超过60%就要小心了。
  • 检查心跳COB-ID是否被其他报文占用。心跳的优先级(0x700+Node-ID)其实不算高,如果总线上有大量0x200以下的PDO,心跳可能被延迟。
  • 我建议把心跳COB-ID设得高一点,比如用0x100+Node-ID(需要修改EDS文件)。

3.3.2 心跳状态一直显示“启动中”

现象:抓包看到数据一直是0x00(启动中),从不变成0x05(运行)。
原因:设备没有完成初始化,或者NMT状态机卡住了。
排查方法:

  • 发送NMT命令0x01(启动节点),看设备是否响应。
  • 检查设备的应用层代码,是不是在进入运行状态前卡在某个初始化函数里了。
  • 我曾经遇到一个情况,设备上电后要等传感器自检,自检没通过就一直停在预操作状态。后来在代码里加了超时强制进入运行的逻辑。

3.3.3 心跳超时误报

现象:消费者频繁报心跳超时,但抓包看到心跳报文是正常的。
原因:消费者和生产者的时间基准不一致,或者消费因子配置错误。
排查方法:

  • 核对两边的心跳生产周期(0x1017)和心跳消费因子(0x1016)是否匹配。
  • 检查消费者的时钟精度。有些低端MCU的定时器漂移严重,100ms的周期实际可能变成110ms。
  • 我建议在消费者端加一个“容忍窗口”,比如超时时间 = 生产周期 × 消费因子 + 10ms。
注意:千万不要把心跳超时时间设得比生产周期还短。我见过有人把消费因子设成1,生产周期100ms,超时时间也是100ms。结果总线稍微抖动一下,系统就崩了。消费因子至少设3,这是行业惯例。

3.4 心跳调试流程图

下面这张图,是我自己调试心跳时用的流程。你照着走一遍,大部分问题都能定位。

心跳调试流程图 开始调试 1. 用分析仪抓取心跳报文 有报文? 检查硬件连接 检查周期和状态 2. 核对心跳周期和消费因子 匹配? 修改EDS配置 检查总线负载 3. 验证超时处理逻辑 调试完成 常见坑点 • 消费因子不要设1 • 超时时间留20%余量 • 检查终端电阻

3.5 避坑指南——我踩过的几个雷

最后,分享几个我亲身踩过的坑,你遇到了直接绕过去。

  • 坑一:心跳周期和消费因子不匹配。我曾经在项目里把生产周期设了200ms,消费因子设了2,超时时间400ms。结果从站实际心跳周期是250ms(晶振不准),消费者那边400ms一到就报超时。后来我把消费因子改成3,问题解决。
  • 坑二:多个消费者共享一个心跳。一个生产者发心跳,总线上多个消费者都在监听。如果某个消费者的消费因子设得太小,它先超时了,其他消费者还没事。这会导致系统行为不一致。我建议所有消费者的超时时间保持一致。
  • 坑三:心跳报文被CAN控制器过滤掉。有些CAN控制器默认只接收特定ID的报文。如果你忘了配置接收过滤,心跳报文根本进不了应用层。抓包能看到,但设备就是没反应。嗯,这个坑我至少见过三次。

总结一句话:心跳调试,先抓包,再对参数,最后看逻辑。别跳步骤,别凭感觉。