CAN 帧结构、字节顺序和位计数
本页解释 AUTOSAR 和 Vehicle Network Toolbox™ 在 CAN 帧结构方面的行为。它参考了 AUTOSAR CP System Template R23-11 中的特定术语,但这些概念是通用的,也适用于该标准的其他版本。
字节顺序(端序)和位计数
字节顺序(或端序)指字节在数字字中的存储顺序。术语 "Big Endian"(Motorola® 字节顺序)指最高有效字节先存储。相反,"Little Endian"(Intel® 字节顺序)指最低有效字节先存储。
位计数指在给定字节布局中二进制数的有序位序列。术语“最高有效位优先”(MSb 优先)或“最低有效位优先”(LSb 优先)指位序列的起始位分别是 MSb 或 LSb。位编号可以独立于字节顺序指定。
Vehicle Network Toolbox 约定
在打包和解包信号的模块中,Vehicle Network Toolbox 通常利用“LSb 优先”位计数,而无论字节顺序如何。例如,假设有一个包含 2 个字节的字,在该字中,位和字节编号如下:

一个包含 10 个位的数字可以按几种不同方式存储在该字中。一种使用 Little Endian 字节顺序存储数字的可能方式如下:

其中起始位是位 2 (LSb),最后一位是位 11 (MSb)。请注意,因为字节顺序是 Little Endian,所以最低有效字节先存储(在字节 0 中)。
另一种存储相同数字但使用 Big Endian 位序的可能方式如下:

其中起始位是位 11 (LSb),最后一位是位 4 (MSb)。请注意,因为字节顺序是 Big Endian,所以最高有效字节先存储(在字节 0 中)。
AUTOSAR 约定
AUTOSAR 标准规定每种字节顺序使用不同位计数。特别是,如果选择 Little Endian 字节顺序,则位计数为 LSb 优先;如果使用 Big Endian 字节顺序,则位计数为 MSb 优先。
此约定意味着,当使用 Little Endian 字节顺序时,对于 Vehicle Network Toolbox 和 AUTOSAR,起始位实际上是相同的,即 LSb。
然而,当使用 Big Endian 时,起始位不同。在上述 Big Endian 示例中,AUTOSAR 会将起始位视为位 4 (MSb),而将最后一位视为位 11 (LSb)。
AUTOSAR 与 DBC 中的 CAN 帧结构
AUTOSAR 标准利用协议数据单元 (PDU) 的概念描述汽车网络,特别是 CAN 总线。
根据 AUTOSAR 描述,CAN 帧是具有给定最大长度的字节数组,具体长度取决于协议(对于常规 CAN,长度为 8 个字节,对于 CAN FD 则为 64 个字节)。该标准允许 CAN 帧包含单个 PDU。最常见的 PDU 类型是 ISignalIPdu,它是一种携带一个或多个 ISignal 的 PDU。(其他 PDU 类型根据上下文使用;值得注意的示例是 ContainerIPdu,这是一种可以携带其他 PDU 的 PDU,通常用于 CAN FD 帧中以在一个帧中传输多个 ISignalIPdu。)
ISignal 是一个位序列,表示要在总线上传输的一个信号的二进制值。
因此,与 CAN 数据库(DBC 文件)中 CAN 帧的常见定义不同(它将信号直接映射到帧),AUTOSAR 提供了更多灵活性。在 AUTOSAR 中,需要先将 ISignal 映射到 ISignalIPdus;然后,将 ISignalIPdus 映射到帧。这两个连续的步骤受到所选的字节顺序和位计数的影响。
PDU 中 AUTOSAR 信号的布局
AUTOSAR 实体 ISignalToIPduMapping 指定 ISignal 在 ISignalIPdu 中的定位方式。在这方面,ISignalToIPduMapping 的关键属性是:
对应的 ISignal,它是另一个 AUTOSAR 实体,定义信号的长度(还定义其他参数)。
packingByteOrder,其值可以是 mostSignificantByteLast(即 Little Endian)、mostSignificantByteFirst(即 Big Endian)和 Opaque(不受 Vehicle Network Toolbox 支持)。
startPosition,即 PDU 中信号的起始位的位置,例如,如果用 Little Endian 字节顺序,则位置为 LSb,如果用 Big Endian 字节顺序则为 MSb。
假设有以下位布局,对应于长度为 2 个字节的 ISignalIPdu:

在本例中,根据 AUTOSAR 约定,相关参数为:
ISignal.length = 10
ISignalIPduMapping.packingByteOrder = mostSignificantByteFirst (Big Endian)
ISignalIPduMapping.startPosition = 5 (MSb)
帧中 AUTOSAR PDU 的布局
AUTOSAR 实体 PduToFrameMapping 指定 PDU 在帧中的定位方式。在这方面,PduToFrameMapping 的关键属性是:
packingByteOrder,其值可以是 mostSignificantByteLast(即 Little Endian)或 mostSignificantByteFirst(即 Big Endian)
startPosition,即 ISignalIPdu 的起始位的位置,例如,如果用 Little Endian 字节顺序,则位置为 LSb,如果用 Big Endian 字节顺序则为 MSb。
尽管这两个参数与 ISignalToIPduMapping 中的名称相同,但它们指 PDU(而不是信号)的字节顺序和位的位置。
此外,请注意 PDU 必须在帧中字节对齐。因此,如果字节顺序是 Little Endian,startPosition 的允许值为 0、8、16... 等,而如果字节顺序是 Big Endian,则 startPosition 的允许值为 7、15、23... 等。
例如,假设在长度为 4 个字节的帧中存储了长度为 2 个字节的以下 ISignalIPdu:

根据 AUTOSAR 约定,参数为:
PduToFrameMapping.packingByteOrder = mostSignificantByteFirst (Big Endian)
PduToFrameMapping.startPosition = 15 (MSb)
信号到帧的映射:AUTOSAR 与 Vehicle Network Toolbox
与 AUTOSAR 相比,ISignalIPdus 与帧之间的中间映射以及 ISignals 与 ISignalIPdus 之间的映射使得理解在 Vehicle Network Toolbox 中计算起始位的方式不那么直观。以下四个示例代表可能的情况。
具有 Little Endian 字节顺序的 PDU 携带具有 Little Endian 字节顺序的信号
假设在长度为 4 个字节的帧中存储了长度为 2 个字节的以下 ISignalIPdu。字节顺序为 Little Endian,起始位为位 8 (LSb),最后一位为位 23 (MSb)。此 PDU 携带一个 ISignal,其本身以 Little Endian 字节顺序存储,其起始位(相对于 PDU)为位 2,位长度为 10 位。

Vehicle Network Toolbox 将信号起始位视为信号的相对于帧的 LSb,无论信号的字节顺序如何。(这是在 CAN Pack 和 CAN Unpack 等模块封装中起始位的解释。)
就位计数而言,在这种情况下,AUTOSAR 中信号起始位的定义与在 Vehicle Network Toolbox 中等效,因为信号的字节顺序是 Little Endian。然而,信号的起始位在 AUTOSAR 中是相对于 PDU 的起始位给出的,PDU 本身以 Little Endian 字节顺序存储,因而其起始位是 PDU 的 LSb。因此,Vehicle Network Toolbox 按如下方式计算起始位(伪代码):
if PduToFrameMapping.byteOrder == mostSignificantByteLast && ISignalIPduMapping.byteOrder == mostSignificantByteLast startBit = PduToFrameMapping.startPosition + ISignalIPduMapping.startPosition end
在示例中,如图中所示,在 Vehicle Network Toolbox 中信号的起始位为位 10。
具有 Little Endian 字节顺序的 PDU 携带具有 Big Endian 字节顺序的信号
假设在长度为 4 个字节的帧中存储了长度为 2 个字节的以下 ISignalIPdu。字节顺序为 Little Endian,起始位为位 8 (LSb),最后一位为位 23 (MSb)。此 PDU 携带一个 ISignal,以 Big Endian 字节顺序存储,其起始位(相对于 PDU)为位 4,位长度为 10 位。

在这种情况下,信号的字节顺序为 Big Endian,位计数约定在 AUTOSAR 和 Vehicle Network Toolbox 之间不同。然而,PDU 的字节顺序是 Little Endian,因此其 startPosition 可以添加到信号的 MSb 以确定相对于帧的 MSb。
最后一步是根据相对于帧的 MSb 确定相对于帧的 LSb。这可以通过以下标准算法完成(伪代码):
function LSb = computeLSbGivenMSb(MSb, bitLength, frameLength) i = rem(MSb, 8); j = fix(MSb/8); MSb_aux = 8*(frameLength - j - 1) + i; LSb_aux = MSb_aux - bitLength + 1; ii = rem(LSb_aux, 8); jj = frameLength - fix(LSb_aux/8) - 1; LSb = ii + 8*jj; end
此算法给出位 19 的值作为 LSb,根据 Vehicle Network Toolbox 约定对应于信号的起始位。
具有 Big Endian 字节顺序的 PDU 携带具有 Little Endian 字节顺序的信号
假设在长度为 4 个字节的帧中存储了长度为 2 个字节的以下 ISignalIPdu。字节顺序为 Big Endian,起始位为位 15 (MSb),最后一位为位 16 (LSb),如图中所示。此 PDU 携带一个 ISignal,以 Little Endian 字节顺序存储,其起始位(相对于 PDU)为位 2,位长度为 10 位。

请注意,PDU 元数据定义属于 PDU 的字节。另请注意,字节顺序(信号和 PDU 的字节顺序)是相对于帧的绝对字节位置给出的。有了元数据后,就可以根据 Vehicle Network Toolbox 约定确定信号的起始位,如下所示(伪代码):
startBit = PduToFrameMapping.startPosition - 7 + ISignalToIPduMapping.startPosition
具有 Big Endian 字节顺序的 PDU 携带具有 Big Endian 字节顺序的信号
假设在长度为 4 个字节的帧中存储了长度为 2 个字节的以下 ISignalIPdu。字节顺序为 Big Endian,起始位为位 15 (MSb),最后一位为位 16 (LSb),如图中所示。此 PDU 携带一个 ISignal,以 Big Endian 字节顺序存储,其起始位(相对于 PDU)为位 4 (MSb),位长度为 10 位。

在这种情况下,可以通过以下方式确定相对于帧的信号的 MSb:
MSb = PduToFrameMapping.startPosition - 7 + ISignalToIPduMapping.startPosition;
通过 MSb,可以根据信号位长度和帧长度计算 LSb,如之前在函数 computeLSbGivenMSb 中所示。