Main Content

Simulink 中基于事件的 CAN 报文传输行为

此示例说明如何在配备了 Vehicle Network Toolbox™ 的 Simulink® 中使用基于事件的 CAN 报文传输。此功能允许在检测到一个时间步到下一个时间步的数据更改时进行 CAN 和 CAN FD 报文传输。

CAN 和 CAN FD Transmit 模块上可用的配置选项支持在数据发生更改时进行报文传输。当启用时,特定 CAN ID 的报文仅在该 ID 的数据发生更改时传输。每个报文根据其 ID 在每个时间步中独立处理。当禁用时,模块和周期性传输操作正常运行。此外,基于事件的传输还可与周期性传输一起启用,两者同时工作。

准备示例模型

包含的示例模型包括两个 CAN Pack 模块,两者配置为连入一个 CAN Transmit 模块。一条报文的数据是一个常量,而另一条报文的数据是在每个时间步都会更改的计数器。

Model1.JPG

打开示例模型。

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');

请注意,在应用设置后,模块显示会发生变化。

Model2.JPG

在 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');

请注意,在应用设置后,模块显示会发生变化。

Model3.JPG

在 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”中的每个时间步都会更改,由于启用了基于事件的传输,它会连续被接收,而且由于启用了周期性传输,后续又出现若干次传输。