在 CAN 通信中使用 DBC 文件
以下示例说明如何使用存储在 DBC 文件中的信息创建、接收和处理报文。此示例说明 CAN 网络的工作流,但所展示的概念也适用于 CAN FD 网络。
打开 DBC 文件
使用 canDatabase 打开文件 demoVNT_CANdbFiles.dbc。
db = canDatabase("demoVNT_CANdbFiles.dbc")db =
Database with properties:
Name: 'demoVNT_CANdbFiles'
Path: 'C:\Users\michellw\OneDrive - MathWorks\Documents\MATLAB\Examples\vnt-ex80654288\demoVNT_CANdbFiles.dbc'
Nodes: {}
NodeInfo: [0×0 struct]
Messages: {5×1 cell}
MessageInfo: [5×1 struct]
Attributes: {}
AttributeInfo: [0×0 struct]
UserData: []
请检查 Messages 属性,以查看此文件中定义的所有报文的名称。
db.Messages
ans = 5×1 cell array
"'DoorControlMsg'"
"'EngineMsg'"
"'SunroofControlMsg'"
"'TransmissionMsg'"
"'WindowControlMsg'"
查看报文信息
使用 messageInfo 查看报文 EngineMsg 的信息,包括标识符、数据长度和信号列表。
messageInfo(db, "EngineMsg")ans = struct with fields:
Name: 'EngineMsg'
ProtocolMode: 'CAN'
Comment: ''
ID: 100
Extended: 0
J1939: []
Length: 8
DLC: 8
BRS: 0
Signals: {2×1 cell}
SignalInfo: [2×1 struct]
TxNodes: {0×1 cell}
Attributes: {}
AttributeInfo: [0×0 struct]
您还可以一次查询所有报文的信息。
messageInfo(db)
ans=5×1 struct array with fields:
'DoorControlMsg' 'CAN' '' 400 0 [ ] 8 8 0 2×1 cell 2×1 struct 0×1 cell 0×0 cell 0×0 struct
'EngineMsg' 'CAN' '' 100 0 [ ] 8 8 0 2×1 cell 2×1 struct 0×1 cell 0×0 cell 0×0 struct
'SunroofControlMsg' 'CAN' '' 800 0 [ ] 2 2 0 1×1 cell 1×1 struct 0×1 cell 0×0 cell 0×0 struct
'TransmissionMsg' 'CAN' '' 200 0 [ ] 8 8 0 1×1 cell 1×1 struct 0×1 cell 0×0 cell 0×0 struct
'WindowControlMsg' 'CAN' '' 600 0 [ ] 4 4 0 2×1 cell 2×1 struct 0×1 cell 0×0 cell 0×0 struct
查看信号信息
使用 signalInfo 查看报文 EngineMsg 中信号 EngineRPM 的信息,包括用于将原始信号转换为物理值的类型、字节顺序、大小和缩放值。
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: [0×1 struct]
Multiplexor: 0
Multiplexed: 0
MultiplexMode: 0
RxNodes: {0×1 cell}
Attributes: {}
AttributeInfo: [0×0 struct]
您还可以一次查询报文 EngineMsg 中所有信号的信息。
signalInfo(db, "EngineMsg")ans=2×1 struct array with fields:
'EngineRPM' '' 0 32 'LittleEndian' 0 'Integer' 'uint32' 0.1000 250 250 9500 'rpm' 0×1 struct 0 0 0 0×1 cell 0×0 cell 0×0 struct
'VehicleSpeed' '' 32 32 'LittleEndian' 0 'Integer' 'uint32' 1 0 0 4.2950e+09 'mph' 0×1 struct 0 0 0 0×1 cell 0×0 cell 0×0 struct
⋮
使用数据库定义创建报文
通过指定要应用数据库定义的数据库和报文名称 EngineMsg 来创建新报文。此报文中的 CAN 信号除以原始数据字节表示外,还以工程单位来表示。
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: [1×1 struct]
Length: 8
Protocol Flags
Error: 0
Remote: 0
Other Information
Database: [1×1 can.Database]
UserData: []
查看信号信息
使用 Signals 属性查看此报文的信号值。您可以直接对这些信号进行写入和读取,以打包和解包报文中的数据。
msgEngineInfo.Signals
ans = struct with fields:
VehicleSpeed: 0
EngineRPM: 250
更改信号信息
直接写入信号 EngineRPM 以更改其值。
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: [1×1 struct]
Length: 8
Protocol Flags
Error: 0
Remote: 0
Other Information
Database: [1×1 can.Database]
UserData: []
读回当前信号值,注意 EngineRPM 已用写入的值更新。
msgEngineInfo.Signals
ans = struct with fields:
VehicleSpeed: 0
EngineRPM: 5.5003e+03
当值直接写入信号时,它会转换、缩放,并使用数据库定义打包到报文数据中。请注意在向 VehicleSpeed 信号写入新值后,Data 属性中的值变化。
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: [1×1 struct]
Length: 8
Protocol Flags
Error: 0
Remote: 0
Other Information
Database: [1×1 can.Database]
UserData: []
msgEngineInfo.Signals
ans = struct with fields:
VehicleSpeed: 71
EngineRPM: 5.5003e+03
接收具有数据库信息的报文
将数据库连接到 CAN 通道,该通道接收报文以自动将数据库定义应用于传入报文。数据库仅解码已定义的报文。所有其他报文都以其原始形式接收。
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: [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: [1×1 can.Database]
UserData: []
接收报文
启动通道,生成一些报文流,然后通过物理报文解码来接收报文。
start(rxCh); generateMsgsDb(); rxMsg = receive(rxCh, Inf, "OutputFormat", "timetable");
查看接收到的报文的前几行。
head(rxMsg)
ans=8×8 timetable
0.13103 sec 100 0 'EngineMsg' [0,0,0,0,0,0,0,0] 8 1×1 struct 0 0
0.13103 sec 200 0 'TransmissionMsg' [0,0,0,0,0,0,0,0] 8 1×1 struct 0 0
0.13104 sec 400 0 'DoorControlMsg' [0,0,0,0,0,0,0,0] 8 1×1 struct 0 0
0.13104 sec 600 0 'WindowControlMsg' [0,0,0,0] 4 1×1 struct 0 0
0.13105 sec 800 0 'SunroofControlMsg' [0,0] 2 1×1 struct 0 0
0.15598 sec 100 0 'EngineMsg' [0,0,0,0,0,0,0,0] 8 1×1 struct 0 0
0.18 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
0.18001 sec 200 0 'TransmissionMsg' [4,0,0,0,0,0,0,0] 8 1×1 struct 0 0
停止接收通道并将其从工作区中清除。
stop(rxCh);
clear rxCh检查收到的报文
检查收到的报文以查看应用的数据库解码。
rxMsg(10, :)
ans=1×8 timetable
0.22994 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
rxMsg.Signals{10}ans = struct with fields:
VehicleSpeed: 50
EngineRPM: 3.5696e+03
提取指定报文的所有实例
提取报文 EngineMsg 的所有实例。
allMsgEngine = rxMsg(strcmpi("EngineMsg", rxMsg.Name), :);查看此特定报文的前几个实例。
head(allMsgEngine)
ans=8×8 timetable
0.13103 sec 100 0 'EngineMsg' [0,0,0,0,0,0,0,0] 8 1×1 struct 0 0
0.15598 sec 100 0 'EngineMsg' [0,0,0,0,0,0,0,0] 8 1×1 struct 0 0
0.18 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
0.20597 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
0.22994 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
0.25695 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
0.27995 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
0.30597 sec 100 0 'EngineMsg' [172,129,0,0,50,0,0,0] 8 1×1 struct 0 0
绘制物理信号值
使用 canSignalTimetable 将报文 EngineMsg 中的信号数据重新打包为一个信号时间表。
signalTimetable = canSignalTimetable(rxMsg, "EngineMsg");查看信号时间表的前几行。
head(signalTimetable)
ans=8×2 timetable
0.13103 sec 0 250
0.15598 sec 0 250
0.18 sec 50 3.5696e+03
0.20597 sec 50 3.5696e+03
0.22994 sec 50 3.5696e+03
0.25695 sec 50 3.5696e+03
0.27995 sec 50 3.5696e+03
0.30597 sec 50 3.5696e+03
绘制信号 VehicleSpeed 随时间变化的值。
plot(signalTimetable.Time, signalTimetable.VehicleSpeed) title("Vehicle Speed from EngineMsg", "FontWeight", "bold") xlabel("Timestamp") ylabel("Vehicle Speed")

关闭 DBC 文件
通过从工作区中清除 DBC 文件的变量,关闭对该 DBC 文件的访问。
clear db