CAN DBC 中的 Intel 与 Motorola 字节序:起始位到底怎么数
Intel 还是 Motorola?用同一组字节演示两种字节序取到的位有何不同,讲清 DBC 里的起始位和 @0/@1,以及为什么工具显示的起始位会和 DBC 文件对不上。
Intel 字节序(DBC 里写作 @1)把多字节信号的低字节放在前面,DBC 起始位指的是信号的最低位(LSB);Motorola 字节序(@0)把高字节放在前面,起始位指的是最高位(MSB)。所以同一帧数据、同一个起始位,按两种字节序取到的位不一样,算出的数也不一样。解码结果对不上时,第一个要查的就是字节序。
同一组字节,两个结果
拿一帧 8 字节数据 12 34 00 00 00 00 00 00,定义一个 16 位无符号信号,系数 1,在 CAN 信号计算器 里分别按两种字节序解码:
| 字节序 | DBC 起始位 | 占用的位 | 原始值 |
|---|---|---|---|
Intel(@1) | 0 | 字节 0 第 0 位(LSB)到字节 1 第 7 位(MSB) | 0x3412(13330) |
Motorola(@0) | 7 | 字节 0 第 7 位(MSB)到字节 1 第 0 位(LSB) | 0x1234(4660) |
两种定义占用的是同样的 16 个位,区别在于把哪个字节当作高字节:
payload 12 34 00 00 00 00 00 00
Intel 高字节 = 字节 1,低字节 = 字节 0 → 0x3412 = 13330
Motorola 高字节 = 字节 0,低字节 = 字节 1 → 0x1234 = 4660
起始位也不同,因为两种字节序是从信号的不同一端开始数的。


DBC 里的 @0 和 @1
DBC 文件里每个信号是一行 SG_:
SG_ Speed : 7|16@0+ (1,0) [0|65535] "" Vector__XXX
从左往右看:
7|16:起始位和位长度。@0:字节序。@0是 Motorola(大端),@1是 Intel(小端)。+表示无符号,-表示有符号(补码)。(1,0):系数和偏移,用法见下方公式。[0|65535]是最小值和最大值,""是单位,最后一个字段是接收节点。
字节序是按信号设置的,不是按报文或整个文件。同一条报文里可以同时有 Intel 信号和 Motorola 信号,所以要看你正在解码的那个信号自己的标志。
起始位是怎么数的
DBC 对两种字节序使用同一套位编号:bit 0 是字节 0 的最低位,bit 7 是字节 0 的最高位,bit 8 是字节 1 的最低位,依此类推。区别在于信号相对于这个编号往哪个方向走。
Intel:起始位是 LSB
信号从起始位开始往上长,到了某个字节的第 7 位,就接着从下一个字节的第 0 位继续。起始位为 0 的 16 位 Intel 信号先占满字节 0,再占满字节 1,数值的高位部分在字节 1。
Motorola:起始位是 MSB
信号从起始位开始,往同一字节的第 0 位方向走;走到第 0 位后,跳到下一个字节的第 7 位继续往下。在位网格上画出来是一条锯齿线,所以常被叫作锯齿(sawtooth)编号。
信号不在字节边界结束时,这个走法最直观。计算器自带的示例是一个 12 位 Motorola 信号,起始位 7,载荷相同。它占用整个字节 0 和字节 1 的高 4 位:
Motorola,起始位 7,长度 12,系数 0.1
占用位 字节 0 的 7…0 位,接着字节 1 的 7…4 位
原始值 0x12(8 位)后接 0x3(4 位) → 0x123 = 291
物理值 291 × 0.1 = 29.1

为什么工具里显示的起始位和 DBC 对不上
手工填信号定义时,最容易错在这里。DBC 文件里,Motorola 信号的起始位记录的是 MSB 的位置,但有些工具对同一个信号显示的是另一个数。canmatrix 关于信号字节序的说明 里有一个例子:一个 32 位 Motorola 信号,DBC 文本里起始位是 7,CANdb++ 里显示为 24,也就是它 LSB 的位置。换到本文的 16 位信号,LSB 在 bit 8。
如果把工具里显示的这个数抄进按 DBC 约定计算的工具,得到的就是另一个信号。在计算器里填 Motorola、起始位 8、长度 16,信号会从字节 1 第 0 位开始,一直延伸到字节 2 和字节 3。这帧里这两个字节都是 0,于是结果是 0 而不是 4660,而且没有任何报错。

起始位错了不一定会得到明显离谱的数。如果相邻字节里放着别的信号,你会得到一个看起来合理但其实错误的值。数值不对时,先对比 DBC 文本里的起始位和工具里显示的起始位,再去动别的参数。MathWorks 的文档 也说明了大端信号在 AUTOSAR 和其工具箱之间起始位编号的类似差异。
字节序之外:有符号值
有无符号是另一个独立标志(+ 或 -),但出错的方式同样安静。有符号信号按补码存储。设信号长 位,这些位按无符号读出的值为 :
以一个起始位 0、系数 0.1 的 12 位 Intel 信号为例。这里 , 只要不小于 2048 就是负数:
Intel,起始位 0,长度 12,系数 0.1,载荷 9C FF
占用位 字节 1 的 3…0 位,接着字节 0 的 7…0 位 → 0xF9C = 3996
无符号 3996 × 0.1 = 399.6
有符号 最高位为 1,3996 − 4096 = −100 → −100 × 0.1 = −10.0
本该出现负数的温度或扭矩突然变成一个很大的正数时,查完字节序再查符号位。
我的 DBC 会用哪种字节序?
没法预设。公开资料对哪种更常见说法不一:OpenXC 固件文档 说汽车网络里大端最常见,embdx 则认为现代 CAN 里 Intel 更常见。既然每个信号都带着标志,直接读 DBC 里的 @0 或 @1,不要猜。
如果手上根本没有 DBC,就找一个能主动改变的量,比如踏板位置或计数器,盯住它所在的报文。在 Trace 里按这个 ID 筛选,让数值沿一个方向慢慢变化:几乎每一步都在变的字节放的是低位部分,偶尔才变的字节放的是高位部分。如果高位部分在编号更小的字节里,这个信号多半是 Motorola。
检查整个 DBC
计算器一次只看一帧。要检查文件里的所有信号,可以用 DBC 查看器 打开,它的位布局会显示每个信号的起始位、字节序、系数和偏移。字节序写错,常常表现为两个信号占用了相同的位,或者信号超出了帧长度;DBC 检查器 会把这两类问题连同行号一起报出来。要解码整段录制而不是一帧,可以看没有 CANoe,怎么打开 BLF 文件。
把你自己的一帧数据粘贴进计算器,在 Intel 和 Motorola 之间切换,看哪种读法和你预期的数值对得上。