第4章:CAN总线位时序与同步:位时间组成、同步段(SS)、传播段(PTS)、相位缓冲段1(PBS1)、相位缓冲段2(PBS2)、硬同步与重同步
各位工程师,大家好。欢迎来到第四章。
前面我们聊了CAN的物理层和数据链路层,但有个核心问题一直没细说——时钟同步。说白了,CAN总线没有单独的时钟线,所有节点都得靠自己的晶振“猜”别人的节奏。这怎么行?
嗯,今天我们就来彻底搞懂CAN的位时序与同步机制。我个人觉得,这是CAN协议里最精妙、也最容易踩坑的地方。
4.1 位时间的组成:一个“位”是怎么切开的?
先问个问题:一个CAN数据位,在总线上持续多久?
答案取决于波特率。比如1Mbps,一个位就是1微秒。但CAN控制器不会傻等1微秒,它会把这一微秒切成四段来精细控制。
这四段分别是:
- 同步段(SS):用于检测总线上的跳变沿。固定为1个Tq(时间量子)。
- 传播段(PTS):补偿信号在总线上的传播延迟。我一般设2-3个Tq。
- 相位缓冲段1(PBS1):用于重同步时延长采样点。可调。
- 相位缓冲段2(PBS2):用于重同步时缩短采样点。可调。
一个完整的位时间 = SS + PTS + PBS1 + PBS2。采样点就在PBS1和PBS2之间。
核心公式:
位时间(Tbit)= 同步段 + 传播段 + 相位缓冲段1 + 相位缓冲段2
采样点位置 = (SS + PTS + PBS1) / Tbit × 100%
举个例子。假设Tq=100ns,位时间=10Tq=1μs(即1Mbps)。我习惯这样分配:
- SS = 1 Tq
- PTS = 3 Tq
- PBS1 = 3 Tq
- PBS2 = 3 Tq
采样点就在第7个Tq结束时,也就是70%的位置。为什么是70%?后面会讲。
4.2 同步段(SS):一切同步的起点
同步段只有一个作用:检测总线上的下降沿(从显性到隐性,或隐性到显性)。
CAN协议规定,每个节点必须在SS段内采样总线电平。如果检测到跳变沿,就认为这是一个“同步信号”。
我的经验: 有些新手会把SS段设得很长,觉得这样能提高容错。其实没必要。SS固定为1Tq就够了。设长了反而会压缩后面的缓冲段,导致同步范围变小。
4.3 传播段(PTS):补偿物理延迟
信号在总线上传输需要时间。比如总线长度40米,信号传播速度约5ns/m,那么来回就是40×5×2=400ns。
传播段就是用来补偿这个延迟的。它必须大于等于2倍的物理延迟(发送到接收再返回)。
我建议这样算:
- 先测量总线长度
- 估算最远两个节点的往返延迟
- PTS ≥ 2 × 最大传播延迟
举个例子。总线长50米,传播延迟5ns/m,往返就是500ns。如果Tq=125ns,那么PTS至少需要4个Tq。我一般会留余量,设成5个Tq。
注意: PTS设得太小,远距离节点会采样到错误电平。我曾经在一个项目中,因为PTS少设了1个Tq,导致总线长度超过30米后频繁出错。排查了整整两天才找到原因。
4.4 相位缓冲段1和2(PBS1/PBS2):同步的“弹性空间”
这两个段是同步机制的核心。它们的作用是:允许采样点前后移动。
- PBS1:重同步时,可以延长(增加采样前的等待时间)。
- PBS2:重同步时,可以缩短(减少采样后的等待时间)。
说白了,如果某个节点发现自己的时钟比总线慢了一点,它就会延长PBS1,让采样点往后挪。如果发现自己的时钟快了,就缩短PBS2,让采样点往前挪。
这个调整范围叫做同步跳转宽度(SJW)。SJW决定了每次重同步最多能调整多少个Tq。
重要规则:
- SJW ≤ PBS1
- SJW ≤ PBS2
- SJW ≥ 1(通常设1-2个Tq)
我个人习惯把SJW设成1个Tq。为什么?因为大多数晶振的误差在1%以内,1个Tq的调整量足够应对。设大了反而可能引入抖动。
4.5 硬同步与重同步:两种同步方式
CAN的同步分两种:硬同步和重同步。
4.5.1 硬同步
发生在总线空闲时。当节点检测到SOF(帧起始)的下降沿,它会立即将当前位时间重置到SS段。这就是硬同步。
硬同步只发生在帧开始时,且只调整一次。
4.5.2 重同步
发生在帧传输过程中。如果节点在SS段之后检测到跳变沿,说明时钟有偏差,需要调整。
- 如果跳变沿出现在PBS1内:说明节点时钟偏慢,需要延长PBS1。
- 如果跳变沿出现在PBS2内:说明节点时钟偏快,需要缩短PBS2。
重同步可以多次发生,每次调整不超过SJW。
避坑指南: 我曾经在一个项目中,把SJW设成了3个Tq,结果发现总线偶尔出现位错误。后来分析波形才发现,重同步调整量太大,导致采样点跳过了正确的电平。从那以后,我坚持SJW不超过2个Tq。
4.6 采样点位置的选择:70%还是80%?
采样点位置直接影响通信可靠性。太靠前,容易采到信号前沿的振荡;太靠后,又可能采到下一个位的开始。
我推荐以下经验值:
| 波特率 | 推荐采样点位置 | 说明 |
|---|---|---|
| 125kbps | 70% - 75% | 低速总线,传播延迟影响小 |
| 250kbps | 70% - 75% | 常用值 |
| 500kbps | 75% - 80% | 高速总线,需要更多余量 |
| 1Mbps | 80% - 85% | 极高速,采样点尽量靠后 |
为什么高速时要靠后?因为信号在总线上有建立时间。采样点靠后,能确保信号已经稳定。
4.7 实战配置示例
假设我们要配置一个500kbps的CAN网络,Tq=125ns(即8MHz晶振,分频后得到)。
位时间 = 1/500kbps = 2000ns = 16个Tq。
我这样分配:
- SS = 1 Tq
- PTS = 5 Tq(补偿约625ns的传播延迟)
- PBS1 = 5 Tq
- PBS2 = 5 Tq
- SJW = 1 Tq
采样点位置 = (1+5+5)/16 = 68.75%。嗯,稍微偏低,但考虑到总线长度不超过20米,这个值完全够用。
配置代码示例(基于STM32 HAL库):
// 假设CAN时钟频率为8MHz
// 目标波特率500kbps
// 位时间 = 16 Tq
CAN_HandleTypeDef hcan;
hcan.Instance = CAN1;
hcan.Init.Prescaler = 1; // 分频系数,Tq = 125ns
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ; // SJW = 1 Tq
hcan.Init.TimeSeg1 = CAN_BS1_10TQ; // SS + PTS + PBS1 = 1+5+5 = 11 Tq
hcan.Init.TimeSeg2 = CAN_BS2_5TQ; // PBS2 = 5 Tq
// 注意:TimeSeg1包含了SS段,所以实际是11Tq
// 采样点位置 = 11/16 = 68.75%
配置完成后,记得用示波器抓一下CAN_H和CAN_L的波形,确认位时间是否正确。我习惯在总线上发一个0x55(交替位),这样能清楚看到每个位的长度。
4.8 常见问题与排查
最后,分享几个我踩过的坑:
- 问题: 总线偶尔出现位错误,但频率不高。
排查: 检查采样点位置。我遇到过采样点设在50%的情况,结果信号上升沿刚好在采样点附近,导致误判。 - 问题: 长距离通信失败。
排查: 计算传播延迟,适当增加PTS。我曾经把PTS从3Tq增加到5Tq,问题就解决了。 - 问题: 不同晶振的节点无法通信。
排查: 检查SJW是否足够大。如果晶振误差超过1%,SJW需要设成2Tq。
嗯,这一章的内容就到这里。位时序和同步是CAN协议的基石,理解透了,后面的错误处理、总线仲裁都会轻松很多。
下一章,我们聊聊CAN的帧格式——数据帧、远程帧、错误帧和过载帧。到时候见。