ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

CAN总线采样点计算:从位时间结构到寄存器配置实战

2026/10/3 16:05:05 拓冰建站 浏览量
CAN总线采样点计算:从位时间结构到寄存器配置实战 做过CAN总线开发的人十有八九都遇到过这种情况两边的波特率明明都配成了500kbps怎么组网之后就是偶发错误帧甚至完全不通拿示波器一看波形也挺漂亮高电平低电平都正常可数据就是收不到。很多时候问题就出在一个大多数人没细算的参数上——采样点。这不是玄学CAN总线的每一个位都有明确的时序分段采样点在哪一刻采集电平直接决定了这条总线在真实线束环境下靠不靠谱。这篇东西我就把CAN比特率和采样点计算的底层逻辑一次讲透从位时间结构到具体的寄存器配置再到实际联调时的踩坑记录尽量让你看完就能自己算、自己调。1. 比特率与位时间先把“1bps”这件事掰开看1.1 为什么CAN不能像UART那样只关心波特率用过UART的人都清楚串口通信只需要约定一个波特率收发双方基本就能工作波特率的误差容忍度甚至能到3%左右。但CAN总线不一样它使用的是NRZ编码没有独立的时钟线接收节点要从数据流的跳变沿里不断恢复同步。这意味着每一个数据位内部都被强行拆成了几段每段都有明确的时间长度接收器必须在一个精确的“采样点”上读取电平。很多人最开始会有一个误解比特率是1Mbps那一个位的时间就是1微秒我在中间时刻采样不就好了这种想法在实际工程里很危险。CAN总线的位时间不是简单的一个方波周期它被划分成同步段、传播段、相位缓冲段1、相位缓冲段2每一段都有它的作用。相位缓冲段1和相位缓冲段2之间的边界才是真正的采样时刻。你把采样点设在50%位置和设在80%位置面对同样的总线信号质量结果可能完全不同。这个位时间分段的思路说到底是为了解决两个问题第一抵消信号在总线上的传播延迟第二抵抗各个节点时钟源之间的微小偏差。如果整个位只有一个毫无内部结构的“电平窗口”那接收器一旦遇到累计相位误差就会直接判断错误总线上错误帧就会像烧鞭炮一样冒出来。1.2 位时间的五段结构和它们各自的身份CAN协议标准里一个位由以下几个时间段组成同步段SYNC_SEG固定为1个时间量子Time Quantum简称tq用来同步总线上各个节点的跳变沿。任何节点检测到下降沿时都希望它落在这个段内。传播段PROP_SEG用来补偿信号在总线上的物理传播延迟和收发器延迟。这段越长能支持的总线物理距离就越长但也会牺牲位时间的其他空间。相位缓冲段1PHASE_SEG1用于吸收上升沿相位误差可以理解为“正向吸收余量”采样点就在它结束的位置。相位缓冲段2PHASE_SEG2用于吸收下降沿相位误差可以理解为“采样后的保持余量”。重同步跳转宽度SJW不是一段独立的时间段它表示重同步时相位缓冲段最多能被延长或缩短多少。时间量子tq是整个CAN控制器的最小时间单位由外设时钟分频而来。举例来说如果外设时钟是42MHz而你配置的是4分频那么1tq (4/42MHz) ≈ 95.24ns。整个位时间就是所有段加起来的总tq数除以这个tq对应的时长就得到实际的比特率。硬件上看STM32的bxCAN、GD32的CAN控制器、NXP的FlexCAN基本都遵循这套思想只是寄存器名称和段长度上限不同。理解了tq怎么来、段怎么分配换任何芯片你都能很快上手。提示千万不要直接用“位时间 1/波特率”来算然后试图把采样点刚好对到中间。硬件上的段长度都是整数个tq必须把位时间拆成整数段再考虑采样点落在哪个边界。2. 采样点计算公式与典型配置推导2.1 采样点到底怎么算采样点Sample Point的位置是执行采样动作的那个时间点在整个位时间中的百分比。计算公式非常直接采样点百分比 (SYNC_SEG PROP_SEG PHASE_SEG1) / (SYNC_SEG PROP_SEG PHASE_SEG1 PHASE_SEG2) × 100%用更简单的说法采样点位置 (1 BS1) / (1 BS1 BS2)。这里BS1和BS2分别对应相位缓冲段1和相位缓冲段2的长度单位都是tq而1代表同步段固定占用的1tq。为什么采样点推荐设置在75%到80%而不是50%这个要从CAN的错误处理机制说起。CAN采用的是“在位时间内采样一次然后一直保持到下一位”的策略采样点越靠后留给信号从发送端到接收端传播的建立时间就越多也允许接收端更晚地观察到稳定的总线电平。假设采样点设在50%如果线束较长、收发器延时较大信号在采样时刻可能还没完全稳定到接收端的电平阈值就会采样到一个错误的电平。这就像拍照时快门按得太早画面还没聚焦完成拍出来的就是糊的。行业内常见的推荐配置是采样点75%左右SJW通常取1tq到4tq。ISO 11898-1里虽然没有强制规定具体百分比但从CANopen、J1939这些高层协议的大量设备实现来看大家都往75%到87.5%这个区间靠拢。特别是很多车厂的CAN一致性测试标准甚至要求采样点在80%左右理由是尽可能地远离位边界的跳变区域降低误采样的概率。2.2 手算一个标准500kbps配置我拿一个常见的MCU配置来做例子假设CAN外设时钟是42MHz目标是500kbps比特率采样点尽可能落在80%附近步骤如下。第一步确定分频值和总tq数。42MHz / 500kbps 84这84就是每个位可以分到的时钟周期总数。我们把它拆成总位时间84tq再除以分频值等等这里直接说清楚42MHz下如果1分频tq就是最小周期位时间需要84tq。但绝大多数CAN控制器要求BS1和BS2都有一定范围84tq这么长其实没必要反而让相位误差吸收能力变差。我更倾向于把位时间控制在8到25tq之间这才是主流控制器的舒适区。第二步改分频。42MHz分频2得到21MHz21MHz / 500kbps 42tq。还是略大。分频4得到10.5MHz10.5MHz / 500kbps 21tq。21tq是很好用的一个总位时间配置。第三步分配段长度。21tq总位时间固定同步段1tq剩下20tq分给BS1和BS2。要采样点在80%意味着采样前的总tq数 21 × 0.8 16.8tq取整17tq那么BS1 17 - 1 16tqBS2 21 - 17 4tq。此时实际采样点 (116)/(1164) 17/21 ≈ 80.95%。这个值非常理想。第四步验证SJW。SJW不能大于BS1和BS2中的较小值这里BS2是4tqSJW可以取1tq到4tq。工程上从抗干扰角度推荐SJW稍大一些比如2tq或4tq但如果总线上节点多且时钟精度都好SJW1tq也没问题。把上面的数代进寄存器BS1 16 - 1 15很多芯片的BS1寄存器字段是以0为偏移的实际写入值要减1BS2 4 - 1 3SJW字段写入值 SJW - 1。不同芯片寄存器定义有差异但底层逻辑完全一样。2.3 不同比特率下的配置参考表实际项目里125kbps、250kbps、500kbps、1Mbps都是常见配置。我整理一个代表性配置表时钟源不同会略有出入但段分配思路可以直接参考。目标比特率外设时钟分频值位时间(tq)SYNCBS1BS2SJW采样点1Mbps36MHz2181134477.8%500kbps42MHz4211164480.95%250kbps42MHz8211164480.95%125kbps42MHz16211164480.95%这里有个细节同样一套段分配只要等比例调整分频值就能保持采样点完全不变。实际上同一批节点的CAN配置最简单可靠的策略就是把位时间tq数固定只改分频适配不同波特率。这样采样点完全一致兼容性最好。3. 芯片寄存器配置与工具辅助计算3.1 STM32CubeMX里的自动计算到底靠不靠谱很多人用STM32CubeMX配置CAN直接填一个500kbps软件自动算出BS1、BS2然后用起来也没啥问题。但CubeMX算出来的采样点并不总是最优尤其是在APB1外设时钟不是那么“好除”的时候。比如APB1 36MHz配置500kbps时CubeMX可能会给出BS113、BS22、位时间16tq的分配采样点算出来是87.5%。这是有效配置但要说最稳未必。用工具本身没有错但关键是你得看懂它给的参数意味着什么。我建议拿到一组配置后自己花30秒按采样点公式验算一下确认采样点在75%到80%之间。如果不在这个范围内就要手动调整BS1和BS2别一键生成就直接烧录。CubeMX里手动配置时只需要注意锁定实际波特率不变然后把BS1尽量拉大BS2尽量压缩让采样点落在理想区间。比如位时间固定20tq时BS115、BS24对应的采样点是80%而BS113、BS26对应的采样点是70%。两个都能跑到同样的比特率但抗干扰能力差别很大。3.2 Linux SocketCAN的bit-timing计算思路Linux下做CAN开发很多人直接使用ip link set can0 type can bitrate 500000这样的命令由内核自动计算位时序参数。自动计算的策略其实也遵守采样点优先的原则通常会把采样点定位在75%到80%区间具体算法可以在内核源码的net/can/bittiming.c里看到。但是如果你需要配合特殊硬件或者非标准线束长度建议还是手动指定。SocketCAN支持下面这种完整参数配置ip link set can0 type can \ tq125 \ prop-seg6 \ phase-seg17 \ phase-seg22 \ sjw1 \ nsamples1 \ restart-ms100注意这里的tq单位是纳秒。上面的配置相当于位时间 (1672)tq 16tq采样点 (167)/16 87.5%。Busybox、iproute2都支持这样手动传参具体参数名可能随版本略有不同用ip link help can可以查看。3.3 在代码里落地一段典型的CAN初始化代码以STM32 HAL库为例初始化参数的结构体如下CAN_HandleTypeDef hcan; hcan.Instance CAN1; hcan.Init.ClockDivider CAN_CLOCKDIV1_DIV4; // 分频4 hcan.Init.SyncJumpWidth CAN_SJW_4TQ; // SJW 4tq hcan.Init.TimeSeg1 CAN_BS1_16TQ; // BS1 16tq hcan.Init.TimeSeg2 CAN_BS2_4TQ; // BS2 4tq hcan.Init.TimeTriggeredCommunicationMode DISABLE; hcan.Init.AutoBusOff ENABLE; hcan.Init.AutoWakeUp DISABLE; hcan.Init.AutoRetransmission ENABLE; hcan.Init.ReceiveFifoLocked DISABLE; hcan.Init.TransmitFifoPriority ENABLE;这份配置对应的实际采样点 (116)/(1164) ≈ 80.95%和外设时钟42MHz分频4结合正好得到500kbps。配合前面的手算推导你应该能看明白每一个字段的来历而不是死记硬背。提示如果多个节点使用不同的MCU务必保证采样点接近而不是比特率完全相等。比特率差0.5%以内通常都能协商但采样点如果差出20%总线边缘节点的误码率会明显上升。4. 常见问题排查与避坑实录4.1 为什么所有参数看着没问题总线还是大量错误帧这是我在现场排查过很多次的典型情况。参数是从某个例程里抄来的波特率也对总线波形也能看到但就是不停出现错误帧。后来一帧一帧抓波形分析发现每个位的电平在采样点附近有抖动推高示波器波形展开后能看到明显的振铃。出现这种问题第一反应别改采样点先查硬件。终端电阻焊了没有、阻值是不是60Ω、CAN_H和CAN_L有没有接反、总线有没有形成星型拓扑这些都是错误帧高发的原因。只有在物理层干净的前提下采样点调整才有意义。否则你调了半天采样点最后发现是终端电阻虚焊前功尽弃。4.2 长线束和短线束对采样点的影响总线长度差异直接影响信号传播延迟。CAN信号在双绞线上的传播速度大约是5ns/m200米总线意味着单程1微秒延迟一来一回2微秒。如果此时位时间本身只有2微秒500kbps那传播段就要预留出足够的空间否则发送节点发出的数据在最远接收节点那里还没传到位采样时刻就已经到了。有一条经验法则总线越长传播段占比就要越大采样点也要越靠后。如果你设计的是车内短距离CAN网络几米线束采样点75%就够了如果是工业现场或者跨设备的CAN总线几十上百米建议采样点往80%到85%甚至87.5%靠。当然单纯靠调采样点并不能无限延长通信距离最终极限还会受限于收发器驱动能力。4.3 不同MCU之间的CAN节点兼容问题我见过最隐蔽的一个兼容性问题节点A用的芯片BS1最大只能到16tq节点B用的芯片BS1最大能到32tq两个工程师各自按自动计算工具生成了500kbps配置结果A的采样点是75%B的采样点是83%。单独测试都通连在一起后B发数据A能收到A发数据B偶发收不到。原因就是A发的数据位在B的采样点附近刚好处于信号边沿附近的振铃区域B采到的电平不稳定。解决方法是统一通信矩阵里的CAN配置规范不光约定波特率还要约定位时间结构和采样点范围。很多OEM的CAN通信矩阵文档里甚至直接写出每个ECU的BS1、BS2和采样点要求原因就在这里。4.4 采样点设太早或太晚分别会出现什么症状很多工程师调配置时只知道“差不多就行”但采样点的位置偏差会表现出完全不同的失效模式采样点太靠前比如60%以下信号还没完全稳定容易在总线负载率高的时候偶发采样错误。症状多为偶发性错误帧总线使用率一提高就爆发。采样点太靠后比如90%以上留给相位缓冲段2的空间太小接收节点对下一个位边沿的容忍度变低同样容易产生位填充错误尤其是在温度漂移导致晶振偏差时更明显。如果设备偶发错误帧但波形看着很好可以先尝试把采样点从当前值向75%到80%挪一下很多问题能直接消失。4.5 常见问题速查表现象可能原因处理方向完全不通没有任何波形波特率不匹配、芯片未进入正常模式确认两端实际位时间检查初始化是否完成偶发错误帧总线使用率越高越严重采样点偏早、总线物理层干扰调整采样点向80%靠近同时检查端接电阻单个节点收发异常其他节点正常该节点tq配置与其他节点采样点差异过大统一位时间结构用示波器量该节点波形一上电就bus-off波特率配置错误或时钟源偏差太大万用表或示波器测量实际位时间核对分频高速率能通低速率不通位时间tq数太少导致SJW能力不足增加位时间tq数并调整BS1、BS2比例5. 为什么CAN FD的采样点要求更严苛CAN FD是CAN的升级协议数据段最高支持8Mbps甚至更高所以在数据段的位时间更短。采样点计算的核心逻辑不变但有个额外约束仲裁段和数据段往往使用不同的位时序配置控制器需要在这两种位时序之间切换。CAN FD仲裁段的采样点通常和经典CAN一致75%到80%而数据段由于速率高、位时间短对信号建立时间更敏感通常采样点会设置在70%到75%之间甚至有些芯片默认给到65%左右。原因在于CAN FD数据段的位时间可能只有几十纳秒过长的传播段会压缩分段空间所以适当降低采样点比例换取更大的相位缓冲段2余量用来容忍下一位的边沿到达时间波动。开发CAN FD节点时如果你只沿用经典CAN那套“采样点越靠后越好”的思路数据段大概率会失败。正确做法是分别计算仲裁段和数据段的位时序仲裁段保证传统兼容性数据段按高速信号专门优化。另外CAN FD的位速率切换BRS对接收端的要求更高发射节点在BRS位之后会切换到数据段速率接收节点必须在此之前重新完成同步。如果SJW配置太小切换沿到来时同步调整不够就会出现位错误。这也是为什么CAN FD要求SJW至少要有1到2tq余量。6. 验证采样点配置的几种实操方法6.1 用示波器直接量位时间最直接的验证方式是把示波器探头接到CAN_H和CAN_L之间用差分方式抓总线波形然后展开单个位来看。测量结果是确认实际位时间的最可靠手段比如500kbps下一个显性位宽度应该是2微秒如果量出来是2.05微秒说明实际波特率偏差了2.5%很多CAN控制器就已经接近容忍极限了。测位宽度时要注意CAN总线上的隐性电平在没有显性位驱动时是悬空的示波器看到的波形可能和理想波形有差距。正确的测量对象是连续两个显性位之间的时间间隔或者用示波器的解码功能直接看波特率测量结果。6.2 通过回环测试与总线占用率判断采样点裕量在硬件基本正常的情况下可以做一次压力验证把总线负载率拉到80%以上连续跑几个小时观察错误帧计数器是否稳定。如果错误计数缓慢增长大概率是采样点裕量不足而不是偶发干扰。比如你可以在STM32里读取CAN_ESR寄存器的REC和TEC计数任何非零增长都值得警惕。更高级的做法是故意在总线上注入一个偏置电阻或者加长一段线缆人为制造信号劣化然后看节点是否还能正常工作。如果采样点配置合理即使波形已经有一点变形错误帧也不会明显增加如果采样点本来就贴着信号边沿稍微加干扰就直接掉线。6.3 多节点一致性的批量验证多节点组网时不要只测试两个节点点对点通信。把所有节点都挂上总线以最高负载率持续通信观察每个节点的错误计数。错误计数明显偏高的节点通常是采样点配置与其他节点不一致。我做过多节点项目后养成了一个习惯把每个节点的CAN配置参数导出来画成一张表格对比BS1、BS2、SJW和实际采样点。只要有一个节点采样点差出5%以上我就会去查硬件版本和软件版本而不是等到整车联调时再找问题。提示CAN控制器通常有环回模式Loopback Mode和静默模式Silent Mode调试阶段多用环回模式验证软件收发逻辑但环回模式完全不经过物理层验证不了采样点问题。采样点问题必须在正常模式下通过真实总线通信来验证。写在最后我在这个领域踩过的坑不算少最大的体会是CAN配置这件事看上去就是填几个寄存器实际上每填一个数字都应该有依据。位时间一共就那么20来个tqBS1多一点采样点就靠后BS2多一点容错就好一点SJW有上下限采样点却不是越靠某个固定值越好一切取决于你的总线长度、波特率、收发器性能和时钟源精度。把采样点计算公式刻在脑子里看到任意一组配置花30秒钟心算一下比例能帮你避开一大半偶发通信故障。做CAN总线开发慢就是快先算清楚再调硬件比反复试配置要高效得多。