跳到主要内容

03. CAN 是什么:先看懂一帧报文

学习形式概念课
硬件要求不需要
配套 Demo
本课动作不涉及硬件操作

这节课要完成什么

这一课只学习三个新概念:

  1. 总线和节点;
  2. CAN 的广播式通信;
  3. 一帧日志里的 CAN-IDDLCDATA

学完后,你应该能独立拆开下面这帧报文:

0x123 [3] 11 22 33

1. “总线”是什么意思

假设一个系统里有控制器、传感器和执行器。如果每两个设备都单独拉一组通信线,设备越多,线路越复杂。

总线是一组被多个设备共同使用的通信线路。先用一根粗线表示共享通道:

控制器 A 传感器 B 执行器 C
| | |
+---------------------+--------------------+
共享总线

这张图只表达三个设备接在同一条主干上。真实 CAN 使用 CANH 和 CANL 两根信号线,下一课再展开。

“共享”有两个重要含义:

  • 设备 B 不是中转站,A 的消息不需要由 B 转发给 C;
  • 任意设备发送时,其他设备都能在总线上看到这帧报文。

2. 什么是 CAN 节点

连接到 CAN 总线、能够收发 CAN 报文的设备,称为 CAN 节点。

可以把这两个词分开理解:

  • 总线说的是多个设备共同使用的通信线路;
  • 节点说的是接到这组线路上、参与通信的设备。

控制器、传感器和电机驱动器都可以成为节点。“节点”描述的是设备在 CAN 总线上的通信角色,与设备的品牌和使用的芯片无关。

放到本教程的实物上看:

底板通过四位接口连接电机,其中 CANH 和 CANL 用于传递 CAN 报文

先看与通信有关的部分:底板和电机之间通过 CANHCANL 传递报文。因此,左边底板是一个 CAN 节点,右边电机内部的控制器是另一个 CAN 节点。图中的 VOUTGND 负责供电和共地,不属于 CAN 总线的两根信号线。

底板上虽然有多颗芯片,但不是每颗芯片都要单独算作一个节点。判断时看的是接到总线上的完整通信设备:整套底板共同完成报文的发送和接收,所以它算一个节点。

现在,两个节点已经通过同一条 CAN 总线连接起来,可以互相传递报文。这样的通信系统通常称为 CAN 网络。这里的“网络”指这些节点和连接它们的总线,与互联网、Wi-Fi 没有关系。

3. CAN 是广播式通信

节点 A 发送一帧后,这帧报文会出现在共享总线上:

节点 A 发送
|
v
+-------------------+-------------------+
| CAN 总线 |
+-------------------+-------------------+
| |
v v
节点 B 看见 节点 C 看见

所有节点都能看见,不代表所有节点都必须处理。各节点可以根据报文标识符选择:

  • 接收并处理;
  • 看见但不使用;
  • 通过硬件过滤器忽略。

因此 CAN 报文不像“只写给某个收件人的私信”,更像带有明确栏目编号的广播。

4. 看懂第一帧 CAN 报文

抓包工具和串口日志常把一帧 CAN 报文显示为:

0x123 [3] 11 22 33

从左到右拆成:

0x123 [3] 11 22 33
| | |
CAN-ID DLC DATA

CAN-ID:报文的标识符

0x123 是这帧报文的 CAN-ID。

0x 表示后面的数字使用十六进制书写。现在只需要把 0x123 看作一个完整编号,不要求立刻掌握十六进制换算。

协议或设备设计者会给不同 CAN-ID 约定不同含义。接收节点看到 0x123 后,可以根据这个编号判断自己是否需要处理这帧报文。

CAN-ID 还会影响报文的发送优先级。假设两个节点恰好同时开始发送:

节点 A 准备发送:0x123
节点 B 准备发送:0x321

对于本教程使用的标准 CAN 数据帧,数值较小的 0x123 优先继续发送,节点 B 会停止本次发送,等待总线空闲后再尝试。这个自动决定发送先后顺序的过程叫作仲裁。节点 B 只是暂时让出总线,并不表示通信出错。

仲裁过程怎样逐位比较,会在后面的课程中展开。现在只需要知道:CAN-ID 既是报文的标识符,也会影响报文占用总线的优先级。

CAN-ID 不应简单理解成“这帧只发给哪台设备的地址”。看一个例子:

传感器发送:CAN-ID 0x180(假设项目约定它表示温度消息)

CAN 总线
|
+--------------+--------------+
| | |
显示器 记录仪 电机
处理 0x180 处理 0x180 忽略 0x180

传感器只是把带有 0x180 标识符的报文放到共享总线上,并没有指定“只交给显示器”。显示器和记录仪可以同时关心 0x180,电机则可以忽略它。

从物理总线角度看,这些节点都能接收到总线上的信号。实际芯片还可以使用接收过滤器,让不关心的 CAN-ID 不必交给应用程序处理。

因此,CAN-ID 更像“消息类别编号”,而不是快递单上的唯一收件地址。后面学习 CANopen 时,会看到 CANopen 把功能类型和 Node-ID 编入一些 CAN-ID;那是 CANopen 对标识符的使用规则,底层报文仍然在共享 CAN 总线上发送。

DLC:数据区有多少字节

[3] 表示 DLC 为 3。DLC 是 Data Length Code 的缩写。

在本课程首先学习的 Classical CAN 数据帧中,可以先把它理解成数据区长度:

DLC = 3
DATA = 11 22 33

后面正好有 3 个数据字节。

DATA:报文携带的数据

11 22 33 是数据区。每两个十六进制字符表示一个字节:

第 0 字节:0x11
第 1 字节:0x22
第 2 字节:0x33

从第 0 字节开始编号,是因为 C 语言数组下标从 0 开始。数据具体代表温度、位置还是状态,CAN 本身并不知道。

5. CAN 负责“怎样传”,不负责“是什么意思”

CAN 控制器会参与处理:

  • 报文格式;
  • 总线仲裁;
  • CRC 等错误检查;
  • 接收确认 ACK;
  • 通信错误和错误状态。

CAN 本身不规定:

  • 0x123 是否代表电机位置;
  • 某个数据字节使用什么单位;
  • 怎样启动一台伺服电机;
  • 设备多久报告一次状态。

可以先记成:

CAN 规定数据怎样在总线上可靠传输
上层协议 规定编号和数据应该怎样解释

CANopen 就是一种建立在 CAN 之上的上层协议。我们会先学会 CAN,再进入 CANopen。

6. 三分钟练习

练习一

0x321 [2] AA BB

尝试自己写答案,再往下看:

CAN-ID = 0x321
DLC = 2
DATA = AA BB

练习二

0x701 [1] 05

目前只拆结构,不猜业务含义:

CAN-ID = 0x701
DLC = 1
DATA = 05

练习三

0x601 [8] 40 41 60 00 00 00 00 00

结果:

CAN-ID = 0x601
DLC = 8
DATA = 40 41 60 00 00 00 00 00

0x7010x601 的 CANopen 含义会在后面揭开。现在能正确数出数据字节就够了。

7. 四个常见误解

DLC 是 CAN-ID 的一部分吗

不是。0x123 [3] 中,CAN-ID 是 0x123,DLC 是 3。

DLC 自己占一个 DATA 字节吗

不占。DLC 用来描述长度,不是数据区的一部分。

A 发送后,只有指定的 B 能看见吗

不是。共享总线上的其他节点都能看到,再选择处理或忽略。

只看 DATA 就能知道电机动作吗

不能。还需要知道上层协议、报文标识符规则、数据类型和单位。

8. 对照一条真实格式日志

后续实验会看到类似输出:

CAN-ID 0x701 DLC 1 DATA 05

它和简写形式完全对应:

0x701 [1] 05

日志格式不同,组成部分没有改变。

这节课只记住三句话

  1. CAN 总线是多个节点共享的通信主干。
  2. CAN 报文会广播到总线,各节点自己决定是否处理。
  3. 常见日志可以拆成 CAN-ID + DLC + DATA

完成检查

不看前文,回答:

  1. 0x456 [3] 10 20 30 的 CAN-ID 是什么?
  2. DLC 是多少?
  3. DATA 有哪些字节?
  4. CAN 是否规定 0x20 一定表示速度?
  5. 为什么不能把 CAN-ID 简单看成收件人地址?

答案:

  1. 0x456
  2. 3。
  3. 0x100x200x30
  4. 不规定,含义由上层协议或项目约定决定。
  5. 因为报文会广播给总线上的节点,CAN-ID 更接近消息标识符。