CAN信号解析流程
1.车辆CAN对应dbc文件
DBC文件是一种用于描述CAN(Controller Area Network)数据通信协议的文件格式,DBC文件中包含了CAN数据的信号定义、编码方式、单位、范围等信息,可以用于解析和生成CAN数据帧。
一个DBC文件通常包含多个数据帧和信号定义,每个数据帧包含了一个或多个信号,每个信号描述了CAN数据的一个或多个位。
dbc文件一个数据包包含内容如下:
一个信号包含的有效内容:
Name | 信号名称 |
Startbit | 信号起始位 |
Length | 信号长度 |
Byte Order | 信号字节序(即大小端) |
Value Type | 信号数据类型 |
Factor | 信号倍率 |
Offset | 信号偏移量 |
Minimum | 信号最小值 |
Maximum | 信号最大值 |
2.解析步骤
信号解析公式:
实际值 = (十进制值 * Factor)+ Offset;
十进制值:接收的CAN数据包中,将信号对应的bit位长度取出,所对应的十进制数据值
解析步骤:
获取信号所需信息
判断数据是否需进行字节序转换
获取信号的十进制值
判断十进制值是否需要向有符号,浮点型转化
根据公式进行计算信号实际值
补充说明:二进制数据中,通常将最右边的位称为最低位(LSB),最左边的位称为最高位(MSB)。因此,在二进制数据中,bit0通常是指最右边的位,也就是最低位。
LSB的全称是"Least Significant Bit",:意为最低有效位;LSB位于二进制数的最右侧。数据位的最低位。
MSB的全称是"Most Significant Bit",:意为最高有效位。MSB位于二进制数的最左侧。数据位的最高位。CAN每个报⽂可包含8Byte的字节数据域,在报⽂内数据的字节序和位序如下:
字节序:Byte0、Byte1、Byte2、Byte3、Byte4、Byte5、Byte6、Byte7
位序:bit7、bit6、bit5、bit4、bit3、bit2、bit1、bit0。
3.解析精度说明
针对dbc信号不同类型信号解析的精度说明。
目前dbc信号数据类型有:
Unsigned | 需精度控制,数量占比85%以上 |
Signed | 需精度控制,数量占比10%左右 |
Double | 正常数据类型解析 |
Float | 正常数据类型解析 |
Unsigned、Signed需精度控制类型说明:
针对这两类的信号数据精度,可采用整形,浮点型。
针对这两类的信号数据精度要求浮点型,则有Float和Double如下考虑:
Float和Double同样是两种浮点数类型。其中Float占用4个字节(32位),Double占用8个字节(64位)。
在精度方面:Double类型的精度要比Float类型高。Double类型可以表示的范围更广,小数点后的位数也更多,因此可以更精确地表示小数。
在使用性能方面:由于Double类型占用的内存空间更大,因此在处理大量浮点数运算时,Double类型的计算速度会比Float类型慢。
推荐高性能计算使用:Float类型
推荐高精度计算使用:Double类型
4.示例
Signed类型解析:
接收数据包的值为:f4 fc 00 00 00 00 00 00 (此数据包为16进制)
1. 获取信号所需信息
{
"start_bit": 0,
"bit_length": 16,
"factor": 0.1,
"offset": 0,
}
2. 判断数据是否需进行字节序转换
考虑底层(mcu)是否统一发送格式,统一大端或者小端,请于底层进行确认!!
当前内容需进行大小端转换。
f4 fc 00 00 00 00 00 00 == 》》00 00 00 00 00 00 fc f4
3. 获取信号的十进制值
二进制数据中,通常将最右边的位称为最低位(LSB),最左边的位称为最高位(MSB)。因此,在二进制数据中,bit0通常是指最右边的位,也就是最低位。
将获取的数据转化为二进制;
根据:start_bit 以及 bit_length,从信号的 bit 0 位 开始,取出总长度为 16 的数据串,并且转化为十进制数据值。
4. Signed需要向有符号转化
此处需将无符号转化为有符号数据。
当前使用取反加1法进行转化,(此外还有符号位扩展法,补码表示法)
将十进制值 转化为 二进制 并且 进行取反加1法,再转化为十进制
即-780
5. 根据公式进行计算信号实际值
根据计算公式:即可得出 signal = (-780 * 0.1)+ 0.0 = -78.0
所以接收到 signal 数据值为 -78
Unsigned类型解析:
接收数据包的值为:cc 0c 00 00 00 00 00 00 (此数据包为16进制)
1. 获取信号所需信息
{
"start_bit": 1,
"bit_length": 15,
"factor": 0.01,
"offset": 0,
}
2. 判断数据是否需进行字节序转换
考虑底层(mcu)是否统一发送格式,统一大端或者小端,请于底层进行确认!!
当前内容需进行大小端转换。
cc 0c 00 00 00 00 00 00 ==》》00 00 00 00 00 00 0c cc
3. 获取信号的十进制值
二进制数据中,通常将最右边的位称为最低位(LSB),最左边的位称为最高位(MSB)。因此,在二进制数据中,bit0通常是指最右边的位,也就是最低位。
将获取的数据转化为二进制;
根据:start_bit 以及 bit_length,从信号的 bit 1位开始,取出总长度为 15 的数据串,并且转化为十进制数据值。
4. Unsigned不需要向有符号,浮点型转化,跳过。
5. 根据公式进行计算信号实际值
根据计算公式:即可得出 signal = (1638 * 0.01)+ 0.0 = 16.38
所以接收到 signal 数据值为16.38
Double、Float类型解析
Double、Float类型解析同Signed类型解析流程。
需要注意流程 4向有符号,浮点型转化,这块步骤有所差异,请注意。
类型转化说明
64756(十进制) 向有符号转化 : 二进制取反加1 ==》-780
64756(十进制) 向有浮点转化 :???待补充
C++编码解析
流程3:
uint64_t jiexi_fun(
uint16_t startbit, uint8_t length, const uint8_t *rawdata, std::string endian) {
uint64_t data{0};
uint8_t lsbbit = startbit % 8;
uint8_t lsbbyte = startbit / 8;
if (endian == "Motorola") {
uint8_t msbbyte = lsbbyte - (lsbbit + length - 1) / 8;
for (int i{msbbyte}; i < lsbbyte + 1; i++) {
data+= ((uint64_t)rawdata[i]) << ((lsbbyte - i) * 8);
}
} else {
uint8_t msbbyte = (startbit + length - 1) / 8;
for (int i{msbbyte}; i >= lsbbyte; i--) {
data += (((uint64_t)rawdata[i]) << (i - lsbbyte) * 8);
}
}
data= data>> lsbbit;
data <<= (64 - length);
data >>= (64 - length);
return data;
}