什么是 DBC 文件 DBC 是Database Can的缩写,其代表的是CAN的数据库文件。简单地说,通过 CAN 总线通信的数据类型可以用 DBC 文件来读取和理解。一般通过 Vector CANdb++ 进行编辑和查看。
DBC 文件内容 当我们打开一份 DBC 文件时,左侧树形目录对应
Networks:从网络的视角来观察总线上存在的节点、报文和信号 
ECUs:每个 ECU 的 Network Node 和 Environment Variables
Environment Variables:在使用 CANoe 仿真节点时会用到 
Network nodes:从单个节点的视角来观察与节点相关的总线报文及信号
Tx Messages:节点发送报文 
Rx Messages:节点接收报文 
Mapped Tx Signals:节点发送信号 
Mapped Rx Signals:节点接收信号 
 
 
 
 
Messages:CAN 总线上传输信息的最小单位 
Signals:Message 里最小的元素单位 
 
值得一提的是,Messages 与 Signals 下包含的报文信号比 Network nodes 下的收发报文信号要多,并且有可能会包含实际没用到的报文信号,因为所有创建的报文信号都会在 Messages 与 Signals 下显示,但只有映射到节点的报文信号才会在 Network nodes 下显示。
因此我们主要看 Network nodes 下里的网络节点,网络节点分为多个类,如下图,分为 SDE、sensor2、sensor3 三个类节点。
当点开节点时,会看到类节点下的 TX 与 RX 下的多个 messages。
ID:CAN message id,一般以16进制显示 
Name: CAN message name 
ID-Format:CAN 报文的类型(CAN Standard/CAN FD Standard) 
DLC:数据长度代码,CAN 报文中数据的长度 
 
每个 message 又包含了多个 signals。
Name:信号的名称 
Multiplexing:多路复用 
Startbit:信号的起始位 
Byte Order:信号的位计数,分为 Motorols(大端字节序)和 Intel(小端字节序) 
Value Type:数据类型 
Factor:信号的转换系数 
Offset:信号的转换偏移 
Minimum & Maximum:最小和最大的信号值 
Unit:信号中存在的物理数据的单位 
Comment:信号说明 
 
其中 factor 因数 与 offse 偏移量 定义了 physical 物理值(如vehicle speed,engine speed,water temperature)与 raw 原始值(总线上传输的值)的线性转换规则。
1 2 physical_value = raw_value * factor  + offset raw_value = ( pysical_value - offset ) / factor  
 
DBC 文件解析 这里使用 Python。首先安装 cantools 这个库文件,可以直接解析 dbc 文件。
 
使用时,直接 import cantools 即可。
1 2 3 import  cantoolsdbc_file = "******"  dbc_info = cantools.db.load_file(dbc_file)     
 
直接使用时,下述附代码,可直接复制使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 import  cantoolsclass  DbcInfo :    """      用于读取dbc文件,返回dbc信息     """     def  __init__ (self, input_file ):         """          init         """         self.dbc_file = input_file         self.dbc_info = cantools.db.load_file(self.dbc_file)     def  get_message (self, frame_id ):         """          return message,特别强调,frame_id输入10进制即可,同时必须是int型数据,不能是字符串         """         return  self.dbc_info.get_message_by_frame_id(frame_id)        def  get_message_name (self, frame_id ):         """          return message name         """         return  self.dbc_info.get_message_by_frame_id(frame_id).name     def  get_message_name_by_message_id (self, frame_name ):         """          return message id by message name         """         return  self.dbc_info.get_message_by_name(frame_name).frame_id     def  get_signals_list (self, frame_id ):         """          return signals list         """         return  self.dbc_info.get_message_by_frame_id(frame_id).signal_tree         def  get_signal (self, frame_id, signal_name ):         """          return signal, 输入message id和signal name         """         return  self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name)     def  get_signal_config_maximum (self, frame_id, signal_name ):         """          return signal maximum         """         return  self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).maximum     def  get_signal_config_minimum (self, frame_id, signal_name ):         """          return signal minimum         """         return  self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).minimum     def  get_signal_config_scale (self, frame_id, signal_name ):         """          return signal scale,这里指的是signal定义中其取值范围的间隔,         比如从1到10,每个2取一个值,scale就是2         """         return  self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).scale     def  get_signal_config_comment (self, frame_id, signal_name ):         """          return signal comment,signal说明         """         return  self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).comment     def  signal_config_value_description_to_num (self, frame_id, signal_name, value_str ):         """          return signal value description         这里需要特别说明下,有些signal取值不是正常的数值,而是文字描述,         这个在定义中是个表,比如1:open, 2:close, 4:ignore,         本函数的意思是当你取到这个字符串,比如close时,能够返回这个字符串在对应中的数字2,         这在解析和保存以及后续发送中是很有用的。         """         return  self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).\             choice_string_to_number(value_str) if  __name__ == '__main__' :    dbc_info = DbcInfo('D:test.dbc' )               print (dbc_info.get_message_name(520 )) 
 
如果想进行 can 报文修改,需要注意的是,直接给的数据不一定符合要求,需要保证修改数值在 signal 的最大最小范围内,同时保证该值符合定义中的取值间隔,可采用下述函数进行 check,保证输入数值符合要求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 def  check_value_meet_norms (self, frame_id, signal_name, value ):    """      check value meet norms and return closest value based on scale factor     检查输入是否符合规范,同时输出符合规范的最接近输入value值的value     如果你要用脚本修改can报文,但是修改的值如果不符合要求,给入会报错,     该函数保证修改值符合规范且接近用户期望值     """     max_value = self.get_signal_config_maximum(frame_id, signal_name)     min_value = self.get_signal_config_minimum(frame_id, signal_name)     scale_value = self.get_signal_config_scale(frame_id, signal_name)     if  value > max_value:         if  isinstance (scale_value, int ):             return  int (max_value)         return  max_value     elif  value < min_value:         if  isinstance (scale_value, int ):             return  int (max_value)         return  min_value     else :         num = round (value / scale_value)         if  isinstance (scale_value, int ):             return  int (num * scale_value)         return  num * scale_value 
 
参考