目录

一、 物理层抗干扰神技:差分信号的暴力美学

二、 协议层颠覆:没有地址,只有“群发”和“订阅”

三、 面试核心:“非破坏性仲裁机制”

四、 进阶:从 STM32 到 Linux 底层驱动的进化之路

五、 八股与实战教训

六、 总结与明日预告


前五天,我们学习了:TCP、MQTT、CoAP,把设备连上互联网的操作了解了一遍。但是,如果你的目标不仅仅是做一个温湿度计,而是想做一台四足机器狗,或者想进入车企搞自动驾驶底层,你会发现一个恐怖的事实:

在机器人的体内、在汽车的底盘里,根本不是常用的 TCP/IP 和以太网!


想象一下:你开着车在高速上以120km/h狂飙,前方突然出现障碍物,你一脚踩下刹车。

如果刹车踏板和刹车卡钳之间用的是 HTTP 或者 TCP 协议……“对不起,当前网络拥堵,正在为您重传刹车指令(引发超时)……”

这已经不是丢包的问题了,这是要命!


在充满电机电磁干扰、要求绝对实时性(毫秒级甚至微秒级响应)的恶劣环境里,互联网协议是不适用的。今天,我们来硬刚统治了工业界和汽车界三十年的绝对骨干、底层大动脉——CAN 总线(Controller Area Network)


一、 物理层抗干扰神技:差分信号的暴力美学

为什么汽车发动机旁边全是高压线圈、机器人关节全是强磁大电机,CAN 依然能稳如老狗地传数据?

因为它在物理层用了一招杀手锏:差分信号

传统的串口(UART)是用一根线(TX/RX)对地(GND)的电压来判断 0 和 1。如果有外界电磁干扰打在通信线上,电压瞬间剧变,数据直接乱码。

CAN 根本不按套路出牌。它有两根线:CAN_H (High)CAN_L (Low)

  • 当发送逻辑 1(隐性电平)时: CAN_H 和 CAN_L 都不通电,两根线都是 2.5V。此时它们俩的电压差为 0V。

  • 当发送逻辑 0(显性电平)时: CAN_H 被拉高到 3.5V,CAN_L 被拉低到 1.5V。此时它们的电压差为 2V。

牛在哪? 假设旁边有个大电机启动,产生了一个 10V 的强干扰同时打在两根线上。

CAN_H 变成了 13.5V,CAN_L 变成了 11.5V。

但是!接收端只看它俩的电压差。13.5V - 11.5V = 2V!差值依然是 2V,数据完美的被还原了!这就叫共模干扰抑制


二、 协议层颠覆:没有地址,只有“群发”和“订阅”

习惯了网络编程的人,初学 CAN 最崩溃的就是:“怎么没有 IP 地址?也没有 MAC 地址?我怎么指定把数据发给谁?”

CAN 的核心哲学是:面向数据,而不是面向节点。

CAN 报文里没有源地址和目标地址,只有一个 ID(标识符)

这就相当于硬件级别的 MQTT(发布/订阅)!

比如,汽车的转向角传感器往总线上扔出一个报文,ID 是 0x012(代表转向数据)。

总线上的所有节点(仪表盘、ESP车身稳定系统、自动驾驶域控制器)都会收到这个报文。

  • 仪表盘一看,0x012 是转向数据,我不需要,直接在硬件底层丢弃(这叫验收滤波)。

  • ESP 系统一看,0x012!正是我要的,立刻收进内存,开始计算车轮防滑。

这种彻底的解耦,意味着你随时可以在总线上增加或拆除一个设备,而不需要修改其他设备的任何代码!


三、 面试核心:“非破坏性仲裁机制”

这是 CAN 总线最核心的八股文,也是它比其他总线较强的机制! 

如果两个节点同时往总线上发数据,怎么办?在以太网里,这叫“冲突”,大家只能退避重传,导致网络延迟飙升。

但 CAN 是个硬汉,它用“线与机制”直接当场决出胜负。

记住一个物理铁律:在 CAN 总线上,0 是老大(显性),1 是小弟(隐性)。只要有一个节点发 0,总线上就是 0。

现场演示:

假设节点 A 想发 ID 为 0x123 (二进制 00100100011) 的报文。

假设节点 B 想发 ID 为 0x124 (二进制 00100100100) 的报文。

它们同时开始发送:

  • 第 1 位:都是 0,总线是 0,和平。

  • 第 2 位:都是 0,总线是 0,和平。

  • ……(前面几位都一样)

  • 第 9 位:节点 A 发送 0,节点 B 发送 1

此时,见证奇迹的时刻到了!

总线被节点 A 的 0 强行拉成了逻辑 0

节点 B 在发完 1 之后,会下意识地回头看一眼总线,发现:“我明明发的 1,怎么总线上变成了 0?”

节点 B 立刻明白:有比我优先级更高的大佬在说话!

节点 B 瞬间闭嘴(转为接收状态),把舞台完全让给节点 A。

结论:ID 越小,报文里的前导 0 越多,优先级就越高!(这就是为什么刹车系统的 ID 永远比车内空调的 ID 小,保证保命数据绝对优先传输,零延迟!)


四、 进阶:从 STM32 到 Linux 底层驱动的进化之路

如果你希望后续的职业发展,能从单片机(裸机/RTOS 开发)往 Linux 应用开发 -> Linux 驱动方向 进阶,那么 CAN 总线是你最好的练兵场!

阶段 1:在 STM32 上玩 CAN(bxCAN)

在单片机阶段,你主要是在和寄存器搏斗。而常常犯迷惑的就是配置 CAN 过滤器(Filter Bank)。你需要根据掩码(Mask)来设置你的单片机到底接收哪些 ID 的数据。如果你配置错了,你会发现总线上一条数据都收不到,或者瞬间被洪水般的数据把单片机 RAM 挤爆。

阶段 2:在 Linux 上玩 CAN(SocketCAN)——真正的降维打击

当你升级到跑着 Linux 系统的高级核心板(比如在机器人主控里常见的 ARM Cortex-A 系列),玩法彻底变了!

在 Linux 中,驱动大牛们把 CAN 总线直接封装成了网络设备(就跟你的 Wi-Fi、以太网卡 eth0 一样,它叫 can0)。

这意味着什么?意味着你可以用昨天写 TCP/UDP Socket 的代码,来写底层工业通信代码!

这叫 SocketCAN

在 Linux 应用层,你只需要:

// 极其优雅的 Linux SocketCAN 调用方式
int s = socket(PF_CAN, SOCK_RAW, CAN_RAW); // 创建 CAN 套接字
struct sockaddr_can addr;
addr.can_family = AF_CAN;
addr.can_ifindex = if_nametoindex("can0"); // 绑定 can0 网卡
bind(s, (struct sockaddr *)&addr, sizeof(addr));

// 发送一帧 CAN 报文
struct can_frame frame;
frame.can_id = 0x123; // 设置 ID
frame.can_dlc = 2;    // 数据长度 2 字节
frame.data[0] = 0x11; // 填充数据
frame.data[1] = 0x22;
write(s, &frame, sizeof(struct can_frame)); // 像写文件一样发送到底层硬件!

理解了从 MCU 的寄存器配置,到 Linux 的设备树(Device Tree)和 SocketCAN 驱动映射,你就真正跨过了从“嵌入式底层打杂”到“Linux系统级开发”的分水岭!


五、 八股与实战教训

坑1:必须要加的 120 欧姆终端电阻!

如果你拿两块 STM32 飞线连 CAN 模块,程序死活调不通,第一步去检查 CAN_H 和 CAN_L 之间有没有并联一个 120 欧姆的电阻!

因为高频信号在导线尽头会产生“信号反射”(就像水波撞到墙壁弹回来),把后面的数据全毁了。120 欧姆电阻的作用就是“吸收”这些到达终点的信号。总线的两端必须各加一个。

坑2:Bus-Off(总线关闭)状态的绝望

面试常考:CAN 节点如果硬件短路了,一直在总线上发错乱的数据,会不会把整个汽车网络搞瘫痪?

答:不会! CAN 控制器内部有非常严密的“错误计数器”。当一个节点发现自己总是发错或者收错,它的错误计数器会飙升。当超过 255 时,这个节点会自动执行“社会性死亡”——切断自己与总线的物理连接,进入 Bus-Off 状态,牺牲自己,保全整车网络。

(注:在写驱动程序时,千万记得要写 Bus-Off 的恢复逻辑,不然设备一旦死掉就只能断电重启了)。


六、 总结与明日预告

今天,我们领略了 CAN 总线这种工业级通信的暴力美学:

  1. 差分信号硬抗强电磁干扰。

  2. 非破坏性仲裁机制(显性 0 覆盖隐性 1)完美解决并发冲突,实现优先级抢占。

  3. 从单片机的寄存器驱动,展望了通向 Linux 驱动工程师的桥梁——SocketCAN

只要你搞懂了 CAN,对于国内的车企(自动驾驶底盘控制)和机器人公司 这些都是有优势的。

但是,挑战又来了!

CAN 报文的数据段(Data Payload),一帧最多只能传 8 个字节! (哪怕是最新的 CAN-FD 也只有 64 字节)。

在复杂的机械臂控制里,如果要传几十上百字节的运动轨迹数据,8 个字节怎么塞得下?难道我们要自己手写分包、拼包逻辑吗?

不用你造轮子。

明天(Day 7),我们将迎来工业控制领域的进阶篇,也是建立在 CAN 物理层之上的高级协议:CANopen!带你揭秘工厂里的伺服电机到底是怎么被精准控制的。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐