Main Content

Periodic CAN Communication in MATLAB

This example shows you how to how to configure CAN channels and messages for transmit messages periodically. It uses MathWorks virtual CAN channels connected in a loopback configuration.

As this example is based on sending and receiving CAN messages on a virtual network, running CAN Explorer in conjunction may provide a more complete understanding of what the code is doing. To run CAN Explorer, open and configure it to use the same interface as the receiving channel of the example. Make sure to start CAN Explorer before beginning to run the example in order to see all of the messages as they occur.

This example describes the workflow for a CAN network, but the concept demonstrated also applies to a CAN FD network.

Create the CAN Channels

Create CAN channels for message transmission and reception.

txCh = canChannel("MathWorks", "Virtual 1", 1);
rxCh = canChannel("MathWorks", "Virtual 1", 2);

Open the DBC-file that contains message and signal definitions, and attach it to both CAN channels.

db = canDatabase("CANDatabasePeriodic.dbc");
txCh.Database = db;
rxCh.Database = db;

Create the CAN Messages

Create CAN messages EngineMsg and TransmissionMsg using the database information.

msgFast = canMessage(db, "EngineMsg")
msgFast = 
  Message with properties:

   Message Identification
    ProtocolMode: 'CAN'
              ID: 100
        Extended: 0
            Name: 'EngineMsg'

   Data Details
       Timestamp: 0
            Data: [0 0 0 0 0 0 0 0]
         Signals: [1x1 struct]
          Length: 8

   Protocol Flags
           Error: 0
          Remote: 0

   Other Information
        Database: [1x1 can.Database]
        UserData: []

msgSlow = canMessage(db, "TransmissionMsg")
msgSlow = 
  Message with properties:

   Message Identification
    ProtocolMode: 'CAN'
              ID: 200
        Extended: 0
            Name: 'TransmissionMsg'

   Data Details
       Timestamp: 0
            Data: [0 0 0 0 0 0 0 0]
         Signals: [1x1 struct]
          Length: 8

   Protocol Flags
           Error: 0
          Remote: 0

   Other Information
        Database: [1x1 can.Database]
        UserData: []

Configure Messages for Periodic Transmission

To enable a message for periodic transmission, use the transmitPeriodic command specifying the transmitting channel, the message to register on the channel, a state value, and the periodic rate.

transmitPeriodic(txCh, msgFast, "On", 0.100);
transmitPeriodic(txCh, msgSlow, "On", 0.500);

Start the Periodic Transmission

Start the receiving channel.

start(rxCh);

Start the transmitting channel with periodic transmission configured in the previous step. Period transmission begins immediately. Allow the channels to run for two seconds.

start(txCh);
pause(2);

Update Transmitted Data

To update the live messages or signal data transmitted onto the CAN bus, write new values directly to the VehicleSpeed signal in message EngineMsg.

msgFast.Signals.VehicleSpeed = 60;
pause(1);
msgFast.Signals.VehicleSpeed = 65;
pause(1);
msgFast.Signals.VehicleSpeed = 70;
pause(1);

Alternatively, you can write new values to the Data property of the created messages.

Receive the Messages

Stop the CAN channels and receive all periodically transmitted messages for analysis.

stop(txCh);
stop(rxCh);
msgRx = receive(rxCh, Inf, "OutputFormat", "timetable");

View the first few rows of the received messages using the head function.

head(msgRx)
ans=8×8 timetable
        Time        ID     Extended           Name                   Data            Length      Signals       Error    Remote
    ____________    ___    ________    ___________________    ___________________    ______    ____________    _____    ______

    0.01281 sec     100     false      {'EngineMsg'      }    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.012813 sec    200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.11073 sec     100     false      {'EngineMsg'      }    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.21072 sec     100     false      {'EngineMsg'      }    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.31073 sec     100     false      {'EngineMsg'      }    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.41074 sec     100     false      {'EngineMsg'      }    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.5107 sec      100     false      {'EngineMsg'      }    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.5107 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 

Analyze the Behavior of Periodic Transmission

Analyze the distribution of messages by plotting the identifiers of each received message against their timestamps. Note the difference between how often the two messages appear according to the configured periodic rates.

plot(msgRx.Time, msgRx.ID, "x")
ylim([0 400])
title("Message Distribution", "FontWeight", "bold")
xlabel("Timestamp")
ylabel("CAN Identifier")

Figure contains an axes object. The axes object with title Message Distribution contains an object of type line.

For further analysis, separate the two messages into individual timetables.

msgRxFast = msgRx(strcmpi("EngineMsg", msgRx.Name), :);
head(msgRxFast)
ans=8×8 timetable
       Time        ID     Extended        Name                Data            Length      Signals       Error    Remote
    ___________    ___    ________    _____________    ___________________    ______    ____________    _____    ______

    0.01281 sec    100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.11073 sec    100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.21072 sec    100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.31073 sec    100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.41074 sec    100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.5107 sec     100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.61075 sec    100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.71074 sec    100     false      {'EngineMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 

msgRxSlow = msgRx(strcmpi("TransmissionMsg", msgRx.Name), :);
head(msgRxSlow)
ans=8×8 timetable
        Time        ID     Extended           Name                   Data            Length      Signals       Error    Remote
    ____________    ___    ________    ___________________    ___________________    ______    ____________    _____    ______

    0.012813 sec    200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    0.5107 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    1.0107 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    1.5108 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    2.0108 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    2.5108 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    3.0108 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    3.5108 sec      200     false      {'TransmissionMsg'}    {[0 0 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 

Analyze the timestamps of each set of messages to see how closely the average of the differences corresponds to the configured periodic rates.

avgPeriodFast = mean(diff(msgRxFast.Time))
avgPeriodFast = duration
   0.099959 sec

avgPeriodSlow = mean(diff(msgRxSlow.Time))
avgPeriodSlow = duration
   0.4998 sec

Use canSignalTimetable to repackage signal data from message EngineMsg into a signal timetable.

signalTimetable = canSignalTimetable(msgRx, "EngineMsg");
head(signalTimetable)
ans=8×2 timetable
       Time        VehicleSpeed    EngineRPM
    ___________    ____________    _________

    0.01281 sec         0             250   
    0.11073 sec         0             250   
    0.21072 sec         0             250   
    0.31073 sec         0             250   
    0.41074 sec         0             250   
    0.5107 sec          0             250   
    0.61075 sec         0             250   
    0.71074 sec         0             250   

Plot the received values of signal VehicleSpeed over time and note how it reflects the three updates in message data.

plot(signalTimetable.Time, signalTimetable.VehicleSpeed)
title("Vehicle Speed from EngineMsg", "FontWeight", "bold")
xlabel("Timestamp")
ylabel("Vehicle Speed")
ylim([-5 75])

Figure contains an axes object. The axes object with title Vehicle Speed from EngineMsg contains an object of type line.

View Messages Configured for Periodic Transmission

To see messages configured on the transmitting channel for automatic transmission, use the transmitConfiguration command.

transmitConfiguration(txCh)
Periodic Messages

ID  Extended      Name             Data        Rate (seconds)
--- -------- --------------- ----------------- --------------
100 false    EngineMsg       0 0 0 0 70 0 0 0  0.100000
200 false    TransmissionMsg 0 0 0 0 0 0 0 0   0.500000


Event Messages

None

Close the Channels and DBC-File

Close access to the channels and the DBC-file by clearing their variables from the workspace.

clear rxCh txCh
clear db