CAN 总线这东西,刚入行嵌入式的朋友十有八九都听过,但真正能把它讲明白、用利索的人并不多。我见过太多项目,MCU 之间通信一上 CAN 就出问题:要么总线直接起不来,要么跑着跑着就疯狂报错,要么数据能发出去但对方死活收不到。最后排查半天,发现是终端电阻没接、波特率算错、或者 ID 优先级配反了这种基础问题。这篇内容就是把我这些年踩过的坑、调过的板子、看过的波形,系统性地梳理一遍。不管你是刚接触嵌入式的新手,还是已经做过几个项目但对 CAN 只停留在"能用就行"阶段的开发者,这篇都值得从头到尾看一遍。我会从物理层讲到应用层,从硬件设计讲到软件配置,把 CAN 总线那些"必懂"的知识点全部拆开揉碎,让你下次再遇到 CAN 问题的时候,脑子里能有一张清晰的排查地图。
1. 为什么 CAN 总线在嵌入式领域这么能打
1.1 从一辆车里的线束说起
如果你拆过汽车的仪表台,会发现里面密密麻麻全是线。早年间每增加一个功能,就要多拉一根线,线束越来越粗,重量越来越大,成本越来越高,可靠性还越来越差。CAN 总线诞生的初衷就是解决这个问题:用两根线把所有节点串起来,大家共享一条通道,谁需要发数据谁就发,不需要的时候闭嘴听着。这个思路放到今天看依然非常先进。
CAN 的全称是 Controller Area Network,控制器局域网。它最早由博世公司在 1986 年推出,后来成为国际标准 ISO 11898。它的核心设计目标就三个:可靠、实时、经济。这三个词看起来简单,但要做到极致并不容易。CAN 总线在汽车电子、工业控制、医疗设备、电梯控制等领域能统治这么多年,靠的就是在这三个维度上几乎没有短板。
1.2 多主架构与优先级仲裁:CAN 的灵魂
CAN 总线最核心的机制是多主架构加非破坏性仲裁。什么意思呢?总线上挂着的每个节点都可以主动发起通信,没有主从之分。如果两个节点同时开始发送数据,它们会通过 ID 逐位比较来决定谁先发。ID 数值越小,优先级越高。输的那个节点会自动退让,变成接收方,等总线空闲了再重发。整个过程不需要软件干预,全靠 CAN 控制器硬件自动完成。
这个机制的精妙之处在于:仲裁过程中不会丢失数据。赢的节点继续发,输的节点自动转为接收,等下一轮再抢。这跟以太网的 CSMA/CD 完全不同,以太网冲突后会退避重传,实时性没法保证。CAN 的这种设计让它在对实时性要求极高的场景下依然稳如老狗。
1.3 差分信号与抗干扰能力
CAN 总线用两根线传输信号:CAN_H 和 CAN_L。它传的不是绝对电压,而是两根线之间的电压差。显性电平(逻辑 0)时,CAN_H 约 3.5V,CAN_L 约 1.5V,压差约 2V;隐性电平(逻辑 1)时,两根线都在 2.5V 左右,压差接近 0V。
这种差分传输的好处是:外界干扰通常会同时作用在两根线上,压差基本不变,接收端照样能正确判断。这就是为什么 CAN 总线在电机、继电器、变频器这些强干扰环境下依然能稳定工作。我做过一个工业现场的项目,旁边就是大功率伺服电机,普通信号线全在跳,CAN 总线上的数据一个 bit 都没错。
1.4 错误检测与自动重发:可靠性从哪来
CAN 总线有一套非常完善的错误检测机制,包括位错误、填充错误、CRC 错误、格式错误、应答错误五种。任何一个节点检测到错误,都会立刻发出错误帧,通知全网。发送方检测到错误后会自动重发,直到成功为止。
更狠的是,CAN 控制器会维护发送错误计数器(TEC)和接收错误计数器(REC)。错误多了,节点会从"错误主动"变成"错误被动",再严重就"总线关闭",自动退出总线,避免一个坏节点拖垮整个网络。这种故障隔离机制是 CAN 可靠性的重要保障。
2. 物理层与硬件设计:那些让你调不通的细节
2.1 终端电阻:不是可选项,是必选项
CAN 总线两端必须各接一个120Ω 终端电阻,这是高频信号传输的基本要求。它的作用是消除信号反射,保证信号完整性。很多新手调不通 CAN,第一件事就应该拿万用表量一下 CAN_H 和 CAN_L 之间的电阻,正常应该是60Ω 左右(两个 120Ω 并联)。
我见过一个项目,板子做了五版,CAN 就是不通。最后发现是终端电阻焊成了 120Ω 单端,另一端没接。改成两端各 120Ω 之后,波形立刻干净了。还有一种情况是节点数多的时候,有人图省事只在主控板接了一个电阻,短距离低速可能凑合能用,但一旦速率上去或者线拉长,误码率立刻飙升。
注意:终端电阻必须接在总线的物理两端,不是每个节点都接。中间节点不需要接终端电阻,否则并联后阻值会偏离 60Ω。
2.2 收发器选型:TJA1050、SN65HVD230 怎么选
MCU 的 CAN 控制器输出的是逻辑电平,不能直接挂到总线上,必须经过CAN 收发器。常见的收发器有 NXP 的 TJA1050、TI 的 SN65HVD230、MAXIM 的 MAX3051 等。
| 型号 | 供电 | 速率 | 特点 | 适用场景 |
|---|---|---|---|---|
| TJA1050 | 5V | 1Mbps | 经典、便宜、抗干扰好 | 工业、汽车 |
| SN65HVD230 | 3.3V | 1Mbps | 低功耗、3.3V 直连 | 电池供电设备 |
| MAX3051 | 3.3V | 1Mbps | 低功耗、小封装 | 便携设备 |
| TJA1042 | 5V | 5Mbps | 支持 CAN FD | 高速场景 |
选型的时候重点看三点:供电电压是否匹配 MCU 电平、速率是否够用、是否有隔离需求。如果现场干扰特别大,建议用带隔离的收发器,比如 ADM3053,把总线侧和逻辑侧完全隔开,能省掉很多莫名其妙的故障。
2.3 布线规范:双绞线、屏蔽层与接地
CAN 总线必须用双绞线,这是差分传输的基本要求。双绞的目的是让两根线受到的干扰尽可能一致,共模干扰才能被抵消。线缆的特性阻抗应该是 120Ω,跟终端电阻匹配。
屏蔽层怎么接?我的经验是:单点接地。屏蔽层只在总线的一端接到机壳地或者大地,另一端悬空。如果两端都接,容易形成地环路,反而引入干扰。如果现场地电位差很大,建议用隔离收发器,把地环路彻底断开。
线长和速率的关系也要注意:
| 速率 | 最大线长 |
|---|---|
| 1Mbps | 40m |
| 500kbps | 100m |
| 250kbps | 250m |
| 125kbps | 500m |
| 50kbps | 1000m |
这个表是经验值,实际能拉多长还跟线材质量、节点数、干扰环境有关。我做过一个 250kbps 拉 300 米的项目,用的屏蔽双绞线,跑得很稳。但同样的速率用普通排线,100 米就开始丢包了。
2.4 共模电感与 TVS:保护你的收发器
工业现场浪涌、静电、短路都是家常便饭。CAN_H 和 CAN_L 对地短路、对电源短路,都可能烧掉收发器。建议在收发器和总线之间加共模电感和TVS 管。共模电感抑制共模干扰,TVS 管钳位瞬态高压。
我有个项目在户外,雷雨季节经常有节点损坏。后来在每块板的 CAN 接口加了共模电感和 TVS,故障率直接降到零。这个成本增加不到两块钱,但省下的售后成本是几十倍。
3. 协议层拆解:帧结构、仲裁与错误处理
3.1 标准帧与扩展帧:11 位 ID 和 29 位 ID
CAN 2.0A 用 11 位标识符,CAN 2.0B 用 29 位标识符。11 位能表示 2048 个 ID,29 位能表示 5 亿多个。大部分嵌入式项目用 11 位就够了,汽车行业因为节点多、信号多,常用 29 位。
标准帧和扩展帧可以在同一条总线上共存,但扩展帧的优先级仲裁会稍微复杂一点。实际项目中,我建议统一用一种格式,要么全标准帧,要么全扩展帧,避免混用带来的调试麻烦。
3.2 数据帧的七个字段:逐位拆解
一个标准数据帧包含七个部分:
- 帧起始(SOF):1 位显性电平,告诉总线"我要开始发了"。
- 仲裁场:11 位 ID + RTR 位。RTR 为显性表示数据帧,隐性表示远程帧。
- 控制场:IDE 位 + 保留位 + 4 位 DLC(数据长度码),DLC 最大为 8。
- 数据场:0 到 8 字节数据。
- CRC 场:15 位 CRC 校验 + 1 位界定符。
- 应答场(ACK):发送方发隐性,接收方如果正确接收就发显性,覆盖掉隐性。
- 帧结束(EOF):7 位隐性电平。
理解这些字段的意义在于:调试的时候你能看懂示波器或者 CAN 分析仪上的波形。比如 ACK 错误,说明没有节点应答,可能是波特率不对或者总线上只有你一个节点。CRC 错误,说明数据在传输过程中被干扰了,要查硬件。
3.3 位填充机制:为什么你的波形会多出几位
CAN 总线有个位填充规则:发送方在连续 5 个相同电平之后,会自动插入一个相反电平。接收方收到连续 5 个相同电平后,会自动删掉后面那个填充位。这个机制的目的是保证信号有足够的跳变,方便接收方同步时钟。
很多新手看波形的时候会懵:明明发了 8 个字节,怎么数出来多了几位?就是位填充在起作用。调试的时候不用太纠结这个,CAN 分析仪会自动处理。但如果你用示波器手动解码,就要注意这个规则。
3.4 错误帧与错误计数器:节点是怎么"自杀"的
前面提到 CAN 有五种错误检测。一旦检测到错误,节点会发错误帧,错误帧由 6 个连续显性位组成,故意违反位填充规则,让全网都知道出错了。
每个节点维护两个计数器:
- TEC(发送错误计数器):发送出错时加 8,成功发送减 1。
- REC(接收错误计数器):接收出错时加 1 或 8,成功接收减 1。
当 TEC 或 REC 超过 127,节点进入错误被动状态,发的错误帧变成被动错误帧。当 TEC 超过 255,节点进入总线关闭状态,自动退出总线,不再发送任何数据。只有软件干预或者总线空闲 128 次 11 位之后,才能恢复。
这个机制的意义是:防止一个坏节点无限重发,把总线带宽全占了。我遇到过一块板子因为收发器损坏,一直发错误帧,导致整个网络瘫痪。后来换了收发器就好了。所以如果你的 CAN 网络突然整体不通,先逐个排查节点,看是不是有节点进入了总线关闭状态。
4. MCU 上的 CAN 控制器配置实战
4.1 波特率计算:一个公式搞定
CAN 波特率的计算公式是:
波特率 = 时钟频率 / (预分频系数 × (1 + BS1 + BS2))其中 BS1 是时间段 1,BS2 是时间段 2,单位都是 Tq。采样点位置 = (1 + BS1) / (1 + BS1 + BS2)。
以 STM32 为例,假设 APB1 时钟是 36MHz,要配 500kbps:
- 预分频系数设为 4,则 Tq 时钟为 9MHz。
- 1 + BS1 + BS2 = 9MHz / 500kbps = 18。
- 取 BS1 = 15,BS2 = 2,采样点 = 16/18 ≈ 88.9%。
采样点一般建议在75% 到 87.5%之间。太低容易受干扰,太高同步裕量不够。如果总线上节点多、线长,建议采样点取 80% 左右。
提示:不同 MCU 的 CAN 控制器寄存器名称不一样,但原理都是配预分频、BS1、BS2 和同步跳转宽度(SJW)。SJW 一般取 1 到 4 个 Tq,用于补偿时钟偏差。
4.2 过滤器配置:别让无关报文占用 CPU
CAN 控制器收到报文后,会先经过验收过滤器。只有通过过滤器的报文才会被存到接收 FIFO,触发中断。如果过滤器没配好,所有报文都进来,CPU 会被中断淹没。
STM32 的 CAN 过滤器有掩码模式和列表模式两种。掩码模式适合接收一组 ID,列表模式适合接收几个特定 ID。比如你要接收 ID 0x100 到 0x1FF 的报文,可以用掩码模式,ID 设为 0x100,掩码设为 0x700,这样只要高 5 位匹配就能通过。
我见过一个项目,过滤器全开,总线上有几十种报文,CPU 光处理 CAN 中断就占了 40% 的负载。后来把过滤器配好,只接收需要的几种 ID,CPU 负载降到 5% 以下。这个优化立竿见影。
4.3 中断还是轮询:实时性与 CPU 占用的权衡
CAN 接收有两种方式:中断和轮询。中断实时性好,但报文多的时候中断频繁,CPU 上下文切换开销大。轮询 CPU 占用可控,但实时性差,可能丢报文。
我的建议是:低速率、少报文用中断;高速率、多报文用 DMA 或者轮询加缓冲。STM32 的 CAN 支持 FIFO 溢出中断,可以在 FIFO 快满的时候再处理,减少中断次数。如果 MCU 支持 CAN DMA,那就更省心了,数据自动搬到内存,CPU 只管处理。
4.4 发送优先级与邮箱管理
CAN 控制器一般有多个发送邮箱。当多个邮箱同时有待发报文时,控制器会按 ID 优先级发送,ID 小的先发。如果 ID 相同,按邮箱编号顺序发。
实际项目中,我建议把紧急报文配小 ID,比如故障报警用 0x001,普通数据用 0x100 以上。这样即使总线繁忙,紧急报文也能优先发出去。另外,发送邮箱不要全占满,留一两个给紧急报文,避免普通报文把邮箱占完,紧急报文发不出去。
5. 应用层协议设计:让 CAN 真正好用
5.1 为什么裸 CAN 不够用
CAN 只定义了物理层和数据链路层,也就是怎么传 bit、怎么组帧、怎么仲裁。但传什么、怎么解释、多长的数据、什么含义,这些都没有规定。所以实际项目中,必须自己定义一套应用层协议。
裸 CAN 的问题在于:8 个字节的数据,如果没有约定,接收方根本不知道第一个字节是命令还是数据,第二个字节是高位还是低位。节点多了,ID 怎么分配?多帧数据怎么拼?错误怎么处理?这些都要应用层来解决。
5.2 自定义协议的常见结构
一个典型的自定义 CAN 应用层协议,数据场 8 个字节可以这样分配:
| 字节 | 含义 |
|---|---|
| Byte0 | 命令码 / 功能码 |
| Byte1 | 目标地址 / 源地址 |
| Byte2-3 | 数据高位 / 低位 |
| Byte4-5 | 参数 1 |
| Byte6-7 | 参数 2 / CRC |
ID 可以用来区分消息类型和源节点。比如高 4 位表示消息类型,低 7 位表示源节点地址。这样接收方一看 ID 就知道是谁发的、什么类型的消息。
5.3 多帧传输:分包与重组
CAN 单帧最多 8 字节,超过 8 字节的数据必须分包。常见做法是:
- 首帧:包含总长度和第一段数据。
- 连续帧:包含后续数据,带序号。
- 流控帧:接收方告诉发送方可以继续发。
- 结束帧:表示传输完成。
这套机制跟 ISO-TP(ISO 15765-2)类似。如果项目对可靠性要求高,建议直接用 ISO-TP 协议栈,不要自己造轮子。自己写的分包重组逻辑,很容易在异常情况下出 bug,比如丢了一帧之后整个传输卡死。
5.4 CANopen 与 J1939:什么时候该用标准协议
如果项目是工业控制,可以考虑CANopen。它定义了对象字典、PDO、SDO、NMT 等一套完整机制,设备互操作性很好。如果项目是商用车、工程机械,J1939是行业标准,定义了参数组编号(PGN)和可疑参数编号(SPN)。
用标准协议的好处是:生态成熟、工具支持好、别人能看懂。坏处是:协议栈复杂、资源占用大、学习成本高。我的经验是:小项目、私有协议够用;大项目、多厂商协作,优先考虑标准协议。
6. 调试实战:从波形到代码的完整排查链路
6.1 示波器看波形:先确认物理层没问题
CAN 调试第一步,一定是看波形。把示波器调到差分模式,探头接 CAN_H 和 CAN_L,看有没有正常的差分信号。正常的 CAN 波形应该是:显性电平约 2V 压差,隐性电平约 0V,边沿干净,没有明显振铃。
如果波形幅度不对,查收发器供电和终端电阻。如果波形有振铃,查终端电阻和线长。如果完全没有波形,查 MCU 的 CAN 控制器有没有初始化成功,收发器有没有使能。
我有个习惯:每块新板子回来,先不写代码,直接上电用示波器看 CAN 引脚有没有波形。如果 MCU 初始化后发送一帧,示波器上能看到波形,说明硬件基本没问题。如果看不到,先查硬件,别浪费时间调代码。
6.2 CAN 分析仪:抓包与解码
示波器看物理层,CAN 分析仪看协议层。常见的 CAN 分析仪有周立功的 USBCAN、Peak 的 PCAN、开源的 CANable 等。它们能把总线上的报文全部抓下来,显示 ID、DLC、数据、时间戳。
抓包的时候重点看:
- 有没有报文:如果没有,说明物理层或者波特率有问题。
- ID 对不对:如果 ID 不对,说明发送方配置有问题。
- 数据对不对:如果数据不对,说明应用层打包或者解析有问题。
- 有没有错误帧:如果有大量错误帧,说明总线有干扰或者波特率不匹配。
6.3 常见故障排查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 完全无通信 | 终端电阻缺失、收发器损坏、波特率错误 | 量电阻、换收发器、核对波特率 |
| 通信不稳定 | 线太长、干扰大、采样点不对 | 降速率、加屏蔽、调采样点 |
| 部分节点不通 | ID 过滤配置错误、节点地址冲突 | 检查过滤器、核对 ID 分配 |
| 错误帧多 | 波特率不匹配、地电位差大 | 统一波特率、加隔离 |
| 总线关闭 | 节点故障、TEC 超限 | 查故障节点、复位控制器 |
6.4 一个真实的排查案例
之前有个项目,客户反馈 CAN 通信时好时坏。我到现场之后,先量终端电阻,60Ω 正常。再看波形,发现显性电平只有 1.5V,偏低。查收发器供电,发现是 5V 供电,但实际只有 4.3V。顺着电源查,发现是 LDO 输入电容虚焊,导致电压不稳。补焊之后,波形立刻正常,通信稳定。
这个案例说明:CAN 问题不一定在 CAN 本身,可能是电源、地、或者周边电路的问题。排查的时候要有全局观,不要只盯着 CAN 收发器。
7. 进阶话题:CAN FD 与时间触发 CAN
7.1 CAN FD:更快、更长
CAN FD(Flexible Data Rate)是 CAN 的升级版,有两个核心改进:数据段速率可变和数据场最长 64 字节。仲裁段还是用标准速率,保证兼容性;数据段可以切换到更高速率,比如 5Mbps,提高吞吐量。
CAN FD 适合大数据量传输的场景,比如刷写程序、传输标定数据、摄像头控制等。但 CAN FD 需要收发器和控制器都支持,老设备不兼容。如果你的项目是新设计的,MCU 也支持 CAN FD,建议直接上 CAN FD,一步到位。
7.2 TTCAN:时间触发机制
TTCAN(Time-Triggered CAN)在 CAN 基础上增加了时间触发机制,用全局时间同步和时间窗口来调度报文。每个报文在固定的时间窗口内发送,避免冲突,保证确定性。
TTCAN 适合对实时性要求极高的场景,比如线控刹车、线控转向。但 TTCAN 实现复杂,需要专门的控制器支持,实际项目中用得不多。大部分场景,标准 CAN 的优先级仲裁已经够用了。
7.3 从 CAN 到 CANopen 的迁移思路
如果你的项目现在用的是私有 CAN 协议,想迁移到 CANopen,我的建议是:
- 先梳理现有报文:把 ID、数据含义、发送周期全部列出来。
- 映射到对象字典:把每个信号映射到 CANopen 的对象字典索引。
- 配置 PDO:把实时性要求高的信号配成 PDO,周期发送。
- 保留私有通道:暂时保留一部分私有报文,逐步迁移。
迁移过程中,不要一次性全改,容易出问题。先在一个子系统上试点,跑稳了再推广。
8. 嵌入式面试中的 CAN 高频考点
8.1 基础概念类问题
面试官常问:"CAN 总线的仲裁机制是怎样的?" 回答要点:多主架构、非破坏性仲裁、ID 越小优先级越高、仲裁过程中数据不丢失。如果能补充"显性电平覆盖隐性电平"这个细节,加分。
另一个高频问题:"CAN 总线的终端电阻为什么是 120Ω?" 回答要点:匹配线缆特性阻抗、消除信号反射、保证信号完整性。如果能说出"两个 120Ω 并联后是 60Ω"这个实测值,说明你动手做过。
8.2 协议细节类问题
"标准帧和扩展帧有什么区别?" 回答要点:11 位 ID vs 29 位 ID、仲裁场结构不同、可以共存但建议统一。
"CAN 的错误检测有哪些?" 回答要点:位错误、填充错误、CRC 错误、格式错误、应答错误。能说出错误计数器的加减规则和总线关闭机制,说明你理解得比较深。
8.3 实战场景类问题
"如果 CAN 通信不稳定,你怎么排查?" 这是最能区分候选人的问题。我的回答思路是:先物理层(电阻、波形、供电),再协议层(波特率、过滤器),最后应用层(打包、解析)。能说出具体排查步骤和工具,比背概念强得多。
"CAN 总线上有节点频繁进入总线关闭,怎么处理?" 回答要点:先定位故障节点,查硬件(收发器、电源、地),再查软件(波特率、发送频率),必要时增加隔离或者降低速率。
8.4 如何准备 CAN 相关的面试
我的建议是:动手搭一个最小 CAN 系统。两块 STM32 板子,两个收发器,一根双绞线,两个 120Ω 电阻,写个最简单的收发程序。跑通之后,故意制造一些故障:拔掉终端电阻、改错波特率、短路 CAN_H 和 CAN_L,观察现象。这样面试的时候,你讲的是自己的真实经历,而不是背书。
9. 项目实战建议与个人经验
9.1 新项目 CAN 设计检查清单
每次新项目开始,我都会过一遍这个清单:
- [ ] 总线速率和线长是否匹配?
- [ ] 终端电阻是否只在两端?
- [ ] 收发器供电和 MCU 电平是否匹配?
- [ ] 是否有共模电感和 TVS 保护?
- [ ] 屏蔽层是否单点接地?
- [ ] ID 分配是否有规划,紧急报文是否用小 ID?
- [ ] 过滤器是否配置,避免 CPU 被无关报文淹没?
- [ ] 应用层协议是否文档化,字节含义是否明确?
- [ ] 是否有总线关闭恢复机制?
- [ ] 是否预留了调试接口(CAN 分析仪接入点)?
这个清单看起来简单,但每一条都是踩过坑之后总结出来的。尤其是 ID 分配和过滤器配置,前期规划好,后期省大事。
9.2 代码分层:让 CAN 驱动可复用
我的 CAN 代码一般分三层:
- 硬件抽象层:封装 MCU 的 CAN 寄存器操作,提供初始化、发送、接收接口。
- 协议层:处理帧的打包和解包,管理多帧传输、超时重传。
- 应用层:定义具体的命令和数据含义,处理业务逻辑。
这样分层的好处是:换 MCU 的时候,只改硬件抽象层;改协议的时候,只改协议层;业务逻辑基本不动。我做过一个项目,从 STM32 换到 NXP 的 MCU,硬件抽象层重写了一遍,协议层和应用层一行没改,两天就完成了移植。
9.3 我踩过的最大的一个坑
早年做一个车载项目,CAN 总线一直偶发丢帧。查了硬件、查了波特率、查了过滤器,都没问题。最后用 CAN 分析仪抓包,发现丢帧的时候总线上有大量错误帧。再查,发现是某个节点的地线和 CAN 地不是同一个地,地电位差导致共模电压超标。
解决方案是加隔离收发器,把 CAN 侧的地和逻辑侧的地完全隔开。改完之后,跑了三个月,一帧没丢。这个坑让我明白:CAN 总线对地电位差很敏感,多节点系统一定要考虑隔离。
9.4 给新手的三个建议
第一,别怕动手。CAN 这东西,看十遍书不如焊一块板子。买两个便宜的 CAN 模块,接上单片机,自己写代码跑一遍,比什么都强。
第二,学会看波形。示波器和 CAN 分析仪是 CAN 调试的两把利器。波形看物理层,分析仪看协议层,两个结合起来,大部分问题都能定位。
第三,文档化你的协议。我见过太多项目,协议只存在于某个人的脑子里,人一走,后面的人完全看不懂。花半天时间把 ID 分配、数据格式、通信流程写清楚,后面能省几十个小时的沟通成本。
CAN 总线不难,但细节很多。每一个细节背后,都是无数工程师踩坑踩出来的经验。希望这篇内容能帮你少走一些弯路,把 CAN 真正用起来、用明白。