4、CAN总线位时序与同步:位时间分段与同步机制
位时序和同步,说白了就是CAN总线上的“时钟对齐”问题。很多新手工程师觉得这玩意儿太抽象,不就是发数据嘛,能发出去不就行了?
我刚开始做CAN项目时也这么想。直到有一次,我在一个电机控制项目里,总线速率设成了500kbps,结果节点一多,时不时就丢帧。查了三天,最后发现是位时序参数配错了,采样点位置不对。嗯,从那以后我再也不敢小看位时序了。
4.1 位时间的基本概念
CAN总线上传输一个bit需要多长时间?这个时间就叫位时间。它不是一个单纯的物理时间,而是被分成了几个逻辑段。
为什么非要分段?因为CAN总线是异步通信,没有单独的时钟线。每个节点都得靠自己内部的时钟去“猜”什么时候该采样。分段的目的,就是为了让这个“猜”的过程更可靠。
一个完整的位时间,被分成4个段:
| 段名称 | 缩写 | 作用 | 典型长度 |
|---|---|---|---|
| 同步段 | SS | 检测总线上的边沿跳变 | 1 Tq |
| 传播时间段 | PTS | 补偿信号在总线上的传播延迟 | 1~8 Tq |
| 相位缓冲段1 | PBS1 | 采样点前的时间缓冲,用于再同步 | 1~8 Tq |
| 相位缓冲段2 | PBS2 | 采样点后的时间缓冲,用于再同步 | 1~8 Tq |
这里有个基础单位——Tq(Time Quantum,时间量子)。它是CAN控制器内部的最小时间单位,由系统时钟分频得到。整个位时间就是若干个Tq拼起来的。
核心公式:
位时间 = SS + PTS + PBS1 + PBS2
采样点位置 = (SS + PTS + PBS1) / 位时间
采样点位置很关键。我一般习惯把采样点放在位时间的85%~90%左右。太靠前,信号还没稳定;太靠后,留给PBS2的时间不够,再同步就不好使了。
4.2 四个段到底在干什么?
同步段(SS)
这个段固定为1个Tq。它的任务就是检测总线上的下降沿(从显性到隐性或反之)。每个位时间的开始,节点都会在SS段检查总线电平有没有跳变。如果有,就说明收到了一个同步信号。
传播时间段(PTS)
PTS用来补偿信号在总线上的传播延迟。你想想看,CAN总线最长能到40米,信号在线上跑需要时间。再加上收发器的延迟、隔离器件的延迟,这些都得算进去。
我在一个分布式系统中遇到过一个问题:两个节点距离30米,PTS设得太短,结果发送节点和接收节点的采样点对不上,老是报错。后来我把PTS加长到4个Tq,问题就解决了。
相位缓冲段1和2(PBS1、PBS2)
这两个段是给再同步用的。简单说,当节点检测到总线上的边沿和自己的时钟有偏差时,就通过调整PBS1和PBS2的长度来“追上”总线节奏。
- PBS1:采样点之前,可以延长(加长位时间)
- PBS2:采样点之后,可以缩短(减短位时间)
4.3 硬同步与再同步
同步分两种:硬同步和再同步。我刚开始学的时候老搞混,后来用一句话记住了——硬同步是“从头开始”,再同步是“微调跟上”。
硬同步
硬同步发生在总线从空闲状态(隐性)变成有数据(显性)的那一刻。比如一个节点开始发送SOF(帧起始)位,总线电平从隐性跳变到显性。所有接收节点检测到这个边沿后,会强制把自己的位时间计数器清零,重新从SS段开始计时。
说白了,硬同步就是一次“硬重启”,让所有节点对齐到同一个起点。
再同步
再同步发生在正常通信过程中。每个节点的时钟晶振都有误差,跑着跑着就会偏。再同步就是通过调整PBS1和PBS2的长度,把偏差纠正回来。
- 如果节点时钟比总线慢(采样点来得晚):延长PBS1,把采样点往前推
- 如果节点时钟比总线快(采样点来得早):缩短PBS2,把采样点往后拉
我的经验:再同步不是无限调整的。每个CAN控制器都有一个同步跳转宽度(SJW)参数,它限制了每次再同步最多能调整多少个Tq。SJW一般设为1~4 Tq,设得太大容易引入噪声,设得太小又跟不上偏差。
4.4 位时序参数配置实战
配置位时序,说白了就是定三个参数:波特率、Tq数量、采样点位置。我一般按这个步骤来:
- 确定目标波特率(比如500kbps,位时间=2μs)
- 选择Tq长度(由系统时钟分频得到,比如80MHz时钟,分频8倍,Tq=100ns)
- 计算位时间包含的Tq数(2μs / 100ns = 20 Tq)
- 分配各段长度(SS=1, PTS=3, PBS1=8, PBS2=8,采样点=60%?不对,太靠前了)
嗯,这里要注意。采样点60%肯定不行。我一般会调整PTS和PBS1,让采样点落在85%左右。比如:
| 段 | 长度(Tq) | 说明 |
|---|---|---|
| SS | 1 | 固定 |
| PTS | 3 | 补偿传播延迟 |
| PBS1 | 13 | 采样点前缓冲 |
| PBS2 | 3 | 采样点后缓冲 |
采样点 = (1+3+13) / 20 = 85%。这个配置在大多数场景下都挺稳的。
避坑指南:我曾经在一个项目里,为了省事直接用了某款MCU的默认CAN配置。结果总线长度超过10米后,通信就开始不稳定。后来发现默认的采样点设在70%,对于长总线来说太靠前了。改成85%后,问题解决。
所以我的建议是:不要偷懒用默认值,一定要根据你的总线长度、节点数量、晶振精度去算一遍位时序参数。
4.5 位时序与同步的完整流程
下面这张图把整个流程串起来了。从硬同步开始,到再同步微调,再到采样点判断,一目了然。
4.6 常见问题与排查思路
最后,我总结几个实际项目中容易踩的坑:
- 采样点太靠前(<75%):总线稍长就丢帧,尤其是高波特率场景
- SJW设得太大:容易把噪声当成边沿跳变,导致误同步
- PTS设得太短:传播延迟补偿不够,远距离节点无法同步
- 晶振精度不够:如果晶振误差超过1%,再同步可能跟不上,建议用0.5%以内的晶振
我的调试习惯:遇到CAN通信不稳定,我第一件事就是拿示波器看CAN_H和CAN_L的波形,数一下位时间,算一下实际采样点。很多时候,问题就出在位时序参数上,而不是硬件坏了。