Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

在 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
    {'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:
    Name
    ProtocolMode
    Comment
    ID
    Extended
    J1939
    Length
    DLC
    BRS
    Signals
    SignalInfo
    TxNodes
    Attributes
    AttributeInfo

查看信号信息

使用 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:
    Name
    Comment
    StartBit
    SignalSize
    ByteOrder
    Signed
    ValueType
    Class
    Factor
    Offset
    Minimum
    Maximum
    Units
    ValueTable
    Multiplexor
    Multiplexed
    MultiplexMode
    RxNodes
    Attributes
    AttributeInfo
      ⋮

使用数据库定义创建报文

通过指定要应用数据库定义的数据库和报文名称 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
       Time        ID     Extended            Name                       Data              Length      Signals       Error    Remote
    ___________    ___    ________    _____________________    ________________________    ______    ____________    _____    ______

    0.13103 sec    100     false      {'EngineMsg'        }    {[     0 0 0 0 0 0 0 0]}      8       {1×1 struct}    false    false 
    0.13103 sec    200     false      {'TransmissionMsg'  }    {[     0 0 0 0 0 0 0 0]}      8       {1×1 struct}    false    false 
    0.13104 sec    400     false      {'DoorControlMsg'   }    {[     0 0 0 0 0 0 0 0]}      8       {1×1 struct}    false    false 
    0.13104 sec    600     false      {'WindowControlMsg' }    {[             0 0 0 0]}      4       {1×1 struct}    false    false 
    0.13105 sec    800     false      {'SunroofControlMsg'}    {[                 0 0]}      2       {1×1 struct}    false    false 
    0.15598 sec    100     false      {'EngineMsg'        }    {[     0 0 0 0 0 0 0 0]}      8       {1×1 struct}    false    false 
    0.18 sec       100     false      {'EngineMsg'        }    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 
    0.18001 sec    200     false      {'TransmissionMsg'  }    {[     4 0 0 0 0 0 0 0]}      8       {1×1 struct}    false    false 

停止接收通道并将其从工作区中清除。

stop(rxCh);
clear rxCh

检查收到的报文

检查收到的报文以查看应用的数据库解码。

rxMsg(10, :)
ans=1×8 timetable
       Time        ID     Extended        Name                   Data              Length      Signals       Error    Remote
    ___________    ___    ________    _____________    ________________________    ______    ____________    _____    ______

    0.22994 sec    100     false      {'EngineMsg'}    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 

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
       Time        ID     Extended        Name                   Data              Length      Signals       Error    Remote
    ___________    ___    ________    _____________    ________________________    ______    ____________    _____    ______

    0.13103 sec    100     false      {'EngineMsg'}    {[     0 0 0 0 0 0 0 0]}      8       {1×1 struct}    false    false 
    0.15598 sec    100     false      {'EngineMsg'}    {[     0 0 0 0 0 0 0 0]}      8       {1×1 struct}    false    false 
    0.18 sec       100     false      {'EngineMsg'}    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 
    0.20597 sec    100     false      {'EngineMsg'}    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 
    0.22994 sec    100     false      {'EngineMsg'}    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 
    0.25695 sec    100     false      {'EngineMsg'}    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 
    0.27995 sec    100     false      {'EngineMsg'}    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 
    0.30597 sec    100     false      {'EngineMsg'}    {[172 129 0 0 50 0 0 0]}      8       {1×1 struct}    false    false 

绘制物理信号值

使用 canSignalTimetable 将报文 EngineMsg 中的信号数据重新打包为一个信号时间表。

signalTimetable = canSignalTimetable(rxMsg, "EngineMsg");

查看信号时间表的前几行。

head(signalTimetable)
ans=8×2 timetable
       Time        VehicleSpeed    EngineRPM
    ___________    ____________    _________

    0.13103 sec          0             250  
    0.15598 sec          0             250  
    0.18 sec            50          3569.6  
    0.20597 sec         50          3569.6  
    0.22994 sec         50          3569.6  
    0.25695 sec         50          3569.6  
    0.27995 sec         50          3569.6  
    0.30597 sec         50          3569.6  

绘制信号 VehicleSpeed 随时间变化的值。

plot(signalTimetable.Time, signalTimetable.VehicleSpeed)
title("Vehicle Speed from EngineMsg", "FontWeight", "bold")
xlabel("Timestamp")
ylabel("Vehicle Speed")

关闭 DBC 文件

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

clear db