之前已经讲过如何生成DBC文件了,程序中该如何解析DBC呢?
其中包括接收CAN报文解析和发送CAN报文组包??
一、Motorola和Intel格式
dbc里的信号Signals,其中里面有两种数据格式 Motorola和Intel格式。
之前C语言里,讲过无数遍的大小端,排上用场了。
参看:C语言再学习-- 大端小端详解(转)
举个例子,比如数字 0x12 34 56 78在内存中的表示形式为:
1)大端模式:
低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
2)小端模式:
低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
MSB和LSB:
MSB: MoST Significant Bit ------- 最高有效位
LSB: Least Significant Bit ------- 最低有效位
先看一下,Motorola和Intel格式的区别。
Intel 格式 layout:
Motorola 格式 layout:
关于CAN报文,用Motorola,还是Intel格式,只在信号数据跨字节解析时,才有区别。单个字节数据没有区别。
当信号在一个字节内实现(信号不跨字节)时,Intel模式和Motorola模式的信号字节顺序,完全一样:
信号的高位(MSB)放在该字节的高位,信号的低位(LSB)放在该字节的低位。
如果是信号数据跨字节解析,才有区别。
Motorola格式即大端,信号的高位(MSB)放在低字节的高位,信号的低位(LSB)放在高字节的低位。反映到矩阵图中就是以起始位为原点,自下而上填充。Motorola格式,MSB在LSB上面。
Intel格式即小端,信号的高位(MSB)放在高字节的高位,信号的低位(LSB)放在低字节的低位;,反映到矩阵图中就是以起始位为原点,自上而下填充。Intel格式,MSB在LSB下面。
总结就一句话:
Intel格式(小端模式 ): “高位在后,低位在前”;
Motorola格式(大端模式): “高位在前,低位在后”。
解析报文和接收报文都是分为两种方式的,一种是使用位操作、一种是使用位域。
二、CAN接收报文解析
1、Intel格式 CAN接收报文解析
VehLength = ((((uint32_t)paraData[1] & 0x07) << 8)
| ((uint32_t)paraData[0]));
VehWidth = ((((uint32_t)paraData[1] & 0xF8) >> 3)
| (((uint32_t)paraData[2] & 0x0F) << 5));
VehWheelBase = ((((uint32_t)paraData[2] & 0xF0) >> 4)
| (((uint32_t)paraData[3] & 0x7F) << 4));
VehRearOverhang = ((((uint32_t)paraData[3] & 0x80) >> 7)
| (((uint32_t)paraData[4]) << 1)
| (((uint32_t)paraData[5] & 0x01) << 9));
VehLeftToSRR = ((((uint32_t)paraData[5] & 0xFE) >> 1)
| (((uint32_t)paraData[6] & 0x0F) << 7));
VehInstallAngle = ((((uint32_t)paraData[6] & 0xF0) >> 4)
| (((uint32_t)paraData[7] & 0x1F) << 4));
2、Motorola格式 CAN接收报文解析
tmp_VehicleSpdUint = ((((uint16_t)paraData[1])&0x01) << 14) + ((((uint16_t)paraData[2])&0xFF) << 6) + (((uint16_t)paraData[3]) >> 2);
3、最后,乘以factor加上offset
tmpYawRateF = (((float)tmpYawRateU) * 0.01f) - 81.91f;
三、CAN发送报文组包
1、首先,减去offset除以factor
tmpYawRateF = (((uint16_t)tmpYawRateU) +81.91) /0.01;
2、Intel格式 CAN发送报文组包
messageBuffer[0] |= (uint8_t)(CIPVVehPara.VehLength & 0x00FF);
messageBuffer[1] |= (uint8_t)((CIPVVehPara.VehLength & 0x0700) >> 8);
messageBuffer[1] |= (uint8_t)((CIPVVehPara.VehWidth & 0x001F) << 3);
messageBuffer[2] |= (uint8_t)((CIPVVehPara.VehWidth & 0x01E0) >> 5);
messageBuffer[2] |= (uint8_t)((CIPVVehPara.VehWheelBase & 0x000F) << 4);
messageBuffer[3] |= (uint8_t)((CIPVVehPara.VehWheelBase & 0x07F0) >> 4);
messageBuffer[3] |= (uint8_t)((CIPVVehPara.VehRearOverhang & 0x0001) << 7);
messageBuffer[4] |= (uint8_t)((CIPVVehPara.VehRearOverhang & 0x01FE) >> 1);
messageBuffer[5] |= (uint8_t)((CIPVVehPara.VehRearOverhang & 0x0200) >> 9);
messageBuffer[5] |= (uint8_t)((CIPVVehPara.VehLeftToSRR & 0x007F) << 1);
messageBuffer[6] |= (uint8_t)((CIPVVehPara.VehLeftToSRR & 0x0780) >> 7);
messageBuffer[6] |= (uint8_t)(((CIPVVehPara.VehInstallAngle+VEH_INSTALL_ANGLE_OFFSET) & 0x000F) << 4);
messageBuffer[7] |= (uint8_t)(((CIPVVehPara.VehInstallAngle+VEH_INSTALL_ANGLE_OFFSET) & 0x01F0) >> 4);
3、Motorola格式 CAN发送报文组包
messageBuffer[0] |= (uint8_t)((POS_X & 0x7F80) >> 7);
messageBuffer[1] |= (uint8_t)((POS_X & 0x007F) << 1);
messageBuffer[1] |= (uint8_t)((POS_Y & 0x4000) >> 14);
messageBuffer[2] |= (uint8_t)((POS_Y & 0x3FC0) >> 6);
messageBuffer[3] |= (uint8_t)((POS_Y & 0x003F) << 2);
messageBuffer[3] |= (uint8_t)((SPD_X & 0x0C00) >> 10);
messageBuffer[4] |= (uint8_t)((SPD_X & 0x03FC) >> 2);
messageBuffer[5] |= (uint8_t)((SPD_X & 0x0003) << 6);
messageBuffer[5] |= (uint8_t)((SPD_Y & 0x3F00) >> 8);
messageBuffer[6] |= (uint8_t)(SPD_Y & 0x00FF);
messageBuffer[7] |= (uint8_t)((TargetMovingFlag & 0x01) << 7);
messageBuffer[7] |= (uint8_t)(gFrameOrder & 0x7F);