4. CAN总线位时序与同步:位时间组成、同步段与重同步、采样点设置与波特率计算

各位同学,咱们今天聊点硬核的——CAN总线的位时序与同步。说实话,很多工程师调CAN通信,遇到通信不稳定,第一反应就是换线、加终端电阻,很少有人会去动位时序参数。但我个人经验是,八成以上的偶发通信故障,根源都在这里。

你想想看,CAN总线上的节点,各自有各自的晶振,频率不可能完全一样。今天25℃,明天85℃,晶振漂移个几十ppm很正常。如果没有一套精密的同步机制,大家各说各话,总线早就乱套了。所以,理解位时序,是搞定CAN通信的必修课。

4.1 位时间的组成:一个bit是怎么切分的?

CAN总线的一个数据位,并不是简单的一个方波。它被分成了四个段,每个段都有特定的功能。我习惯把这四个段比作一个“时间窗口”,窗口里每个位置都有活干。

段名称 缩写 功能描述 我常设的值
同步段 SS 用于总线同步,检测下降沿 固定1 Tq
传播时间段 PTS 补偿物理延迟(线缆、收发器) 1~8 Tq
相位缓冲段1 PBS1 采样点前调整,用于重同步 1~8 Tq
相位缓冲段2 PBS2 采样点后调整,用于重同步 1~8 Tq

这里有个关键概念——时间量子(Tq)。它是CAN控制器的最小时间单位,由系统时钟分频得到。一个位时间 = SS + PTS + PBS1 + PBS2,单位都是Tq。

核心公式:

位时间 (Tbit) = (SYNC_SEG + PROP_SEG + PHASE_SEG1 + PHASE_SEG2) × Tq

波特率 = 1 / Tbit

举个例子,假设系统时钟16MHz,预分频器设为8,那么Tq = 8 / 16MHz = 500ns。如果位时间设为16个Tq,那么一个位就是8μs,波特率就是125kbps。

4.2 同步段与重同步:为什么总线不会乱?

同步段(SS)是每个位的起点。CAN协议规定,总线上出现下降沿时,所有节点都要在SS段内检测到这个边沿。如果某个节点的时钟偏快或偏慢,边沿就会落在SS之外,这时候就需要重同步了。

重同步分为两种:

  • 硬同步:发生在总线从空闲到开始传输的瞬间(SOF位)。所有节点强制将当前位时间对齐到SS段。
  • 重同步:发生在数据帧传输过程中。如果检测到边沿偏移,控制器会自动调整PBS1或PBS2的长度。

我曾经在一个项目里,用了两个不同品牌的CAN收发器,一个晶振精度20ppm,另一个50ppm。刚开始没注意同步参数,结果跑高速500kbps时,偶尔丢帧。后来把SJW(同步跳转宽度)从1Tq改到2Tq,问题就解决了。说白了,SJW就是允许每次重同步调整的最大Tq数,设大一点,容错能力就强一些。

避坑指南:我曾经遇到过一位同事,把SJW设得特别大(4Tq),以为这样更稳定。结果适得其反,因为SJW过大,会导致采样点位置剧烈抖动,反而增加了误码率。SJW一般设为1~2Tq就够用了。

4.3 采样点设置:什么时候读总线最准?

采样点,就是CAN控制器读取总线电平的那个时刻。它位于PBS1和PBS2之间。采样点设置得好不好,直接决定了通信的可靠性。

我个人的经验是:采样点尽量靠后,但不要太靠后。为什么?

  • 采样点太靠前(比如50%),总线信号还没稳定,容易读到毛刺。
  • 采样点太靠后(比如90%),留给PBS2的时间太少,重同步的调整空间不够。

行业内有个经验值:采样点设置在75%~87.5%之间比较理想。对于125kbps以下的低速应用,可以适当提前;对于500kbps以上的高速应用,建议尽量靠后。

采样点计算公式:

采样点位置 = (SS + PTS + PBS1) / (SS + PTS + PBS1 + PBS2) × 100%

举个例子:SS=1, PTS=3, PBS1=4, PBS2=4,那么采样点 = (1+3+4)/(1+3+4+4) = 8/12 ≈ 66.7%。这个值偏低,建议调整。

4.4 波特率计算:手把手教你配寄存器

好了,理论讲完了,咱们来点实际的。假设你手头有个项目,要求CAN通信速率为250kbps,系统时钟为8MHz。怎么配?

第一步:确定Tq数量。CAN协议要求位时间至少由8个Tq组成,推荐16~25个Tq。咱们选16个Tq。

第二步:计算Tq长度。Tbit = 1/250kbps = 4μs。Tq = 4μs / 16 = 250ns。

第三步:计算预分频值。预分频 = Tq × 系统时钟 = 250ns × 8MHz = 2。所以预分频器设为2。

第四步:分配四个段。SS固定为1Tq。PTS设为3Tq(补偿物理延迟)。剩下12个Tq分给PBS1和PBS2,我习惯PBS1=6, PBS2=6。这样采样点 = (1+3+6)/16 = 62.5%。嗯,有点低,咱们调整一下:PBS1=7, PBS2=5,采样点 = (1+3+7)/16 = 68.75%。还是偏低。再调:PBS1=8, PBS2=4,采样点 = (1+3+8)/16 = 75%。这个值可以了。

// 以STM32的bxCAN为例,配置250kbps
// 系统时钟8MHz,预分频2,Tq=250ns
// 位时间16Tq,SS=1, PTS=3, PBS1=8, PBS2=4
// 采样点75%

CAN_InitTypeDef CAN_InitStruct;
CAN_InitStruct.CAN_Prescaler = 2;          // 预分频
CAN_InitStruct.CAN_Mode = CAN_Mode_Normal;
CAN_InitStruct.CAN_SJW = CAN_SJW_1tq;      // 同步跳转宽度1Tq
CAN_InitStruct.CAN_BS1 = CAN_BS1_8tq;      // PBS1 = 8Tq
CAN_InitStruct.CAN_BS2 = CAN_BS2_4tq;      // PBS2 = 4Tq
CAN_InitStruct.CAN_TTCM = DISABLE;
CAN_InitStruct.CAN_ABOM = ENABLE;
CAN_InitStruct.CAN_AWUM = DISABLE;
CAN_InitStruct.CAN_NART = DISABLE;
CAN_InitStruct.CAN_RFLM = DISABLE;
CAN_InitStruct.CAN_TXFP = DISABLE;
CAN_Init(CAN1, &CAN_InitStruct);

常见波特率配置速查表(系统时钟8MHz):

目标波特率 预分频 Tq (ns) 位时间 (Tq) SS PTS PBS1 PBS2 采样点
1 Mbps 1 125 8 1 2 3 2 75%
500 kbps 1 125 16 1 3 8 4 75%
250 kbps 2 250 16 1 3 8 4 75%
125 kbps 4 500 16 1 3 8 4 75%

4.5 位时序与同步知识图谱

下面这张图,把位时序的组成、同步机制和采样点的关系串起来了。建议你保存下来,调试的时候对照着看。

CAN总线位时序与同步知识图谱 一个位时间 (Tbit) = SS + PTS + PBS1 + PBS2 由若干个时间量子 (Tq) 组成,Tq = 系统时钟 / 预分频 SS (1 Tq) PTS (1~8 Tq) PBS1 (1~8 Tq) PBS2 (1~8 Tq) 采样点 硬同步 发生在SOF位,强制对齐SS段 所有节点同步到下降沿 重同步 传输过程中调整PBS1/PBS2 SJW控制每次调整的最大Tq数 波特率计算流程 ① 确定目标波特率 → ② 选择位时间Tq数 (8~25) → ③ 计算Tq长度 ④ 计算预分频值 → ⑤ 分配SS/PTS/PBS1/PBS2 → ⑥ 验证采样点 (75%~87.5%) ⑦ 配置SJW (1~2 Tq) → ⑧ 实际测试验证

4.6 实际调试中的几个坑

最后,分享几个我在项目中踩过的坑,希望能帮你少走弯路。

  • 坑一:采样点太靠前。有一次调试500kbps,采样点设在60%,结果总线长度超过10米就开始丢帧。后来把采样点改到80%,同样线长,通信稳如老狗。
  • 坑二:SJW设得太大。前面说过,SJW不是越大越好。我见过有人设到4Tq,结果总线抖动厉害,误码率反而上升。
  • 坑三:忽略物理延迟。PTS段是用来补偿线缆和收发器延迟的。如果总线很长(比如50米以上),PTS至少要设到5~6Tq,否则采样点会读到错误电平。
  • 坑四:不同节点配置不一致。同一个总线上的所有节点,位时序参数必须一致。我曾经遇到过,一个节点用16Tq,另一个用20Tq,结果通信时好时坏。查了半天才发现是配置没统一。

我的调试习惯:先用示波器抓一下CAN_H和CAN_L的波形,看看位时间是否准确。然后通过CAN分析仪发送特定ID的报文,观察是否有错误帧。如果错误帧比例超过1%,优先检查位时序配置。

好了,这一章的内容就到这里。位时序和同步是CAN通信的底层基础,理解透了,后面讲错误处理、总线仲裁的时候,你会觉得豁然开朗。记住一句话:采样点决定通信质量,SJW决定容错能力。下次调CAN的时候,不妨先看看这两个参数。