一、CAN Message格式
CAN报文帧包含5种类型的帧,数据帧、远程帧、错误帧、过载帧和帧间隔。
在CAN报文的总线传输过程中,不同类型的帧具有不同的功能。
数据帧: 用作节点之间收发数据,是使用最多的帧类型。
远程帧: 接收节点向具有相同ID的发送节点请求数据的帧。
错误帧: 任何节点检测到错误时就会发送错误帧,通知其他节点。
过载帧: 用于延迟下一个信息帧的发送。
帧间隔: 用于将数据帧及远程帧与前面的帧分离开来的帧。
不同类型的帧具有不同的格式,以最常用的数据帧为例,CAN总线的数据帧有标准格式(StandardFormat)和扩展格式(ExtendedFormat)两种格式。
数据帧可以分为七段:
- 帧起始(SOF)
标识一个数据帧的开始,固定一个显性位。
用于同步, 总线空闲期间的任何隐性到显性的跳变都将引起节点进行 硬同步。只有总线在空闲期间节点才能够发送SOF。 - 仲裁段(Arbitration Field)
仲裁段的内容主要为本数据帧的ID信息。数据帧分为标准格式和扩展格式两种,区别就在于ID信息的长度:标准格式的ID为11位;扩展格式为29位。在CAN协议中,ID决定着数据帧发送的优先级,也决定着其他设备是否会接收这个数据帧。
仲裁段除了报文ID外,还有RTR, IDE, SRR位。RTR位为远程传输请求位,判断帧的类型为数据帧还是远程帧。(数据帧为显性电平,逻辑0;远程帧为隐性电平,逻辑为1。)IDE为扩展帧标志位,标准帧中为0,扩展帧为1。 - 控制段
在控制段,r1(reserved1)和r0(reserved0)为保留位,默认设置为显性位。最主要的是DLC(Data Length Code)段,它是用二进制编码表示本报文中的数据段包含多少个字节。DLC段由4位组成,DLC3−DLC0,表示的数字为0-8。 - 数据段
由数据帧中被发送的数据组成,有0-8个字节长度,由DLC确定,远程帧时无效。 - CRC段
CAN总线使用CRC校验进行数据检错,CRC校验值存放于CRC段。CRC校验段由15位CRC值和1位CRC界定符构成。由帧起始、仲裁段、控制段、数据段构成的多项式经过一定的规则计算后发送至总线的CRC序列。接受端接收数据时,按照同样的规则对所接收的数据进行CRC计算,然后两个CRC序列进行比较,以判定数据是否出错。在CRC校验码之后,有一个CRC界定符,它为隐性位,主要作用是把CRC校验码与后面的ACK段隔开。 - ACK段
ACK段包含确认位(ACK slot)和界定符(Delimiter,
DEL)。在ACK段中发送站送出两个隐性位。一个正确接收到有效报文的接收器在ACK槽期间,将此消息通过一个显性位报告给发送器。所有接收到匹配CRC序列的站通过在ACK槽内把隐性位写入发送器的隐性位来报告。界定符必须是隐性位。 - 帧结束段(End-of-Frame, EOF)
帧结束段由发送端发送7个隐性位表示结束。
以0x135报文为例,其标准帧格式的构成如下:
了解了数据帧的结构之后,我们再去看在simulink中是如何定义一个数据帧格式报文进行CAN通信的。
二、simulink中创建CAN报文总线
在simulink中接收到一个CAN报文作为输入,只需要创建一个Input端口,将其信号属性页面的数据类型改为总线对象即可。
然而Simulink中并没有内置总线类型,所以需要我们自己定义,Matlab提供了创建Simulink CAN 报文总线的函数canMessageBusType,我们可以使用这个函数创建simulink总线对象。
2.1 canMessageBusType用法
不带参数canMessageBusType
在基础工作区中创建名为 CAN_MESSAGE_BUS 的 Simulink CAN 报文总线对象。
带参数canMessageBusType(modelName)
在与指定模型 modelName 关联的数据字典中创建类型为 CAN_MESSAGE_BUS 的 Simulink CAN 报文总线对象。(建议使用)
2.2 创建CAN_MESSAGE_BUS
1. 在模型资源管理器中创建外部数据字典
2. 在matlab命令行使用canMessageBusType(modelName)函数在字典中创建CAN_MESSAGE_BUS 。
在总线编辑器中可以看到总线对象中包含的元素。
Extended — CAN 报文的标识符类型,标准类型或扩展类型。
Length — CAN 报文的长度(以字节为单位),指定为 uint8 值。
Remote — 指定 CAN 报文是否为远程帧。
Error — CAN 报文错误帧指示符。指示当前 CAN 报文是否为错误帧。
ID — CAN 报文的标识符。
Timestamp — 收到报文的时间。
Data — CAN 报文数据。
支持用户构造的报文类型就两类,数据帧和远程帧,其他类型的帧都是由总线协议根据总线传输状态控制生成,且具有固定的格式。如错误帧由错误标志(Error Flag)和错误界定符(Error Delimiter)组成。帧间隔由间隔段、延迟传输段和总线空闲段构成。可以看到,Matalb构造的报文总线对象,配置了报文的标识符类型,报文长度等属性。通过这些属性判断来判断总线上来的报文类型并存储报文信息。
三、构造总线输入数据进行调试仿真
我们通过canMessageBusType函数构造总线类型输入(Input)来作为我们模型的总线类型数据输入,那么如何在调试仿真时构造总线类型输入实例呢?有两种方法。
3.1 通过Bus Creator 模块与Bus Selector 模块构造总线输入
根据Matlab文档的说明,Bus Creator 模块可将一组输入元素合并成一条总线。您可以将任何元素类型连接到输入端口,包括其他总线。您可以使用 Bus Selector 模块访问总线中的元素。
总线元素必须具有唯一名称。默认情况下,总线的每个元素都继承连接到 Bus Creator 模块的元素的名称。如果存在重复名称,Bus Creator 模块会将端口号追加到所有输入元素名称。
输入: 包含在总线中的各种元素。这里我们构建simulink中标准格式的CAN报文数据帧,包含Extended、Length、Remote、Error 、ID 、Timestamp 、Data7个元素。
输出: Bus: CAN_MESSAGE_BUS类型总线
① 创建一个Bus Creator 模块,输入数目改为7,输出数据类型选择自己定义的总线类型Bus: CAN_MESSAGE_BUS。取消勾选【使用来自输入的名称,而不是来自总线对象的名称】,我们使用总线对象的名称。勾选【以非虚拟总线输出】,选择以非虚拟总线输出才能使仿真和代码生成应用由 Bus 对象定义的结构体。当总线为虚拟总线时,Bus 对象将仅验证总线的属性。不同的总线类型在生成代码的效率、大小和可读性方面可能存在显著差异。要使总线出现在生成的代码中,它必须为非虚拟总线。
② 创建总线中的元素,修改各个常量值的数据类型为对应元素数据类型,ID为uint32,Timestamp为double,Data应为uint8类型的[1x8]数组。然后与Bus Creator输入端口连接,双击信号线,输入对应元素名称。
③ 创建一个Bus Selector 模块,连接到Bus Creator 模块的输出,在模块参数设置中将左侧候选框中的Data选择到右侧。
最后连接上显示模块,如图所示。使用Bus Selector 模块将总线中需要的元素提取出来。
3.2 通过CAN Pack模块构造总线输入
CAN Pack模块有三种数据输入方式,通过 Data is input as 框选择。
raw data 即CAN报文的8字节数据,可用MUX模块合并各个信号输入。
manually specified signals 模块内手工配置报文格式,模块外输入原始信号。
CANdb specified signals 通过外部导入DBC文件的方式,将信号打包成CAN报文。
外部导入DBC文件方式可参考:
https://blog.csdn.net/weixin_40531919/article/details/135021229
CAN pack模块只需配置数据段中的内容,即Data中的数据。勾选【Output as bus】,将信号打包成为标准CAN_MESSAGE_BUS类型。后可接Bus Selector 模块提取总线中的元素。
四、总结
在simulink中构建CAN报文总线结构数据是为了满足生成代码的需要,在进行CAN报文相关模型仿真时,常常报文中各个CAN信号数据结构是已知的,在建立总线数据类型非必要时,仿真时不必建立完整的CAN报文总线数据,可以直接将数据通过Bus Creator以虚拟总线输出,在仿真和生成代码中,虚拟信号可以直接访问元素,因此比非虚拟信号的执行速度更快。