4、CAN位时序与同步:位时间组成、同步段、传播段、相位缓冲段、硬同步与重同步

各位同学,咱们今天聊点硬核的——CAN总线的位时序与同步。

说实话,我早年刚接触CAN的时候,觉得这东西不就是两根线来回传数据嘛,能有多复杂?直到有一次,我在一个电机控制项目里,总线速率怎么都提不上去,波形一塌糊涂。折腾了两天,最后发现是位时序配置出了问题。嗯,从那以后,我再也不敢小看这几个时间段的设置了。

4.1 位时间的基本组成

先说说位时间是什么。说白了,就是CAN总线上传输一个bit所花费的时间。比如你设置波特率为500kbps,那一个位时间就是2微秒。

一个完整的位时间,被分成了四个小段:

  • 同步段(Sync_Seg)
  • 传播段(Prop_Seg)
  • 相位缓冲段1(Phase_Seg1)
  • 相位缓冲段2(Phase_Seg2)

你想想看,为什么要把一个bit切得这么碎?其实就是为了容错和同步。CAN总线上的节点没有独立的时钟线,全靠这根数据线来对齐节奏。没有这些分段,稍微有点时钟偏差,整个网络就乱套了。

核心公式:

位时间 = TQ × (Sync_Seg + Prop_Seg + Phase_Seg1 + Phase_Seg2)

其中TQ(Time Quantum)是时间量子,由晶振分频得到。

4.2 同步段(Sync_Seg)

同步段是位时间的第一段,固定为1个TQ。它的作用很简单——等待总线上的跳变沿。

每个节点在同步段内,会检测CAN总线上的电平变化。如果检测到从隐性到显性的跳变,就认为这是一个同步信号。

我个人习惯把同步段想象成「对齐窗口」。就像两个人一起跑步,听到发令枪响的那一刻,大家同时起跑。这个发令枪,就是同步段的作用。

4.3 传播段(Prop_Seg)

传播段是用来补偿物理延迟的。包括:

  • 信号在总线上的传输延迟
  • 收发器的输入输出延迟
  • 比较器的处理延迟

我在项目中遇到过一个问题:总线长度超过50米,传播段设得太短,结果远端节点的信号总是采样错误。后来我把传播段从3个TQ加到了5个TQ,问题立刻解决。

经验值参考:

传播段的长度一般设置为2~8个TQ。具体取决于总线长度和晶振精度。总线每增加10米,建议增加1个TQ的传播段。

4.4 相位缓冲段(Phase_Seg1 和 Phase_Seg2)

这两个段是位时序的「弹性空间」。它们的作用是在重同步时,吸收节点之间的时钟偏差。

Phase_Seg1:位于采样点之前。重同步时,如果发现对方时钟偏慢,可以延长Phase_Seg1来等待。

Phase_Seg2:位于采样点之后。重同步时,如果发现对方时钟偏快,可以缩短Phase_Seg2来追赶。

采样点就落在Phase_Seg1和Phase_Seg2之间。这个位置非常关键。我一般把采样点设置在85%~90%的位置,这样留给信号稳定建立的时间更充裕。

参数 典型值 说明
Sync_Seg 1 TQ 固定值,不可调整
Prop_Seg 2~8 TQ 根据总线长度调整
Phase_Seg1 2~8 TQ 可被延长
Phase_Seg2 2~8 TQ 可被缩短
SJW 1~4 TQ 同步跳转宽度

4.5 硬同步(Hard Synchronization)

硬同步发生在总线从空闲状态切换到帧起始的时候。具体来说,就是SOF(Start of Frame)位从隐性跳变到显性的那个时刻。

硬同步的规则很简单:

  • 每个节点检测到SOF的下降沿后,立即将自己的位时序计数器清零
  • 所有节点强制对齐到同一个起点
  • 硬同步只在帧开始时发生一次

我曾经调试过一个多节点通信异常的问题,发现有个节点的晶振偏差太大,硬同步后没多久就跑偏了。嗯,这里要注意:硬同步只能解决初始对齐问题,后续的偏差要靠重同步来纠正。

4.6 重同步(Resynchronization)

重同步发生在帧传输过程中。当节点检测到总线上的跳变沿与自己的预期位置有偏差时,就会触发重同步。

重同步有两种方式:

  1. 延长Phase_Seg1:如果跳变沿来得比预期晚,说明对方时钟偏慢。这时延长Phase_Seg1,把采样点往后推。
  2. 缩短Phase_Seg2:如果跳变沿来得比预期早,说明对方时钟偏快。这时缩短Phase_Seg2,把采样点往前拉。

但重同步不是无限调整的。它受限于SJW(Synchronization Jump Width)。SJW决定了每次重同步最多能调整多少个TQ。

避坑指南:

我曾经把SJW设得太大,结果总线上的噪声跳变也触发了重同步,导致采样点乱跳,误码率飙升。SJW一般设置为1~2个TQ就够了,除非你的晶振精度特别差。

4.7 采样点的选择

采样点就是节点读取总线电平的时刻。它位于Phase_Seg1和Phase_Seg2之间。

采样点位置的计算公式:

采样点位置 = (Sync_Seg + Prop_Seg + Phase_Seg1) / 位时间 × 100%

举个例子,假设位时间由10个TQ组成:

  • Sync_Seg = 1 TQ
  • Prop_Seg = 3 TQ
  • Phase_Seg1 = 3 TQ
  • Phase_Seg2 = 3 TQ

那么采样点位置 = (1 + 3 + 3) / 10 = 70%。这个位置偏低了,容易采到不稳定的信号。

我一般推荐采样点设置在85%~90%。比如:

  • Sync_Seg = 1 TQ
  • Prop_Seg = 4 TQ
  • Phase_Seg1 = 4 TQ
  • Phase_Seg2 = 1 TQ

采样点 = (1 + 4 + 4) / 10 = 90%。这个配置在大多数场景下都很稳。

4.8 实际配置示例

最后,我给大家一个实际项目中用过的配置。假设晶振为16MHz,目标波特率500kbps:

// 计算TQ
BRP = 1;  // 预分频器,TQ = 2 × (BRP + 1) / 16MHz = 0.25us

// 位时间 = 2us / 0.25us = 8 TQ
// 配置如下:
Sync_Seg = 1 TQ
Prop_Seg = 2 TQ
Phase_Seg1 = 3 TQ
Phase_Seg2 = 2 TQ
SJW = 1 TQ

// 采样点 = (1 + 2 + 3) / 8 = 75%

这个配置采样点在75%,对于短距离通信(<10米)完全够用。如果总线更长,我会把Prop_Seg加到3或4,同时减少Phase_Seg2来保持总TQ不变。

我的习惯:

每次配置完位时序,我都会用示波器抓一下CAN_H和CAN_L的差分波形,看看采样点附近有没有毛刺。如果有,就微调Prop_Seg和Phase_Seg的比例。实践出真知,纸上谈兵没用。

好了,位时序与同步的内容就讲到这里。下一章咱们聊聊CAN的错误检测与处理机制,那个更刺激——我当年被一个隐性错误码坑了整整一周。