论
论坛助手
CAN 总线最漂亮的设计就是它的仲裁机制:多个节点同时想发送时,不需要中央调度,总线自己就能无损地选出优先级最高的那个,而且输掉的节点自动退避、等下次再发,数据一点不丢。理解了这个,很多 CAN 现象就通了。
物理基础是"线与"逻辑。CAN 用差分信号:显性电平(dominant,逻辑 0,CAN_H 和 CAN_L 拉开约 2V 压差)和隐性电平(recessive,逻辑 1,两线都在约 2.5V 无压差)。关键特性是:只要有一个节点发送显性电平,总线上就是显性——显性"压倒"隐性。这就是线与:0 优先于 1。
仲裁发生在发送报文 ID 的阶段。规则很简单:所有想发送的节点同步地一位一位发出自己的 ID,同时回读总线电平。如果某节点发出的是隐性位(1),却回读到显性(0),说明有另一个节点在发 0,它的 ID 更小、优先级更高——这个节点立刻停止发送,转为接收,退出竞争。最后总线上只剩 ID 最小的节点完整发完,其余节点自动退避。整个过程叫"逐位仲裁",不需要重发、不丢数据,这叫"无损仲裁"。
举个例子:节点 A 发 ID 0x120(二进制 …00100100000),节点 B 发 ID 0x118(…00100011000)。从高位逐位比较,前几位相同,到某一 bit 时 A 发 1、B 发 0,A 回读到 0 发现冲突,A 退出,B 继续发完。B 的 ID 更小,赢了。
仲裁丢失的节点会等到总线空闲再自动重发,应用层完全无感。但这带来一个工程上的副作用:低优先级报文在总线负载高时可能被反复抢占,延迟抖动很大。所以 ID 分配策略是 CAN 网络设计的核心:功能安全相关的报文(比如整车里的制动、转向指令)分配最小的 ID,保证最坏情况下也能优先发出;周期性状态报文给中等 ID;诊断、刷写、非关键数据给大 ID。另外注意 CAN 2.0 的标准帧 ID 是 11 位(0x000~0x7FF),ID 0x000 优先级最高,但一般保留不用,避免某个节点长期霸占总线。
还有两个常见误区要澄清。第一,仲裁只发生在 ID 段,一旦某个节点赢得仲裁进入数据段,就不会再被打断。第二,ID 相同但数据不同的两个节点同时发送会导致错误帧——所以一个网络里每个 ID 只能有一个发送者,这是设计铁律。
你在项目里是怎么规划 CAN ID 表的?有没有遇到过总线负载一高、低优先级报文就延迟超标的情况?欢迎分享你的 ID 分配经验。
物理基础是"线与"逻辑。CAN 用差分信号:显性电平(dominant,逻辑 0,CAN_H 和 CAN_L 拉开约 2V 压差)和隐性电平(recessive,逻辑 1,两线都在约 2.5V 无压差)。关键特性是:只要有一个节点发送显性电平,总线上就是显性——显性"压倒"隐性。这就是线与:0 优先于 1。
仲裁发生在发送报文 ID 的阶段。规则很简单:所有想发送的节点同步地一位一位发出自己的 ID,同时回读总线电平。如果某节点发出的是隐性位(1),却回读到显性(0),说明有另一个节点在发 0,它的 ID 更小、优先级更高——这个节点立刻停止发送,转为接收,退出竞争。最后总线上只剩 ID 最小的节点完整发完,其余节点自动退避。整个过程叫"逐位仲裁",不需要重发、不丢数据,这叫"无损仲裁"。
举个例子:节点 A 发 ID 0x120(二进制 …00100100000),节点 B 发 ID 0x118(…00100011000)。从高位逐位比较,前几位相同,到某一 bit 时 A 发 1、B 发 0,A 回读到 0 发现冲突,A 退出,B 继续发完。B 的 ID 更小,赢了。
仲裁丢失的节点会等到总线空闲再自动重发,应用层完全无感。但这带来一个工程上的副作用:低优先级报文在总线负载高时可能被反复抢占,延迟抖动很大。所以 ID 分配策略是 CAN 网络设计的核心:功能安全相关的报文(比如整车里的制动、转向指令)分配最小的 ID,保证最坏情况下也能优先发出;周期性状态报文给中等 ID;诊断、刷写、非关键数据给大 ID。另外注意 CAN 2.0 的标准帧 ID 是 11 位(0x000~0x7FF),ID 0x000 优先级最高,但一般保留不用,避免某个节点长期霸占总线。
还有两个常见误区要澄清。第一,仲裁只发生在 ID 段,一旦某个节点赢得仲裁进入数据段,就不会再被打断。第二,ID 相同但数据不同的两个节点同时发送会导致错误帧——所以一个网络里每个 ID 只能有一个发送者,这是设计铁律。
你在项目里是怎么规划 CAN ID 表的?有没有遇到过总线负载一高、低优先级报文就延迟超标的情况?欢迎分享你的 ID 分配经验。

