Simulink 中基于事件的 CAN 报文传输行为
此示例说明如何在配备了 Vehicle Network Toolbox™ 的 Simulink® 中使用基于事件的 CAN 报文传输。此功能允许在检测到一个时间步到下一个时间步的数据更改时进行 CAN 和 CAN FD 报文传输。
CAN 和 CAN FD Transmit 模块上可用的配置选项支持在数据发生更改时进行报文传输。当启用时,特定 CAN ID 的报文仅在该 ID 的数据发生更改时传输。每个报文根据其 ID 在每个时间步中独立处理。当禁用时,模块和周期性传输操作正常运行。此外,基于事件的传输还可与周期性传输一起启用,两者同时工作。
准备示例模型
包含的示例模型包括两个 CAN Pack 模块,两者配置为连入一个 CAN Transmit 模块。一条报文的数据是一个常量,而另一条报文的数据是在每个时间步都会更改的计数器。
打开示例模型。
open EventTransmit
准备 CAN 数据库文件访问
您可以使用 canDatabase
函数访问 CAN DBC 文件的内容。通过此函数,可以获得关于网络节点、报文和信号的详细信息。此 DBC 文件在模型中使用,用于解码从模型发送的信息。
db = canDatabase("CANBusEvent.dbc")
db = Database with properties: Name: 'CANBusEvent' Path: 'C:\Users\jpyle\Documents\MATLAB\ExampleManager\jpyle.21bExampleBlitz\vnt-ex59902587\CANBusEvent.dbc' Nodes: {'ECU'} NodeInfo: [1×1 struct] Messages: {2×1 cell} MessageInfo: [2×1 struct] Attributes: {} AttributeInfo: [0×0 struct] UserData: []
测试节点在 DBC 文件中定义。
node = nodeInfo(db,"ECU")
node = struct with fields:
Name: 'ECU'
Comment: ''
Attributes: {}
AttributeInfo: [0×0 struct]
该节点传输两条 CAN 报文。
messageInfo(db,"Constant_Msg")
ans = struct with fields:
Name: 'Constant_Msg'
ProtocolMode: 'CAN'
Comment: ''
ID: 10
Extended: 0
J1939: []
Length: 4
DLC: 4
BRS: 0
Signals: {'Constant'}
SignalInfo: [1×1 struct]
TxNodes: {'ECU'}
Attributes: {}
AttributeInfo: [0×0 struct]
messageInfo(db,"Counter_Msg")
ans = struct with fields:
Name: 'Counter_Msg'
ProtocolMode: 'CAN'
Comment: ''
ID: 20
Extended: 0
J1939: []
Length: 4
DLC: 4
BRS: 0
Signals: {'Counter'}
SignalInfo: [1×1 struct]
TxNodes: {'ECU'}
Attributes: {}
AttributeInfo: [0×0 struct]
使用基于事件的传输执行模型
仅启用基于事件的传输
以编程方式在 CAN Transmit 模块中启用基于事件的传输。此外,禁用周期性传输。
db = canDatabase("CANBusEvent.dbc")
db = Database with properties: Name: 'CANBusEvent' Path: 'C:\Users\jpyle\Documents\MATLAB\ExampleManager\jpyle.21bExampleBlitz\vnt-ex59902587\CANBusEvent.dbc' Nodes: {'ECU'} NodeInfo: [1×1 struct] Messages: {2×1 cell} MessageInfo: [2×1 struct] Attributes: {} AttributeInfo: [0×0 struct] UserData: []
set_param('EventTransmit/CAN Transmit', 'EnableEventTransmit', 'on'); set_param('EventTransmit/CAN Transmit', 'EnablePeriodicTransmit', 'off');
请注意,在应用设置后,模块显示会发生变化。
在 MATLAB 中配置 CAN 通道以与模型通信
使用虚拟设备通信创建一个与 Simulink 模型对接的 CAN 通道。此外,将 CAN 数据库连接到它,以自动解码传入报文。
canCh = canChannel("Mathworks","Virtual 1",2)
canCh = Channel with properties: Device Information DeviceVendor: 'MathWorks' Device: 'Virtual 1' DeviceChannelIndex: 2 DeviceSerialNumber: 0 ProtocolMode: 'CAN' Status Information Running: 0 MessagesAvailable: 0 MessagesReceived: 0 MessagesTransmitted: 0 InitializationAccess: 1 InitialTimestamp: [0×0 datetime] FilterHistory: 'Standard ID Filter: Allow All | Extended ID Filter: Allow All' Channel Information BusStatus: 'N/A' SilentMode: 0 TransceiverName: 'N/A' TransceiverState: 'N/A' ReceiveErrorCount: 0 TransmitErrorCount: 0 BusSpeed: 500000 SJW: [] TSEG1: [] TSEG2: [] NumOfSamples: [] Other Information Database: [] UserData: []
canCh.Database = db;
启动 CAN 通道以联网。
start(canCh);
运行模型
分配仿真运行时间并启动模型。
t = "10"; set_param("EventTransmit","StopTime",t) set_param("EventTransmit","SimulationCommand","start");
等到仿真开始。
while strcmp(get_param("EventTransmit","SimulationStatus"),"stopped") end
等到仿真结束。
pause(2)
在 MATLAB 中接收报文
从总线中接收模型生成的所有报文。
msg = receive(canCh,inf,"OutputFormat","timetable")
msg=12×8 timetable
Time ID Extended Name Data Length Signals Error Remote
__________ __ ________ ________________ ____________ ______ ____________ _____ ______
5.204 sec 10 false {'Constant_Msg'} {[ 5 0 0 0]} 4 {1×1 struct} false false
5.204 sec 20 false {'Counter_Msg' } {[ 0 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 1 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 2 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 3 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 4 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 5 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 6 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 7 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 8 0 0 0]} 4 {1×1 struct} false false
5.206 sec 20 false {'Counter_Msg' } {[ 9 0 0 0]} 4 {1×1 struct} false false
5.2061 sec 20 false {'Counter_Msg' } {[10 0 0 0]} 4 {1×1 struct} false false
在 MATLAB® 中停止 CAN 通道。
stop(canCh);
探查收到的报文和信号数据
已接收到 CAN ID 的次数如下图所示。报文“Constant_Msg”(CAN ID 10) 只接收到一次,因为其数据在初始设置后未更改。报文“Counter_Msg”(CAN ID 20) 在每个时间步都接收到,因为其数据在模型运行期间不断更改。
% Define X and Y axis. x = 1:length(msg.ID); y = msg.ID; % Plot the graph for both the CAN IDs received. stem(x,y,'filled') hold on; yMax = max(msg.ID)+5; ylim([0 yMax]) % Label the graph. xlabel("Number of CAN messages"); ylabel("CAN ID"); legend("CAN ID","Location","northeast"); legend("boxoff"); hold off;
接下来,绘制在同一仿真运行期间每个报文中接收到的信号。
% Create a structure with signal details. signalTimeTable = canSignalTimetable(msg); % Plot the signal values of "Constant_Msg". x1 = 1:height(signalTimeTable.Constant_Msg); y1 = signalTimeTable.Constant_Msg.Constant; plot(x1, y1,"Marker","o"); hold on % Plot the signal values of "Counter_Msg". x2 = 1:height(signalTimeTable.Counter_Msg); y2 = signalTimeTable.Counter_Msg.Counter; plot(x2, y2,"Marker","o"); % Determine the maximum value for y-axis for scaling of graph. y1Max = max(signalTimeTable.Constant_Msg.Constant); y2Max = max(signalTimeTable.Counter_Msg.Counter); yMax = max(y1Max,y2Max)+5; ylim([0 yMax]); % Label the graph. xlabel("Number of Times Signals Received"); ylabel("CAN Signal Value"); legend("Constant","Counter","Location","northeastoutside"); legend("boxoff"); hold off
信号“Constant”(在报文“Constant_Msg”中)只绘制一次,而信号“Counter”(在报文“Counter_Msg”中)在每个时间步中都绘制一次。这是由于在 CAN Transmit 模块中启用了基于事件的传输,在这种状态下,仅当该 CAN ID 的数据与之前接收的报文相比发生更改时,才会传输 CAN 报文。
由于报文“Counter_Msg”中的信号是计数器,它会在每个时间步递增 1,因此可以看到其绘图是一个线性曲线。
每个数据点表示启用了基于事件的传输的一次传输,因此在每个时间步都会收到“计数器”信号,但“常量”信号只会收到一次。
使用基于事件的传输和周期性传输执行模型
启用两种传输模式
以编程方式在 CAN Transmit 模块中启用事件传输。此外,启用周期性传输并设置报文周期。
set_param('EventTransmit/CAN Transmit', 'EnableEventTransmit', 'on'); set_param('EventTransmit/CAN Transmit', 'EnablePeriodicTransmit', 'on'); set_param('EventTransmit/CAN Transmit', 'MessagePeriod', '0.1');
请注意,在应用设置后,模块显示会发生变化。
在 MATLAB 中配置 CAN 通道以与模型通信
使用虚拟设备通信创建一个与 Simulink 模型对接的 CAN 通道。此外,将 CAN 数据库连接到它,以自动解码传入报文。
canCh = canChannel("Mathworks","Virtual 1",2)
canCh = Channel with properties: Device Information DeviceVendor: 'MathWorks' Device: 'Virtual 1' DeviceChannelIndex: 2 DeviceSerialNumber: 0 ProtocolMode: 'CAN' Status Information Running: 0 MessagesAvailable: 0 MessagesReceived: 0 MessagesTransmitted: 0 InitializationAccess: 1 InitialTimestamp: [0×0 datetime] FilterHistory: 'Standard ID Filter: Allow All | Extended ID Filter: Allow All' Channel Information BusStatus: 'N/A' SilentMode: 0 TransceiverName: 'N/A' TransceiverState: 'N/A' ReceiveErrorCount: 0 TransmitErrorCount: 0 BusSpeed: 500000 SJW: [] TSEG1: [] TSEG2: [] NumOfSamples: [] Other Information Database: [] UserData: []
canCh.Database = db;
启动 CAN 通道以联网。
start(canCh);
运行模型
分配仿真运行时间并启动模型。
t = "20"; set_param("EventTransmit","StopTime",t) set_param("EventTransmit","SimulationCommand","start");
等到仿真开始。
while strcmp(get_param("EventTransmit","SimulationStatus"),"stopped") end
等到仿真结束。
pause(5);
在 MATLAB 中接收报文
从总线中接收模型生成的所有报文。
msg = receive(canCh,Inf,"OutputFormat","timetable")
msg=22×8 timetable
Time ID Extended Name Data Length Signals Error Remote
__________ __ ________ ________________ ____________ ______ ____________ _____ ______
4.598 sec 10 false {'Constant_Msg'} {[ 5 0 0 0]} 4 {1×1 struct} false false
4.598 sec 20 false {'Counter_Msg' } {[ 0 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 1 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 2 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 3 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 4 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 5 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 6 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 7 0 0 0]} 4 {1×1 struct} false false
4.5987 sec 20 false {'Counter_Msg' } {[ 8 0 0 0]} 4 {1×1 struct} false false
4.5988 sec 20 false {'Counter_Msg' } {[ 9 0 0 0]} 4 {1×1 struct} false false
4.5988 sec 20 false {'Counter_Msg' } {[10 0 0 0]} 4 {1×1 struct} false false
4.5988 sec 20 false {'Counter_Msg' } {[11 0 0 0]} 4 {1×1 struct} false false
4.5988 sec 20 false {'Counter_Msg' } {[12 0 0 0]} 4 {1×1 struct} false false
4.5988 sec 20 false {'Counter_Msg' } {[13 0 0 0]} 4 {1×1 struct} false false
4.5988 sec 20 false {'Counter_Msg' } {[14 0 0 0]} 4 {1×1 struct} false false
⋮
在 MATLAB 中停止 CAN 通道。
stop(canCh);
探查收到的数据
绘制在同一周期内每个报文中接收到的数据。
% Create a structure with signal details. signalTimeTable = canSignalTimetable(msg); % Plot the signal values of "Constant_Msg". x3 = 1:height(signalTimeTable.Constant_Msg); y3 = signalTimeTable.Constant_Msg.Constant; plot(x3, y3,"Marker","o"); hold on % Plot the signal values of "Counter_Msg". x4 = 1:height(signalTimeTable.Counter_Msg); y4 = signalTimeTable.Counter_Msg.Counter; plot(x4, y4,"Marker","o"); % Determine the maximum value for y-axis for scaling of graph. y3Max = max(signalTimeTable.Constant_Msg.Constant); y4Max = max(signalTimeTable.Counter_Msg.Counter); yMax = max(y3Max,y4Max)+5; ylim([0 yMax]); % Label the graph. xlabel("Number of Times Signals Received"); ylabel("CAN Signal Value"); legend("Constant","Counter","Location","northeastoutside"); legend("boxoff"); hold off
图中显示报文“Constant_Msg”中的信号“Constant”只收到几次;一次是在开始时由基于事件的传输引起的,后面的次数是传输的周期性引起的。这是因为信号的输入值保持不变。
而信号“Counter”的值在报文“Counter_Msg”中的每个时间步都会更改,由于启用了基于事件的传输,它会连续被接收,而且由于启用了周期性传输,后续又出现若干次传输。