小聊一下excel生成dbc
Motorola、Intel格式
讲这2个格式首先说一下大小端格式。
大端模式:
低地址中存放的是字数据的低字节,高地址存放的是字数据的高字节。例:
(16位宽的数0x1234在小端模式CPU内存中的存放方式(假设从地址0x4000开始存放))
内存地址 | 0x4000 | 0x4001 |
存放内容 | 0x34 | 0x12 |
大端模式:
字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。例:
内存地址 | 0x4000 | 0x4001 |
存放内容 | 0x12 | 0x34 |
在dbc中,
Motorola格式:
Motorola格式跟大端格式一样,低地址代表高字节,高地址代表低字节。与Intel不一样,Motorola格式有2种表达方式,一种是Motorola_LSB,另一种是Motorola_MSB,但实际上它们代表的数据结构是一样的,只是表达方式不一样而已,其中Motorola_LSB的起始位是从低字节开始的,而
Motorola_MSB的起始位是从高字节开始的。
以某段报文为例:
使用db++查看layout:
可以看到文本阅读和db++中看到的startbit是不一样的。db++的sb是lsb,而文本中显示的是msb。
从图中可以看到:motorola格式的msb为高字节的最高位。
Intel格式:
Intel格式跟小端格式一样,
低地址代表低字节,高地址代表高字节。
例:
物理值、总线值转换
公式如下:
physical_value = raw_value * factor + offset
raw_value =(physical_value - offset)/ factor
例子:
以车速信号为例:
假设实际车速为50km/h,那么根据公式
(50-0)/0.00390625=12800=0x3200,那么0x3200就是填充在报文中的总线值。
dbc文件详解
含上图所示的几种信息,接下来咱们逐一解释下。
- VERSION、BS_分别表示版本和波特率信息,都可以忽略不填;
- BU_定义总线上的节点名称;
- BO_ MessageId(10进制数表示) MessageName: MessageSize TransmitterBO_表示报文关键字,需要描述报文的ID、名字、长度和发送方;
- SG_ SignalName : StartBit|SignalSize@ByteOrder ValueType (Factor,Offset) [Min|Max] Unit ReceiverSG_为信号关键字,需要描述信号的名字、起始位、长度、字节顺序(motorola为0,Intel为1)、数值类型(+表示无符号,-表示有符号)、精度、偏移量、最值、单位、接收方;
- CM_ Object MessageId/NodeName “Comment”CM_为注释信息,可以为信号、报文添加解释信息,这些在db++文件中和导入到CAN设备后都可以显示出来;
- BA_DEF_ Object AttributeName ValueType Min Max;BA_DEF_DEF_ AttributeName DefaultValue;用来做属性定义,一般只有主机厂才会生成特别详细的dbc文件内容;
小工具分享
其实写这篇文章的初衷是有同事想要帮忙制作dbc文件,于是便写了一个
先来个生成过程的打印信息吧:
脚本的具体功能:
首先在config.xlsx中写入信号列表.xlsx中报文、信号的属性的位置信息(列号),如下图:
然后执行py脚本即可生成dbc文件。没有py环境的可以在dist文件夹下找到同名的exe文件双击执行。
附个视频吧:
py 源码
from openpyxl import load_workbook
from collections import OrderedDict
import xlrd
from telnetlib import NOP
import os,sys
class Xls_Info_cl:
def __init__(self):
#there configs are important.
self.ByteOrder = "Motorola_lsb"
# there configs are necessary.
self.FileName = 'Platform_CANCMX_V0.4.0_FVCM_2022_05_30.xlsx'
self.Sheet = 'Signal Matrix'
self.Start_row = 2
self.MsgID_column = 'B'
self.Msg_Name_column = 'A'
self.Msg_Lenth_column = 'E'
self.Sig_Name_column = 'G'
self.StartBit_column = 'L'
self.Size_column = 'M'
self.ValueType_column = 'N'
self.Sig_Factor_column = 'O'
self.Sig_Offset_column = 'P'
self.Min_column = 'Q'
self.Max_column = 'R'
self.Unit_column = 'Y'
self.Value_Description_column = 'Z'
# there config is not necessary
self.Self_Node_colume = 'AA'
self.Self_Msg_Period_colume = 'D'
self.Sig_Multiplexortype = 'F'
# 获取当前工作目录的绝对路径
script_dir = os.path.dirname(sys.argv[0])
#获取表格内容
file_path = os.path.join(script_dir,'config_ini.xlsx')
workbook_object = load_workbook(filename=file_path)
sheet = workbook_object['config']
Xls_Info = Xls_Info_cl()
Xls_Info.ByteOrder = sheet['B3'].value
Xls_Info.FileName = sheet['B4'].value
Xls_Info.Sheet = sheet['B5'].value
Xls_Info.Start_row = sheet['B6'].value
Xls_Info.MsgID_column = sheet['B7'].value
Xls_Info.Msg_Name_column = sheet['B8'].value
Xls_Info.Msg_Lenth_column = sheet['B9'].value
Xls_Info.Sig_Name_column = sheet['B10'].value
Xls_Info.StartBit_column = sheet['B11'].value
Xls_Info.Size_column = sheet['B12'].value
Xls_Info.Sig_Factor_column = sheet['B13'].value
Xls_Info.Sig_Offset_column = sheet['B14'].value
Xls_Info.Max_column = sheet['B15'].value
Xls_Info.Min_column = sheet['B16'].value
Xls_Info.Unit_column = sheet['B17'].value
Xls_Info.ValueType_column = sheet['B18'].value
Xls_Info.Self_Node_colume = sheet['B19'].value
Xls_Info.Self_Msg_Period_colume = sheet['B20'].value
Xls_Info.Sig_Multiplexortype = sheet['B21'].value
file_path = os.path.join(script_dir,Xls_Info.FileName)
#加载Excel
if '.xlsx' in Xls_Info.FileName:
workbook_object = load_workbook(filename=file_path)
else:
workbook_object = xlrd.open_workbook(filename=(file_path))
#获取表单名称
names= workbook_object.sheetnames #获取表单的名称返回list
# 获取表单
sheet = workbook_object[Xls_Info.Sheet]
def Get_CellValue(column,row):
if column != 'FF' or column != None:
code = sheet[column + str(row)].value
else:
code = None
if type(code) == str:
code = code.replace('0X','').replace('0X','')
elif type(code) == int or type(code) == float:
code = str(code)
else:
code = None
return code
dbc_code = ''
MSg_Comment = ''
Sig_Comment = ''
dbc_txt = ''
last = ''
dbc_canfd = False
for i in range(((int)(Xls_Info.Start_row) + 1),sheet.max_row+1):
if(None != Get_CellValue(Xls_Info.Msg_Name_column,i)):
#eg:BO_ 389 ESCDAFuncSts: 8 Vector__XXX
if None != Get_CellValue(Xls_Info.Msg_Name_column,i) and last != Get_CellValue(Xls_Info.Msg_Name_column,i):
last = Get_CellValue(Xls_Info.Msg_Name_column,i)
if None != Get_CellValue(Xls_Info.Self_Node_colume,i) and (('S' in Get_CellValue(Xls_Info.Self_Node_colume,i)) or ('T' in Get_CellValue(Xls_Info.Self_Node_colume,i))\
or ('s' in Get_CellValue(Xls_Info.Self_Node_colume,i)) or ('t' in Get_CellValue(Xls_Info.Self_Node_colume,i))):
send_node = Get_CellValue(Xls_Info.Self_Node_colume,Xls_Info.Start_row)
receive_node = 'Vector__XXX'
else:
send_node = 'Vector__XXX'
receive_node = Get_CellValue(Xls_Info.Self_Node_colume,Xls_Info.Start_row)
MSG_ID = Get_CellValue(Xls_Info.MsgID_column,i)
MSG_ID = int(MSG_ID,16)
if Get_CellValue(Xls_Info.Msg_Lenth_column,i) != None:
MsgLenth = int(Get_CellValue(Xls_Info.Msg_Lenth_column,i))
else:
#default value is 8
MsgLenth = 8
dbc_code += '\nBO_ ' + str(MSG_ID) + ' ' + Get_CellValue(Xls_Info.Msg_Name_column,i)\
+ ': ' + str(MsgLenth) + ' ' + send_node + '\n'
if MsgLenth > 8:
dbc_canfd = True
if Get_CellValue(Xls_Info.Self_Msg_Period_colume,i) != None:
MSg_Comment += 'BA_ "GenMsgSendType" BO_ ' + str(MSG_ID) + ' 0;\n'
MSg_Comment += 'BA_ "GenMsgCycleTime" BO_ ' + str(MSG_ID) + ' ' + Get_CellValue(Xls_Info.Self_Msg_Period_colume,i) + ';\n'
if None != Get_CellValue(Xls_Info.Sig_Name_column,i):
#start bit is msb in db++,but is lsb in candb++!
if Xls_Info.ByteOrder == 'Motorola_lsb':
""" if 'TrGearRatio' == Get_CellValue(Xls_Info.Sig_Name_column,i):
NOP """
startByte = int(Get_CellValue(Xls_Info.StartBit_column,i))//8
Bit_CAN_Use = 8 - int(Get_CellValue(Xls_Info.StartBit_column,i))%8
Ramain_Bit = int(Get_CellValue(Xls_Info.Size_column,i))
for bitnum in range(int(Get_CellValue(Xls_Info.Size_column,i))):
if Bit_CAN_Use > 0:
#use byte in start bit first
Bit_CAN_Use -= 1
Ramain_Bit -= 1
else:
#use last byte in sb
Bit_CAN_Use = 8
if startByte > 0:
startByte -= 1
Bit_CAN_Use -= 1
Ramain_Bit -= 1
if Ramain_Bit == 0:
startbit = startByte*8 + (8-Bit_CAN_Use) - 1
else:
startbit = int(Get_CellValue(Xls_Info.StartBit_column,i))
# SG_ BrkPdlPosInfo_RllCnt : 51|4@0+ (1,0) [0|15] "" FVCM
if Xls_Info.ValueType_column != 'FF' and Xls_Info.ValueType_column != None and 'u' not in Get_CellValue(Xls_Info.ValueType_column,i)\
and 'U' not in Get_CellValue(Xls_Info.ValueType_column,i):
ValueType = '-'
else:
ValueType = '+'
if Xls_Info.Unit_column != 'FF' and Xls_Info.Unit_column != None and None != Get_CellValue(Xls_Info.Unit_column,i):
Unit = sheet[Xls_Info.Unit_column+str(i)].value.replace(' ','')
else:
Unit = ''
if Xls_Info.Sig_Multiplexortype != 'FF' and Xls_Info.Sig_Multiplexortype != None and None != Get_CellValue(Xls_Info.Sig_Multiplexortype,i):
if 'M' in Get_CellValue(Xls_Info.Sig_Multiplexortype,i) or 'm' in Get_CellValue(Xls_Info.Sig_Multiplexortype,i):
Multi_code = ' m'
else:
Multi_code = ' m' + Get_CellValue(Xls_Info.Sig_Multiplexortype,i)
else:
Multi_code = ''
dbc_code +=' SG_ ' + Get_CellValue(Xls_Info.Sig_Name_column,i) + Multi_code +' : ' + str(startbit) +\
'|' + Get_CellValue(Xls_Info.Size_column,i) + '@0' + ValueType + '(' + Get_CellValue(Xls_Info.Sig_Factor_column,i) + ',' +\
Get_CellValue(Xls_Info.Sig_Offset_column,i) + ') [' + Get_CellValue(Xls_Info.Min_column,i) + '|' +\
Get_CellValue(Xls_Info.Max_column,i) + '] \"' + Unit + '\" ' + receive_node + '\n'
# Sig Comment Gen ,Different manufacturers have different formats, to do.
""" if Xls_Info.Value_Description_column != 'FF' and Xls_Info.Value_Description_column != '' and None != sheet[Xls_Info.Value_Description_column+str(i)].value:
Sig_Comment += 'VAL_ ' + str(MSG_ID) + ' ' + sheet[Xls_Info.Sig_Name_column+str(i)].value.replace(' ','') + ' ' +\
sheet[Xls_Info.Value_Description_column+str(i)].value.replace(' ','').replace('0X','').replace('0x','').replace('\n','" ').replace(':',' "') + '" ;\n' """
dbc_txt +='VERSION ""\n\
\n\
\n\
NS_ : \n\
NS_DESC_\n\
CM_\n\
BA_DEF_\n\
BA_\n\
VAL_\n\
CAT_DEF_\n\
CAT_\n\
FILTER\n\
BA_DEF_DEF_\n\
EV_DATA_\n\
ENVVAR_DATA_\n\
SGTYPE_\n\
SGTYPE_VAL_\n\
BA_DEF_SGTYPE_\n\
BA_SGTYPE_\n\
SIG_TYPE_REF_\n\
VAL_TABLE_\n\
SIG_GROUP_\n\
SIG_VALTYPE_\n\
SIGTYPE_VALTYPE_\n\
BO_TX_BU_\n\
BA_DEF_REL_\n\
BA_REL_\n\
BA_DEF_DEF_REL_\n\
BU_SG_REL_\n\
BU_EV_REL_\n\
BU_BO_REL_\n\
SG_MUL_VAL_\n\
\n\
BS_:\n\
\n\
BU_: Vector__XXX '
dbc_txt += Get_CellValue(Xls_Info.Self_Node_colume,Xls_Info.Start_row) + '\n\n'
dbc_txt += dbc_code
dbc_txt += '\n\nBA_DEF_ BO_ "GenMsgCycleTime" FLOAT 0 300000;\n\
BA_DEF_ BO_ "GenMsgSendType" ENUM "cyclic","spontaneous","immediate";\n\
BA_DEF_ "BaudRate" FLOAT 0 2000000;\n\
BA_DEF_ "BusType" STRING ;\n\
BA_DEF_DEF_ "GenMsgCycleTime" 0;\n\
BA_DEF_DEF_ "GenMsgSendType" "cyclic";\n'
if dbc_canfd == True:
dbc_txt += 'BA_ "BusType" "CAN FD";\n\
BA_ "BaudRate" 2000000;\n'
else:
dbc_txt += 'BA_DEF_DEF_ "BaudRate" 500000;\n\
BA_DEF_DEF_ "BusType" "CAN";"'
dbc_txt += MSg_Comment +'\n'
#dbc_txt += Sig_Comment
print(dbc_txt)
file = open(script_dir+"\\inputfilename.dbc", "w")
file.write(dbc_txt)
file.close()
文章转载自公众号:汽车与基础软件