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)
重同步发生在帧传输过程中。当节点检测到总线上的跳变沿与自己的预期位置有偏差时,就会触发重同步。
重同步有两种方式:
- 延长Phase_Seg1:如果跳变沿来得比预期晚,说明对方时钟偏慢。这时延长Phase_Seg1,把采样点往后推。
- 缩短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的错误检测与处理机制,那个更刺激——我当年被一个隐性错误码坑了整整一周。