第一章 CAN/LIN总线基础

1.1 CAN总线的起源

说到CAN总线,得从上世纪80年代讲起。那时候汽车电子开始爆发,ECU越来越多,线束越来越重。我记得有个老工程师跟我吐槽过,说当时一辆豪华车的线束能绕地球半圈——当然这是夸张,但确实是个大问题。

1983年,德国博世公司开始研发一种新的串行通信协议。说白了,就是要解决「多个ECU之间怎么高效通信」的问题。1986年,CAN总线正式发布。嗯,这里有个有意思的点:CAN最初是为汽车设计的,但现在工业自动化、医疗设备、甚至电梯都在用。

为什么会这么火?因为CAN总线有两个核心优势:实时性高可靠性强。你想想看,刹车信号如果延迟了100毫秒,那后果...我不用多说。

核心要点:CAN总线是博世为解决汽车线束过多、ECU通信复杂而设计的串行总线协议。它采用多主站架构,任何节点都可以主动发送数据。

1.2 CAN总线物理层

物理层,说白了就是信号怎么在线上跑。CAN总线使用差分信号传输,两条线:CAN_H和CAN_L。我刚开始学的时候总觉得差分信号很玄乎,其实原理很简单——两条线电压差决定逻辑值。

CAN总线的电平定义是这样的:

信号状态 CAN_H电压 CAN_L电压 电压差
显性(Dominant) 3.5V 1.5V 2V
隐性(Recessive) 2.5V 2.5V 0V

显性电平对应逻辑0,隐性电平对应逻辑1。这里有个坑:显性电平会覆盖隐性电平。什么意思?就是如果两个节点同时发数据,一个发0一个发1,总线最终是0。这就是CAN总线仲裁的基础。

避坑指南:我曾经在一个项目中,终端电阻没接对,导致通信时好时坏。CAN总线两端必须各接一个120Ω的终端电阻,这是用来消除信号反射的。别问我怎么知道的...那次排查花了我整整两天。

CAN总线的传输速率最高可达1Mbps(40米以内),距离越长速率越低。500kbps时能跑100米左右。我个人习惯在项目初期就定好速率,因为后期改起来很麻烦。

1.3 CAN总线数据帧

CAN总线的数据帧,我把它拆成几个部分来讲。标准帧有11位ID,扩展帧有29位ID。实际项目中,标准帧用得最多。

一个标准数据帧的结构如下:

帧起始(1bit) + 仲裁场(12bit) + 控制场(6bit) + 数据场(0-8byte) + CRC场(16bit) + 应答场(2bit) + 帧结束(7bit)

这里我重点说说仲裁场。CAN总线的仲裁机制很巧妙——ID越小,优先级越高。比如ID=0x001的节点和ID=0x100的节点同时发数据,0x001会赢。为什么?因为ID小的显性位更多。

数据场最多8个字节。你可能会问:为什么只有8个字节?嗯,这是为了确保实时性。数据越长,总线占用时间越久,其他节点就得等着。在汽车上,一个刹车信号8个字节足够了。

个人经验:我建议在设计CAN网络时,把关键信号(如刹车、转向)分配小ID,非关键信号(如车窗、座椅)分配大ID。这样能保证实时性。我曾经在一个项目中看到有人把车窗信号ID设得比刹车还小...结果你懂的。

1.4 LIN总线的起源

LIN总线,全称是Local Interconnect Network。它诞生的原因很简单——CAN总线太贵了。你想想看,一个车窗控制器用CAN总线,成本上去了,但功能其实很简单。

1998年,几家汽车厂商联合推出了LIN总线。它的定位很明确:低成本、低速、单主多从。说白了,就是给那些对实时性要求不高的子系统用的。

LIN总线的速率最高20kbps,一条总线最多支持16个节点。我刚开始做LIN项目时觉得这速率太低了,后来发现对于灯光控制、车窗控制这些应用,20kbps绰绰有余。

核心要点:LIN总线是CAN总线的低成本补充方案,适用于车身舒适性系统。它基于UART/SCI接口,使用单线传输。

1.5 LIN总线物理层

LIN总线的物理层比CAN简单得多。单线传输,以12V为电源,通过总线上的电压变化来表示逻辑电平。

信号状态 总线电压 逻辑值
显性 0V(地) 逻辑0
隐性 12V(电源) 逻辑1

LIN总线使用一根线,通过上拉电阻连接到12V。节点通过拉低总线来发送显性位。这里要注意:LIN总线的上拉电阻在主节点中,从节点不需要。

避坑指南:我曾经在一个项目中,从节点也加了上拉电阻,结果总线电平一直不对。后来查了半天才发现,LIN规范要求只有主节点有1kΩ上拉电阻,从节点如果有的话必须是30kΩ以上。这个细节很容易被忽略。

1.6 LIN总线报文帧

LIN总线的报文帧结构和CAN不太一样。它由主节点发起,从节点响应。一个完整的LIN帧包括:

  1. 同步间隔场:至少13个显性位,用于唤醒总线
  2. 同步场:0x55,用于时钟同步
  3. 标识符场:6位ID + 2位奇偶校验
  4. 数据场:1-8个字节
  5. 校验和场:1个字节

LIN的标识符范围是0x00到0x3F,共64个。其中0x00-0x3B用于正常通信,0x3C和0x3D用于诊断,0x3E和0x3F保留。

我个人觉得LIN最巧妙的地方是时钟同步机制。因为LIN节点通常使用内部RC振荡器,精度不高。但通过同步场,从节点可以校准自己的波特率。嗯,这个设计真的很实用。

个人经验:在做LIN灯光网络时,我建议把灯光控制信号放在ID较小的帧里。比如近光灯用ID=0x01,远光灯用ID=0x02。这样主节点调度时,关键灯光信号能优先发送。我曾经在一个项目中把转向灯信号放在ID=0x30,结果每次打转向灯都有延迟...后来改了ID就好了。

好了,这一章的内容就到这里。CAN和LIN的基础知识,说白了就是理解它们「为什么这么设计」以及「怎么用」。下一章我们会深入CAN/LIN的协议细节,到时候再聊。