主要内容

在 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