Use DBC-Files in CAN Communication
This example shows you how to create, receive and process messages using information stored in DBC-files. This example describes the workflow for a CAN network, but the concept demonstrated also applies to a CAN FD network.
Open the DBC-File
Open file demoVNT_CANdbFiles.dbc
using canDatabase
.
db = canDatabase("demoVNT_CANdbFiles.dbc")
db = Database with properties: Name: 'demoVNT_CANdbFiles' Path: '/tmp/Bdoc22a_1891349_157288/tpe433a46b/vnt-ex80654288/demoVNT_CANdbFiles.dbc' UTF8_File: '/tmp/Bdoc22a_1891349_157288/tpe433a46b/vnt-ex80654288/demoVNT_CANdbFiles.dbc' Nodes: {} NodeInfo: [0x0 struct] Messages: {5x1 cell} MessageInfo: [5x1 struct] Attributes: {} AttributeInfo: [0x0 struct] UserData: []
Examine the Messages
property to see the names of all messages defined in this file.
db.Messages
ans = 5x1 cell
{'DoorControlMsg' }
{'EngineMsg' }
{'SunroofControlMsg'}
{'TransmissionMsg' }
{'WindowControlMsg' }
View Message Information
Use messageInfo
to view information for message EngineMsg
, including the identifier, data length, and a signal list.
messageInfo(db, "EngineMsg")
ans = struct with fields:
Name: 'EngineMsg'
ProtocolMode: 'CAN'
Comment: ''
ID: 100
Extended: 0
J1939: []
Length: 8
DLC: 8
BRS: 0
Signals: {2x1 cell}
SignalInfo: [2x1 struct]
TxNodes: {0x1 cell}
Attributes: {}
AttributeInfo: [0x0 struct]
You can also query for information on all messages at once.
messageInfo(db)
ans=5×1 struct array with fields:
Name
ProtocolMode
Comment
ID
Extended
J1939
Length
DLC
BRS
Signals
SignalInfo
TxNodes
Attributes
AttributeInfo
View Signal Information
Use signalInfo
to view information for signal EngineRPM
in message EngineMsg
, including type, byte ordering, size, and scaling values that translate raw signals to physical values.
signalInfo(db, "EngineMsg", "EngineRPM")
ans = struct with fields:
Name: 'EngineRPM'
Comment: ''
StartBit: 0
SignalSize: 32
ByteOrder: 'LittleEndian'
Signed: 0
ValueType: 'Integer'
Class: 'uint32'
Factor: 0.1000
Offset: 250
Minimum: 250
Maximum: 9500
Units: 'rpm'
ValueTable: [0x1 struct]
Multiplexor: 0
Multiplexed: 0
MultiplexMode: 0
RxNodes: {0x1 cell}
Attributes: {}
AttributeInfo: [0x0 struct]
You can also query for information on all signals in message EngineMsg
at once.
signalInfo(db, "EngineMsg")
ans=2×1 struct array with fields:
Name
Comment
StartBit
SignalSize
ByteOrder
Signed
ValueType
Class
Factor
Offset
Minimum
Maximum
Units
ValueTable
Multiplexor
Multiplexed
MultiplexMode
RxNodes
Attributes
AttributeInfo
⋮
Create a Message Using Database Definitions
Create a new message by specifying the database and the message name EngineMsg
to have the database definition applied. CAN signals in this message are represented in engineering units in addition to the raw data bytes.
msgEngineInfo = canMessage(db, "EngineMsg")
msgEngineInfo = 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: []
View Signal Information
Use the Signals
property to see signal values for this message. You can directly write to and read from these signals to pack and unpack data from the message.
msgEngineInfo.Signals
ans = struct with fields:
VehicleSpeed: 0
EngineRPM: 250
Change Signal Information
Write directly to the signal EngineRPM
to change its value.
msgEngineInfo.Signals.EngineRPM = 5500.25
msgEngineInfo = Message with properties: Message Identification ProtocolMode: 'CAN' ID: 100 Extended: 0 Name: 'EngineMsg' Data Details Timestamp: 0 Data: [23 205 0 0 0 0 0 0] Signals: [1x1 struct] Length: 8 Protocol Flags Error: 0 Remote: 0 Other Information Database: [1x1 can.Database] UserData: []
Read the current signal values back and note that EngineRPM
has been updated with the written value.
msgEngineInfo.Signals
ans = struct with fields:
VehicleSpeed: 0
EngineRPM: 5.5003e+03
When a value is written directly to the signal, it is translated, scaled, and packed into the message data using the database definition. Note the value change in the Data
property after a new value is written to the VehicleSpeed
signal.
msgEngineInfo.Signals.VehicleSpeed = 70.81
msgEngineInfo = Message with properties: Message Identification ProtocolMode: 'CAN' ID: 100 Extended: 0 Name: 'EngineMsg' Data Details Timestamp: 0 Data: [23 205 0 0 71 0 0 0] Signals: [1x1 struct] Length: 8 Protocol Flags Error: 0 Remote: 0 Other Information Database: [1x1 can.Database] UserData: []
msgEngineInfo.Signals
ans = struct with fields:
VehicleSpeed: 71
EngineRPM: 5.5003e+03
Receive Messages with Database Information
Attach a database to a CAN channel that receives messages to apply database definitions to incoming messages automatically. The database decodes only messages that are defined. All other messages are received in their raw form.
rxCh = canChannel("MathWorks", "Virtual 1", 2); rxCh.Database = db
rxCh = 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: [0x0 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: [1x1 can.Database] UserData: []
Receive Messages
Start the channel, generate some message traffic, and receive messages with physical message decoding.
start(rxCh); generateMsgsDb(); rxMsg = receive(rxCh, Inf, "OutputFormat", "timetable");
View the first few rows of received messages.
head(rxMsg)
ans=8×8 timetable
Time ID Extended Name Data Length Signals Error Remote
____________ ___ ________ _____________________ ________________________ ______ ____________ _____ ______
0.049547 sec 100 false {'EngineMsg' } {[ 0 0 0 0 0 0 0 0]} 8 {1x1 struct} false false
0.049549 sec 200 false {'TransmissionMsg' } {[ 0 0 0 0 0 0 0 0]} 8 {1x1 struct} false false
0.049551 sec 400 false {'DoorControlMsg' } {[ 0 0 0 0 0 0 0 0]} 8 {1x1 struct} false false
0.049553 sec 600 false {'WindowControlMsg' } {[ 0 0 0 0]} 4 {1x1 struct} false false
0.049554 sec 800 false {'SunroofControlMsg'} {[ 0 0]} 2 {1x1 struct} false false
0.075082 sec 100 false {'EngineMsg' } {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.099548 sec 100 false {'EngineMsg' } {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.099549 sec 200 false {'TransmissionMsg' } {[ 4 0 0 0 0 0 0 0]} 8 {1x1 struct} false false
Stop the receiving channel and clear it from the workspace.
stop(rxCh);
clear rxCh
Examine a Received Message
Inspect a received message to see the applied database decoding.
rxMsg(10, :)
ans=1×8 timetable
Time ID Extended Name Data Length Signals Error Remote
___________ ___ ________ _____________ ________________________ ______ ____________ _____ ______
0.14954 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
rxMsg.Signals{10}
ans = struct with fields:
VehicleSpeed: 50
EngineRPM: 3.5696e+03
Extract All Instances of a Specified Message
Extract all instances of message EngineMsg
.
allMsgEngine = rxMsg(strcmpi("EngineMsg", rxMsg.Name), :);
View the first few instances of this specific message.
head(allMsgEngine)
ans=8×8 timetable
Time ID Extended Name Data Length Signals Error Remote
____________ ___ ________ _____________ ________________________ ______ ____________ _____ ______
0.049547 sec 100 false {'EngineMsg'} {[ 0 0 0 0 0 0 0 0]} 8 {1x1 struct} false false
0.075082 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.099548 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.12454 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.14954 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.17454 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.19954 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
0.22455 sec 100 false {'EngineMsg'} {[172 129 0 0 50 0 0 0]} 8 {1x1 struct} false false
Plot Physical Signal Values
Use canSignalTimetable
to repackage signal data from message EngineMsg
into a signal timetable.
signalTimetable = canSignalTimetable(rxMsg, "EngineMsg");
View the first few rows of the signal timetable.
head(signalTimetable)
ans=8×2 timetable
Time VehicleSpeed EngineRPM
____________ ____________ _________
0.049547 sec 0 250
0.075082 sec 50 3569.6
0.099548 sec 50 3569.6
0.12454 sec 50 3569.6
0.14954 sec 50 3569.6
0.17454 sec 50 3569.6
0.19954 sec 50 3569.6
0.22455 sec 50 3569.6
Plot the values of signal VehicleSpeed
over time.
plot(signalTimetable.Time, signalTimetable.VehicleSpeed) title("Vehicle Speed from EngineMsg", "FontWeight", "bold") xlabel("Timestamp") ylabel("Vehicle Speed")
Close the DBC-File
Close access to the DBC-file by clearing its variable from the workspace.
clear db