在学习笔记篇---CAN通信(一)的时候,主要讲了什么是CAN,以及CAN总线的硬件连接和帧格式规范,本篇主要讲CAN总线的位同步、仲裁和错误处理机制。
一、位同步:解决 “时钟不同步” 的通信关键
1. 为什么需要位同步?
CAN 总线有个特点:没有专门的时钟线。总线上的所有设备(比如单片机、传感器),全靠 “约定好的波特率” 来判断 “一个数据位该传多久”。
发送方:按照约定波特率,每隔固定时间发一个数据位(比如约定波特率 200kbps,就每隔 5μs 发一位);
接收方:同样按这个波特率,每隔固定时间 “采样” 一次总线电平,读取数据位。
理想情况下,接收方的采样时间会刚好落在数据位的 “正中间”—— 这时候读出来的数据最准确。但实际场景中,两个问题会导致 “不同步”:
接收方一开始的采样点就没对准数据位中心;
设备之间的时钟总会有微小误差(比如甲设备时钟快一点,乙设备慢一点),误差越积越多,采样点会慢慢偏离数据位中心。
一旦采样点偏离,接收方就可能把 “0” 读成 “1”,或把 “1” 读成 “0”—— 这时候,位同步机制就登场了,它的核心作用就是:实时校准接收方的采样时间,让采样点始终对准数据位中心,保证数据传输准确。
2. 位时序:把 “一个数据位” 拆成 “可调整的小片段”
为了灵活校准采样点,CAN 总线把 “一个数据位的总时长” 拆成了 4 个连续的小片段,每个片段由若干个 “最小时间单位(Tq)” 组成(Tq 是 Time Quantum 的缩写,相当于 CAN 总线的 “时间最小刻度”,由芯片内部时钟分频得到,比如 0.5μs/Tq)。
这 4 个片段各司其职,分工明确:
| | |
| | 用于 “对齐时钟” 的基准段,长度固定为 1Tq。总线上的数据跳变(比如 0 变 1、1 变 0)最好发生在这里 |
| | 补偿信号在总线中的传输延迟(比如信号从发送方传到接收方需要时间),长度可设(通常 1-8Tq) |
| | 用于 “加长调整” 的缓冲段,长度可设(通常 1-8Tq) |
| | 用于 “缩短调整” 的缓冲段,长度可设(通常 1-8Tq),采样点就位于 PBS1 和 PBS2 的交界处 |
简单说:一个数据位的总时长 = SS + PTS + PBS1 + PBS2,所有片段的 Tq 加起来,就是这个数据位的 “总时间刻度”。
3. 硬同步:帧开头的 “统一看齐”
硬同步是 “一次性对齐”—— 只在每帧数据的开头生效,目的是让所有设备的时钟 “从零开始同步”。
具体过程:
总线上某一个设备(发送方)率先发起通信,发送 “帧起始位(SOF)”——SOF 是一个从 “高电平” 变 “低电平” 的下降沿,相当于喊了一声 “大家注意,要开始传数据了!”;
总线上其他所有设备(接收方)一检测到这个 SOF 下降沿,就会立刻把自己的 “位时序计时器” 归零,重新从 “同步段(SS)” 开始计时;
这样一来,所有接收方的时钟就和发送方的时钟 “对齐了起点”—— 如果设备之间没有时钟误差,后续每个数据位的采样点都会刚好落在中心。
关键点:硬同步只有 “SOF 下降沿” 这一次机会,后续再遇到跳变沿,就用不上硬同步了。
4. 再同步:过程中的 “动态校准”
就算硬同步对齐了起点,设备时钟的微小误差还是会慢慢积累(比如发送方时钟快,接收方时钟慢),导致后续数据位的跳变沿 “跑出同步段(SS)”,采样点开始偏离中心。这时候,再同步机制就会进行 “动态微调”。
具体过程:
接收方会监测每个数据位的跳变沿(SOF 之后的所有跳变沿都算);
一旦发现跳变沿不在 SS 段,就根据 “再同步补偿宽度(SJW)” 进行调整 —— 要么加长 PBS1 段(让采样点往后移),要么缩短 PBS2 段(让采样点往前移);
调整的幅度不能超过 SJW 的设定值(通常 SJW=1-4Tq),避免调整过度导致新的同步问题。
简单理解:再同步就像跑步时的 “微调步伐”—— 硬同步是起跑时大家对齐起跑线,再同步是跑步过程中,有人快了就放慢一点,有人慢了就加快一点,始终保持队伍整齐。
5. 波特率计算:怎么算出 “约定的传输速度”?
波特率是 CAN 总线的 “传输速度”(比如 200kbps、500kbps),核心公式很简单:波特率 = 1 / 一个数据位的总时长而 “一个数据位的总时长”= (SS 的 Tq 数 + PTS 的 Tq 数 + PBS1 的 Tq 数 + PBS2 的 Tq 数)× Tq 的实际时间
举个具体例子(和你原文一致,补充细节说明):
设定各段 Tq 数:SS=1Tq、PTS=3Tq、PBS1=3Tq、PBS2=3Tq;
已知 Tq=0.5μs(由芯片时钟分频得到,比如芯片时钟 16MHz,分频 32 后就是 0.5μs/Tq);
一个数据位的总时长 = (1+3+3+3)× 0.5μs = 10×0.5μs = 5μs;
波特率 = 1 / 5μs = 200kbps(注:1 秒 = 10^6 微秒,1/5μs=200000 次 / 秒 = 200kbps)。
再补充一个常见场景:如果 Tq=0.25μs,各段 Tq 数不变,总时长 = 10×0.25μs=2.5μs,波特率就是 400kbps—— 可见,调整 Tq 的实际时间或各段 Tq 数,就能改变波特率。
二、仲裁机制:总线的 “有序抢答规则”
上一部分我们搞懂了位同步 —— 解决的是 “设备之间时钟不同步,数据读不准” 的问题。这一部分,我们聚焦另一个核心问题:CAN 总线就像 “一条公共电话线”,所有设备都连在上面,如果多个设备同时想发数据,怎么避免 “说话打架”? 这就需要 CAN 总线的 “交通规则”——仲裁机制。
1. 为什么必须有仲裁?—— 避免 “同时说话” 的混乱
CAN 总线的核心特点是 “共享总线”:只用一对差分信号线,所有设备都挂在这对线上。这就像一群人共用一个对讲机,要是两个人同时开口,声音混在一起,谁都听不清 ——CAN 总线也是如此,同一时间只能有一个设备 “说话”(发数据)。
如果没有仲裁机制,多个设备同时发数据,会导致:
数据混乱:不同设备的信号叠加,接收方根本无法识别有效数据;
资源浪费:传输无效数据,浪费总线带宽(传输时间);
硬件风险:极端情况下,信号冲突可能损坏设备接口。
所以,仲裁机制的核心目标是:制定一套 “公平又高效” 的规则,让多个设备有序使用总线,避免冲突,同时优先满足高优先级设备的需求。
2. 仲裁的核心逻辑:先看 “总线闲不闲”,再比 “谁的优先级高”
CAN 仲裁分两步走:第一步判断总线是否可用,第二步若多个设备同时抢总线,就通过 “比拼” 决定谁先用 —— 整个过程不会破坏已发送的有效数据(这就是非破坏性仲裁的关键)。
(1)第一步:判断总线是否空闲 ——“没人用我再说话”
CAN 总线有个总线空闲标准:当总线上出现连续 11 个 “隐性电平”(可以理解为 “安静状态”,对应逻辑 1)时,就说明总线没人用了。
只有确认总线空闲,设备才能发起数据帧(发数据)或遥控帧(要数据);
一旦有设备开始发数据,总线就会进入 “活跃状态”—— 此时总线上会频繁出现 “显性电平”(可以理解为 “说话状态”,对应逻辑 0),不可能再出现连续 11 个隐性电平,其他设备看到后就知道 “总线有人用了”,会乖乖排队等空闲;
补充:如果总线活跃时,某设备发现严重错误(比如数据传错),可以发送错误帧或过载帧强行打断当前传输 —— 这是特殊情况,目的是避免错误数据继续传播。
(2)第二步:同时抢总线?—— 比 ID,小 ID 赢(非破坏性仲裁核心)
如果多个设备的发送需求 “撞车”(比如同时检测到总线空闲,一起开始发数据),就进入 “仲裁比拼” 环节。核心规则是:比 ID 号,ID 号越小,优先级越高,最终获得总线控制权。
这个比拼能实现 “非破坏性”(不会浪费已发送的有效数据),全靠两个关键设计:
① 线与特性:“只要有一个人说话,其他人再安静也没用”
这是 CAN 总线的硬件核心特性,简单说:
总线上只要有一个设备发送 “显性电平 0”,整个总线就呈现 “0”(相当于 “有人在说话”);
只有所有设备都发送 “隐性电平 1”,总线才呈现 “1”(相当于 “所有人都安静”)。
类比成对讲机:哪怕你想安静(发 1),但只要有别人在说话(发 0),你听到的就是别人的声音(总线状态为 0)。
② 回读机制:“发完一个字,立刻听一下自己说的对不对”
每个设备发送一个数据位后,都会立刻回读总线当前的电平—— 确认自己发的信号有没有被总线正确呈现。结合线与特性,会出现两种情况:
若设备发的是 “0”(显性):不管其他设备发什么,总线都一定是 0,回读结果必然和发送一致,设备会继续发下一位;
若设备发的是 “1”(隐性):如果回读发现总线是 0,就说明有其他设备发了 0(优先级更高),自己的 1 被 “覆盖” 了 —— 此时设备会立刻知道 “我输了”,马上停止发送,转而变成接收状态,乖乖听赢的设备传数据。
③ 比拼过程:逐位 PK,输了就 “闭嘴”
仲裁时,所有设备会从 ID 号的最高位开始,逐位发送 + 回读,一旦出现差异,输的设备立刻退出,全程不破坏已发送的正确数据。
举个通俗例子(用 3 位 ID 简化,实际标准 ID 是 11 位,扩展 ID 是 29 位):
设备 A:ID=001(二进制,优先级中等)
设备 B:ID=000(二进制,优先级最高)
设备 C:ID=010(二进制,优先级最低)
三个设备同时检测到总线空闲,一起开始发 ID:
第 1 位(最高位):A、B、C 都发 0 → 回读都是 0,所有人继续;
第 2 位:A、B 都发 0,C 发 1 → C 回读发现总线是 0(被 A、B 的 0 覆盖),立刻知道自己输了,停止发送,转成接收;
第 3 位:A 发 1,B 发 0 → A 回读发现总线是 0(被 B 的 0 覆盖),知道自己输了,停止发送,转成接收;
最终:只有 B(ID=000)继续发送完整数据,A 和 C 安静接收 —— 整个过程中,B 已经发送的 ID 位都是正确的,没有被破坏,这就是非破坏性仲裁的优势。
3. 补充规则:特殊情况的优先级判定
除了 “ID 越小优先级越高”,还有两个特殊仲裁规则,确保仲裁更合理:
(1)数据帧 vs 遥控帧:数据帧优先级更高
如果两个设备的 ID 号完全一样,一个发 “数据帧”(给别人传数据),一个发 “遥控帧”(向别人要数据)——数据帧会赢。
原因很简单:“发数据” 通常是更紧急的需求(比如传感器检测到故障,立刻发报警数据),而 “要数据” 可以稍等,避免 “要数据的设备” 打断 “发关键数据的设备”。
(2)标准 ID(11 位) vs 扩展 ID(29 位):标准 ID 优先级更高
如果标准 ID(11 位)和扩展 ID(29 位)的 “高 11 位” 完全一样,标准 ID 设备会赢—— 这靠扩展帧里的SRR 位(替代远程请求位)保证:
标准帧的对应位置(IDE 位之后)发送的是 “显性电平 0”;
扩展帧的 SRR 位必须固定发送 “隐性电平 1”;
比拼到这一位时,扩展帧发 1 但回读是 0(被标准帧的 0 覆盖),会立刻退出仲裁,确保标准帧优先。
4. 仲裁的核心优势:高效、有序、无浪费
总结一下 CAN 仲裁机制的核心好处:
无需 “中央控制器”:不用专门的设备分配总线资源,所有设备按规则自行比拼,降低系统复杂度;
非破坏性:就算同时抢总线,也不会破坏已发送的有效数据,避免带宽浪费;
优先级明确:通过 ID 设定优先级,紧急消息(小 ID)能优先传输(比如汽车上的刹车信号 ID 比空调信号 ID 小,确保刹车信号优先);
自动排队:仲裁失利的设备会自动等待下一次总线空闲,重新尝试发送,无需人工干预。
三、错误处理机制:CAN 总线的 “自动纠错与故障隔离系统”
解决了 “时钟不同步” 的位同步问题、“谁先说话” 的仲裁问题后,CAN 通信还需要应对最后一个关键挑战:数据传错了怎么办? 这就需要 CAN 总线的 “纠错保安”——错误处理机制。它能自动检测传输错误、标记错误状态,甚至隔离故障设备,确保总线整体通信稳定。
1. 核心目标:及时发现错误、减少错误影响、隔离故障设备
CAN 总线工作在工业控制、汽车电子等复杂环境中,难免受到电磁干扰、线路接触不良等影响,导致数据传输错误。错误处理机制的核心作用是:
快速检测:在数据传输过程中实时监控,第一时间发现错误;
主动告警:通过发送 “错误帧” 告知总线上其他设备 “当前数据有误”;
状态管理:根据错误发生频率,调整设备自身的通信状态(避免故障设备持续干扰总线);
故障隔离:若设备频繁出错,自动将其 “隔离”(总线关闭状态),确保其他设备正常通信。
2. 3 种设备错误状态:从 “正常工作” 到 “暂停通信”
每个 CAN 设备都有一套 “错误状态管理逻辑”,根据错误发生情况,设备会处于以下 3 种状态之一,状态由两个核心计数器决定(后文详解):
| | |
|---|
| 主动错误状态(Active Error) | | 正常参与通信;检测到错误时,发送主动错误帧(强告警,强制中断错误数据传输) |
| 被动错误状态(Passive Error) | 设备频繁出错(错误计数器值偏高),处于 “警告” 状态 | 正常参与通信;检测到错误时,仅发送被动错误帧(弱告警,不强制中断,需等待总线空闲后再重发) |
| 总线关闭状态(Bus Off) | 设备严重故障(错误计数器值超标),已失去正常通信能力 | 禁止参与任何通信(发送、接收均被暂停),需手动或自动复位后才能恢复 |
通俗类比:
主动错误状态 = 健康的员工(偶尔犯错,及时上报并纠正);
被动错误状态 = 频繁出错的员工(被警告,仍可工作但需低调,不影响他人);
总线关闭状态 = 严重失职的员工(被暂停工作,隔离处理)。
3. 核心工具:错误计数器(TEC + REC)—— 状态的 “判定标尺”
设备的错误状态由两个错误计数器决定,计数器的增减严格遵循 CAN 协议规则:
TEC(Transmit Error Counter):发送错误计数器
记录设备 “发送数据时” 发生的错误次数(比如发送后检测到数据异常);
REC(Receive Error Counter):接收错误计数器
记录设备 “接收数据时” 发生的错误次数(比如接收的数据校验失败)。
计数器核心规则(关键!):
计数器增加场景:
设备发送数据时检测到错误:TEC += 8;
设备接收数据时检测到错误:REC += 1(若当前是被动错误状态,REC += 2);
设备发送主动错误帧后,又检测到总线错误:TEC += 8;
计数器减少场景:
设备成功发送一帧完整数据(无错误):TEC -= 1(TEC≥0 时);
设备成功接收一帧完整数据(无错误):REC -= 1(REC≥0 时);
状态切换条件:
主动错误状态:TEC < 128且REC < 128;
被动错误状态:128 ≤ TEC ≤ 255或128 ≤ REC ≤ 255;
总线关闭状态:TEC > 255(此时设备停止所有通信)。
4. 5 种核心错误类型:CAN 总线能检测的 “所有错误场景”
CAN 协议定义了5 种必须检测的错误类型,覆盖从 “单 bit 错误” 到 “格式错误” 的所有常见问题,每种错误都有明确的检测逻辑:
(1)位错误(Bit Error)——“发送和接收的不一致”
触发条件:设备发送一个数据位后,通过 “回读机制” 读取总线电平,发现 “发送的电平” 与 “总线实际电平” 不一致(特殊情况除外:仲裁段的隐性位、应答段的显性位不判定为位错误);
通俗解释:你说 “1”(发隐性电平),但总线实际是 “0”(被其他设备的显性电平覆盖),且这种情况不在允许的特殊场景内,就判定为位错误;
检测方:发送数据的设备(只有发送方会回读自己的发送位,所以由发送方检测)。
(2)填充错误(Stuff Error)——“违反了‘位填充’规则”
触发条件:CAN 总线为了同步和抗干扰,有 “位填充规则”—— 连续发送 5 个相同电平(比如 5 个 0 或 5 个 1)后,必须插入 1 个相反电平(第 6 位为反相);若设备检测到连续 6 个及以上相同电平,就判定为填充错误;
通俗解释:约定 “最多连续说 5 个相同的字”,结果有人连续说 6 个,就违反规则,判定为错误;
检测方:所有接收设备(发送方也会监控自己的发送数据,若违反规则也会检测到)。
(3)CRC 错误(CRC Error)——“数据校验失败”
触发条件:发送方会在数据帧 / 遥控帧的 “CRC 段”,发送一个基于数据内容计算的 “CRC 校验码”;接收方接收完数据后,会用同样的算法计算 CRC 码,若与接收到的 CRC 校验码不一致,就判定为 CRC 错误;
通俗解释:你给朋友发消息时,在末尾加了 “校验码:123”(基于消息内容计算),朋友收到后计算出的校验码是 “456”,就知道消息传错了;
检测方:所有接收设备。
(4)格式错误(Form Error)——“数据帧格式不符合规则”
触发条件:CAN 帧的固定格式位(比如帧起始 SOF、仲裁段 IDE 位、CRC 界定符、ACK 界定符、帧结束 EOF 等)有固定的电平要求(比如 EOF 必须是 7 个隐性电平);若设备检测到这些固定格式位的电平不符合协议规定,就判定为格式错误;
通俗解释:约定 “消息开头必须是‘您好’”,结果有人开头是 “喂”,就违反格式规则;
检测方:所有接收设备(发送方也会自检)。
(5)应答错误(Acknowledgment Error)——“发送的数据没人确认”
触发条件:发送方发送完数据后,会在 “ACK 段” 发送一个隐性电平(1),并等待接收方回应;接收方成功接收数据后,会在 ACK 段发送一个显性电平(0)作为 “确认信号”;若发送方在 ACK 段回读发现总线仍是隐性电平(1),说明没有任何接收方确认收到数据,判定为应答错误;
通俗解释:你喊 “有人收到消息吗?”(发隐性电平),但没人回应 “收到”(显性电平),就知道消息没被接收;
检测方:发送数据的设备。
5. 错误帧:错误发生时的 “告警信号”
当设备检测到上述任何一种错误时,会立刻发送错误帧,告知总线上其他设备 “当前数据有误”,错误帧分为两种,对应设备的错误状态:
主动错误帧:由 “主动错误状态” 的设备发送,结构是 “6 个连续的显性电平(强告警)+ 8 个隐性电平(恢复同步)”—— 相当于 “大声喊:这里出错了!”,会强制中断当前的数据传输;
被动错误帧:由 “被动错误状态” 的设备发送,结构是 “6 个连续的隐性电平(弱告警)+ 8 个隐性电平(恢复同步)”—— 相当于 “小声说:这里好像出错了”,不会强制中断传输,避免影响其他设备。
6. 错误恢复:出错后如何重新通信?
若设备发送主动错误帧后,总线会暂停当前传输,所有设备等待总线空闲(连续 11 个隐性电平)后,仲裁失利的设备会重新尝试发送数据;
若设备处于被动错误状态,每次发送数据前,必须等待总线空闲后再延迟一段 “被动错误延迟时间”,避免与正常设备冲突;
若设备进入总线关闭状态,需通过两种方式恢复:① 硬件复位(重启设备);② 软件复位(通过 CAN 控制器的复位命令,让 TEC/REC 计数器清零,恢复为主动错误状态)。
CAN 总线的错误处理机制,通过 “5 种错误检测 + 2 个错误计数器 + 3 种状态管理”,实现了 “自动检测、主动告警、状态自适应、故障隔离” 的全流程纠错能力。哪怕总线上有个别设备故障,也能通过状态切换和总线关闭机制,确保其他设备正常通信 —— 这也是 CAN 总线在工业控制、汽车电子等对稳定性要求极高的场景中,被广泛应用的核心原因之一。