本文转载在我的微信公众号:古德曼汽车工业。
希望关注本专栏的朋友,也能一并关注微信公众号。
友情提示:本期内容讨论的内容有烧脑,请大家做好心理准备。【思想】隐隐感觉本文观看人数会是新低。
1.什么是字节
使用CANdb++ Editor的小伙伴们肯定会注意到创建报文的时候有一个ByterOrder让我们选Intel或Motorola。
这个问题在编程中叫做字节序问题,用来描述一个多字节数据【FLOAT/INT/结构体】是高字节在前还是低字节在前。假设一个使用16进制表示的32位数据0x12345678,需要将这个数据存放在内存地址从0x8000起的四个内存空间中
在低位的内存地址存放高有效字节的模式称为:大端序(big endian)
在低位的内存地址存放低有效字节的模式称为:小端序(little endian)
这个问题的由来牵涉到两大CPU门派,Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而Intel的x86系列则采用little endian方式存储数据。也是DBC Editor++为什么使用Motorola/Intel来表述这个问题。如果看完上述内容还在蒙圈的小伙伴我推荐下《总线架构29讲,一文彻底讲清CAN总线的intel和Motorola编码》,我相信同样的知识经不同人的表述会有不一样的传递效果。
2.字节序对嵌入式CAN总线通讯的影响
由于集成电路处理小端序的效率比较高,所以大部分嵌入式芯片都采用小端序,这对CAN报文矩阵读取有不小的影响。在《CAN总线(J1939)速成指南【1】》介绍了总线数据帧的结构中有一个8字节组成的数据域。报文数据通过单片机的CAN接收中断函数获取,将数据存放对应的协议栈的数据数组中,通过共同体读取对应的数据,具体如何操作请温习下《嵌入式C语言环境下的CAN总线通讯协议》
无影响的完美矩阵
如果8字节的数据与只用来传输以1字节对齐的1字节数据,如下图
这样的报文矩阵非常整齐,每一个字节就对应一个字节的有效数据,这种情况是不会受到字节序问题的影响,直接通过共同体访问数据即可。
稍微有点复杂
实际应用过程中像上面这种极端完美的结构式非常少见的,更多的是报文中会有16位或32位的数据类型,如下图
这样的结构存在8位、16位、32位的数据类型,但是数据都以1字节对齐。遇到这样的报文不能通过共同体直接访问。例如:需要把1、2字节放入一个16位的内存空间来表示UINT16的数据,这里就会收到字节序的影响。处理这个问题最简单的办法就是接收数据后,调整报文数组的帧顺序。
基于小端序的原则,将1、2字节对调,3、7字节对调并且4、5字节对调,调整过帧顺序后就能通过共同体变量进行数据访问。
令人头疼的
《嵌入式C语言环境下的CAN总线通讯协议》也介绍过了实际开发中的报文矩阵可能更复杂,存在空位、数据长度也不是常见的8位、16位、32位、又不以1字节对齐,如下图:
该例子为之前《嵌入式C语言环境下的CAN总线通讯协议》使用的例子,这里我们就以1字节对齐划分最小的数据BLOCK,每个BLOCK的位长度均为8的整数倍。
将0、1字节看作一个Block,将0、1字节进行对调;将2、3、4字节看作一个Block,将2、4字节进行对调,调整过帧顺序后就能通过共同体变量进行数据访问。
3.实际操作问
实际工程中CAN总线协议报文会非常多,如果仅仅靠人工一个一个调整报文顺序,首先时间成本就会很高,更可怕的是这样会增加误操作的概率,会给后面的开发造成非常【不可思议】的问题。因为高低字节反了,解析出来的数据自然也会有很大的问题。幸亏懒惰是第一生产力,这种操作通常需要运用自动化工具解决,这里分享下【思想】自制偷懒工具的思路。
首先需要能够解析dbc文件,读取报文的id,设置报文周期
解析报文矩阵,同时对dbc文件中不存在的空位进行填补,使之成为完整的Block
生成结构体数据的同时,对Block进行划分,这一步主要是为了后面调试核对方便
上图中未被模糊的部分就是自动化工具根据划分的Block结果自动生成的报文数组顺序调整的代码。
-----=========推荐阅读==========-----