本文研究CAN Pack模块的用法和该模块生成的代码。涉及到一些dbc文件查看和编辑的内容,需要从Vector官网下载一个CANdb++ Editor软件。
1 Simulink中的CAN Pack模块
在汽车ECU软件开发中,一般是ASW软件将Signal打包成Message后,然后由BSW实现CAN的发送功能。想要打包Signal,就必须首先知道单个Signal在整个Message中的布局(Layout),可以从DBC文件中获取描述信息。
通过DBC文件知道了Signal和Message之间的关系后,就需要通过代码或者模型实现打包的过程。CAN Pack模块就为我们封装好了从Signal打包成Message。
CAN Pack模块如下图所示,输入端接的是Signal,输出端输出了打包好的Message。
2 CAN Pack模块的建模与仿真
本章节会用dbc文件来配置CAN Pack模块,并讨论各个配置参数和仿真结果之间的关系。
2.1 在模块中配置DBC文件
1)首先在matlab根路径下找一个dbc文件demoVNT_CANdbFiles.dbc,作为后文仿真用的原材料。
将这个dbc文件与模型拷贝到同一个路径下。
2)在模型中新建一个CAN Pack模块,将Data is input as下拉框选择为CANdb,表示用一个DBC文件中的参数来打包Signal;将下面的CANdb file文本框设置为上一步的dbc名称;勾选下面的Output as bus。
3)做完上述配置后,这个模块就自动从DBC中识别出其中的Message list。
4)然后选其中一个Message,例如下图中的WindowControlMsg,就会在下面的Signal一栏中切换成这个Message中包含的所有Signal,以及Signal属性。
通过CANdb++打开这个dbc文件demoVNT_CANdbFiles.dbc,查看属性信息,这些属性是完全一致的。说明CAN Pack解析好了dbc文件,也就配置功能了。
5)点击OK保存模块配置,在模型中,模块就变成了两个输入端口,分别对应了这个Message中的两个信号。
输出的CAN Msg是一个Bus信号,其中的Data和ID是比较重要的。后文会重点研究Message的Data和输入之间的关系。
2.2 CAN Pack模块仿真
基于2.1节中的配置,可以尝试用这个模块进行仿真。如果修改了dbc文件,那么模块的输出结果会有所不同。
2.2.1 仿真1:初始配置
1)首先,不对DBC文件做修改的情况下,WindowControlMsg中的两个Signal的布局是这样的。
PassengerDoorWindow信号的起始位(startbit)是0,长度(length)是8,因此占据了Message的第0行。DriverDoorWindow信号的起始位(startbit)是8,长度(length)是8,因此占据了Message的第1行。他们的数值范围都是是0~255,Factor和offset是1和0,也就是说从原始值到物理值,不会进行放大和偏移转换,也没有跨行的复杂情况。
2)在模型中,将PassengerDoorWindow输入为常量128,DriverDoorWindow输入常量为25。然后仿真,就会看到输出结果的Data[0]和Data[1]分别为128和25。也就是说,将PassengerDoorWindow和DriverDoorWindow打包到了Message的Data[0]和Data[1]中。
由于DBC中对这个Message的配置,仿真1是一种简单、特殊的情况,所以打包的过程非常简单,就直接把两个Signal放到了Message的前两行。后面博主会手动修改demoVNT_CANdbFiles.dbc的配置信息并进行仿真,研究一下属性更复杂的情况下,会仿真出什么结果。
2.2.2 仿真2:factor&offset属性
在打包的过程中,可以通过factor&offset属性做一个放大和偏移,公式如下:
raw_value = (physical_value - Offset) / Factor
- 1
那么为什么要做这个转化呢?假设一种情况,如果Signal的物理值范围是 -10–>10,精度是0.1,那该怎么在Message中表示出来呢?有一种办法就是先将这个物理值加上10(offset=-10),再乘以10(factor=0.1),那么-10–>10的范围就会扩大到0–>200,在Message中就可以用8个bit的长度来表示了。下面就可以验证一下这个属性。
1)打开DBC文件,将PassengerDoorWindow的Factor设为0.1,Offset设为-10,Minimum设为-10,Maximum设为10,其他的属性不变,并保存。
2)在CAN Pack模块中重新选一下dbc文件。
3)在模型中,将PassengerDoorWindow输入为常量-4.5,仿真得出结果如下。打包后的Data[0]输出为55.
从-4.5的物理值到55的原始值,就是经历了一个factor&offset公式转换。首先-4.5减去offset(-10),得出5.5;然后5.5除以factor(0.1)得出55;最后根据startbit和length,将转换过后的原始值55打包进了Data[0]。
2.2.3 仿真3:Value Type属性
Value Type属性表示打包进Message的时候的类型选择。在仿真1中的默认项是Unsigned。博主在工作中只遇到过Unsigned和Signed两种Value Type属性,所以这一章节研究一下Value Type属性为Signed时,是怎么打包Message的。
1)在仿真1的原始DBC基础上,将PassengerDoorWindow的Length属性设为7,Value Type属性设为Signed,Minimum设为-64,Maximum设为63,其他的属性不变。这样设置表示,用7个bit来描述有符号数,可以描述从-64到63.
2)在CAN Pack模块中重新选一下dbc文件。
3)在模型中,将PassengerDoorWindow输入为常量30,仿真得出结果如下。打包后的Data[0]输出为30。
说明0~63的正整数是按照原来的数值打包进Message Data的。
4)在模型中,将PassengerDoorWindow输入为常量-30,仿真得出结果如下。打包后的Data[0]输出为98。
这个计算过程很简单,在dbc文件中把Length属性设置为7,也就是用7个bit来表示正整数和负整数,前一半用于表示正数,后一半用于表示负数。后一半的计算过程是
Data[0] = 2^Length + PassengerDoorWindow = 128 + (-30) = 98
- 1
所以,如果输入的PassengerDoorWindow是-15,那么Data[0]会输出113。另外,本节的Value Type属性和上一节的factor&offset属性都可以用来表示正负数,但是实际工作中,博主觉得factor&offset属性比较灵活一点,在代码中有更好的统一性。
2.2.4 仿真4:Byte Order属性–Intel格式
Btye Order属性表示打包Message时的字节顺序,分为Intel和Motorola两种。在仿真1,2,3中,信号在Message中的排布方式都是仅占据一行的。当一个Signal跨越多行的时候,Byte Order属性就会决定打包时候的顺序,具体区别如下:
- Intel格式:Signal的低位存放在Message的低位,Signal的高位存放在Message的高位。
- Motorola格式:Signal的低位存放在Message的高位,Signal的高位存放在Message的低位。
用文字概念表述不容易理解,但是通过Simulink的CAN Pack模块,就可以轻松理解Byte Order属性的含义。
下面就会通过仿真来理解Intel格式的Byte Order属性。
1)在仿真1的原始DBC基础上,将DriverDoorWindow的Startbit改成20,Length保持为8,Byte Order保持为Intel,然后点击应用。
2)双击WindowControlMsg,切换到Layout选项卡,可以看到DriverDoorWindow信号在Message中的布局。
DriverDoorWindow转换成2进制后,由于是Intel格式,低4位放在了Message的第20号到23号中;高4位放在了Message的24号到27号中。
3)在CAN Pack模块中重新选一下dbc文件。
4)在模型中,将DriverDoorWindow输入为常量100,仿真得出结果如下。打包后的Data[2]输出为64,Data[3]输出为6。
移位的过程可以按照如下方式推算。
首先将100转为2进制,就是0110 0100。所以DriverDoorWindow的低4位是0100,高4位是0110。
根据第2步中的关系,DriverDoorWindow的低4位要放在Message的20号到23号,也就是Data[2]的高4位,所以要将0000 0100左移4位,得到01000000,再转为10进制就是64了,也就是仿真输出的Data[2]。
同理,DriverDoorWindow的高4位要放在Message的24号到27号,也就是Data[3]的低4位,所以将01100000右移4位,得到00000110,再转为10进制就是6,所以Data[3]输出的值就是6。
2.2.5 仿真5:Byte Order属性–Motorola格式
下面就会通过仿真来理解Motorola格式的Byte Order属性。
1)在仿真1的原始DBC基础上,将DriverDoorWindow的Startbit改成20,Length保持为8,Byte Order保持为Motorola,然后点击应用。
2)双击WindowControlMsg,切换到Layout选项卡,可以看到DriverDoorWindow信号在Message中的布局。
这里的Layout中就可以看出和仿真4中是不同的。在Motorola格式的时候,低4位放在了Message的第20号到23号中;高4位放在了Message的8号到1号中。
3)在CAN Pack模块中重新选一下dbc文件。
4)在模型中,将DriverDoorWindow输入为常量100,仿真得出结果如下。打包后的Data[2]输出为64,Data[1]输出为6。
移位的过程也可以按照仿真4中相同的方法推算,这里再重新算一次。
首先将100转为2进制,就是0110 0100。所以DriverDoorWindow的低4位是0100,高4位是0110。
根据第2步中的关系,DriverDoorWindow的低4位要放在Message的20号到23号,也就是Data[2]的高4位,所以要将0000 0100左移4位,得到0100 0000,再转为10进制就是64了,也就是仿真输出的Data[2]。这一点和仿真4是相同的。
不同的是,DriverDoorWindow的高4位要放在Message的8号到11号,也就是Data[1]的低4位,所以将0110 0000右移4位,得到0000 0110,再转为10进制就是6,所以Data[1]输出的值就是6。
3 CAN Pack模块的代码生成
在第2章中仿真得到了正确的结果,但是在实际工作中需要通过代码来实现打包Signal的功能。如果手写过CAN打包的C代码,过程十分的繁琐也很容易出错。好在CAN Pack模块是支持生成代码的,所以本章节将这个模块生成代码。
1)在仿真模型的基础上,把输入的常数模块和输出的Disp模块替换成Inport和Outport。
2)配置好离散求解器和Embedded Coder文件,可以参照博主以前的博客。
3)Ctrl + B生成代码。
很简单的一个CAN Pack模块生成了200多行代码,只为了把两个Signal打包到一个Message中。其中所用的算法中,使用了大量的移位运算。另外,为了通用性,还出现了很多左移右移0位的代码。
所以就不建议仔细阅读这一段代码了,直接拿去编译就行。
4 总结
本文研究了Simulink中的CAN Pack模块的仿真和代码生成。与之相对的还有CAN Unpack模块,可以将一个Message中的信号解析出来。其用法思路就是把CAN Pack倒过来,可以举一反三。
评论记录:
回复评论: