Can总线字节序与相关计算
0. Bit Numbering
Bit numbering是汽车网络数据库用以辅助描述信号的专用术语,具体含义是位的编号顺序。
在通信数据库中,有两种Bit numbering,分别是msb0和lsb0。如字面意思,在一个字节内,如果msb的位置是0号bit,那么就被称为msb0,如果lsb的位置是0,bit numbering就是lsb0。
lsb0
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
lit0 bit1 bit2 bit3 bit4 bit5 bit6 bit7
最常见的Can通信数据库是Can DBC和Autosar ARXML,它们都采用的是lsb0的bit numbering,不论是字节序是大端还是小端,还有一些其他的数据库采用的是大端采用msb0,小端采用lsb0的策略。
它并不会改变signal在数据库中的实际位置,但是会影响人们如何阅读signal,这点在解析通信数据库时非常重要。例如:在msb0下的bit3,在lsb0下就是bit4。
1.Byte Order
Byte order是另一个用来描述通信数据库中signal的属性,它是指将byte数组中的signal解析成数字的一种规则。给定不跨字节的数据0x1234,要将它作为一个signal发送到总线上,就必须考虑打包和解包的规则,由此引出了两种字节序:大端和小端(motorola order和intel order)。
如果将0x12先发送到总线上,这种字节序就被称为大端或motorola字节序,反之,如果0x34先发送到总线上,就称为小端或intel字节序。
对于通信来说,都有字节序的概念,例如以太网采用的就是motorola字节序。同时cpu也有字节序的概念,在大端cpu中,0x12存放在第一个字节,对于intel,0x34放在第一个字节。
对于通信数据库来说, 小端字节序在排列时signal由lsb向msb靠近,并且lsb在前(即lsb所在的bit数字小),大端字节序意味着在排列时signal将由lsb开始计数,向msb增加,但msb在前 。
大端字节序:
7 6 5 4 3 2 1 0
0 msb<-----
1----lsb<
7
小端字节序:
7 6 5 4 3 2 1 0
0-------lsb<
1msb<---------
7
字节序的资料非常多,这里不再赘述。
2. Bit 位置计算
2.1 Startbit 和 length
Startbit 和 length如字面意思不再赘述,但需要注意的是在DBC中,如果signal是motorola格式,那么它的startbit实际是它的endbit,例如长度为 11 的一个signal:
7 6 5 4 3 2 1 0
0 >msb---
1---------lsb>
7
NOTE!
如果用CanDB++打开,这个signal的起始位置将会 显示 为bit9(只是显示,实际文本还是3)。
上面这个singal的起始位置直接打开DBC文本查看将会是msb 3(实际是lsb 9),尤其在解析DBC时要注意。
2.2 相关公式
- 将一个位的位序号从lsb0转换到msb0的位序号(或msb0到lsb0)
b = b - (b % 8) + 7 - (b % 8)
2. 在msb0下,由一个信号的msb位序号转化得到lsb位序号
b = b+length-1
3. 在msb0下,将一个信号的lsb位序号转化为msb位序号
b = b + 1 - length
2.3 公式示例
将2.1所示的signal的startbit 3转化为CanDb++中的9。
- 因为DBC是lsb0的bit numbering,而公式需要在msb0下操作,所以先得到msb0下startbit的序号
b = 3-(3%8)+7-(3%8) = 4
- 在msb0下由startbit即msb得到lsb在msb0下的序号
b = b+length-1=4+11-1 = 14
- 将msb0下的lsb序号转化为lsb0下的序号(因为DBC是lsb0)
b = 14-(14%8)+7-(14%8) = 9
3. Byte order转换
当Cpu和signal的字节序不一致时,解析方式不一致将会导致数据错误。所以要进行字节序的转化,所谓字节序的转化在底层软件来看无非就是 内存的字节换位 ,无论是uint16、uint32、uint64位的数据都可以用交换内存字节位置的方式来转换字节序。附上一段简单的C代码:
typedef unsigned char *pByteBuf_t;
LOCAL_INLINE void Lib_SwapByte(pByteBuf_t const byteF, pByteBuf_t const byteS)
uint8 byteTemp;
byteTemp = *byteF;
*byteF = *byteS;
*byteS = byteTemp;
LOCAL_INLINE void Lib_ChangeByteOrder(pByteBuf_t pByteBuf,uint8 SizeInByte)
uint8 u8Loop = 0U;
if(pByteBuf !=NULL_PTR)
for(u8Loop = 0U;u8Loop<SizeInByte/2U;u8Loop++)
Lib_SwapByte(&pByteBuf[u8Loop], &pByteBuf[(SizeInByte - 1U) - u8Loop]);
void Func(void)