一、CAN报文简介

CAN是控制器局域网络(Controller Area Network, CAN)的简称,是由以研发和生产汽车电子产品著称的德国BOSCH公司开发的,并最终成为国际标准(ISO 11898),是国际上应用最广泛的现场总线之一。 在北美和西欧,CAN总线协议已经成为汽车计算机控制系统和嵌入式工业控制局域网的标准总线,并且拥有以CAN为底层协议专为大型货车和重工机械车辆设计的J1939协议。

CAN总线以报文为单位进行数据传送。CAN报文按照帧格式可分为标准帧和扩展帧,标准帧是具有11位标识符的CAN帧,扩展帧是具有29位标识符的CAN帧。按照帧类型可分为:1.从发送节点向其它节点发送数据;2.远程帧:向其它节点请求发送具有同一识别符的数据帧;3.错误帧:指明已检测到总线错误;4.过载帧:过载帧用以在数据帧(或远程帧)之间提供一附加的延时。共有两种编码格式:Intel格式和Motorola格式,在编码优缺点上,Motorola格式与Intel格式并没有孰优孰劣之分,只不过根据设计者的习惯,由用户自主选择罢了。当然,对于使用者来讲,在进行解析之前,就必须要知道编码的格式是哪一种,否则,就不能保证正确地解析信号的含义。以下就以8位字节编码方式的CAN总线信号为例,详细分析一下两者之间的区别。

Intel编码格式

当一个信号的数据长度不超过1个字节(8位)并且信号在一个字节内实现(即该信号没有跨字节实现):该信号的高位(S_msb)将被放在该字节的高位,信号的低位(S_lsb)将被放在该字节的低位。
当一个信号的数据长度超过1个字节(8位)或者数据长度不超过一个字节但是采用跨字节方式实现时:该信号的高位(S_msb)将被放在高字节(MSB)的高位,信号的低位(S_lsb)将被放在低字节(LSB)的低位。

Motorola编码格式

当一个信号的数据长度不超过1个字节(8位)并且信号在一个字节内实现(即该信号没有跨字节实现):该信号的高位(S_msb)将被放在该字节的高位,信号的低位(S_lsb)将被放在该字节的低位。
当一个信号的数据长度超过1个字节(8位)或者数据长度不超过一个字节但是采用跨字节方式实现时:该信号的高位(S_msb)将被放在低字节(MSB)的高位,信号的低位(S_lsb)将被放在高字节(LSB)的低位。
可以看出,当一个信号的数据长度不超过1Byte时,Intel与Motorola两种格式的编码结果没有什么不同,完全一样。当信号的数据长度超过1Byte时,两者的编码结果出现了明显的不同。

二、CAN报文转换工具需求分析

1、 支持标准帧的CAN报文的转换,扩展帧暂不支持

2、 CAN报文支持Intel、motorola两种编码,先支持motorola格式,后期追加Intel格式

3、 工具具有一定的容错处理能力、报告生成能力

4、 制定统一格式,方便使用者修改测试脚本

5、增加交互模式,键盘输入,控制台输出;例如:

提示语:startBit:length:minValue:maxValue:setValue

输入:35:1:0:1:1

控制台输出:00 00 00 00 08 00 00 00

Intel和Motorola编码举例:

三、交互模式

代码如下:

import sys
print("----------------欢迎使用CAN报文转换工具交互模式----------------")
print("请输入CAN信号,格式为:startBit:length:minValue:maxValue:setValue")
print("例如:32:1:0:1:1")
print("或者省略minValue和maxValue:35:1:::1")
print("信号输入结束请再按一次回车")#十进制转换成二进制list
def octToBin(octNum, bit):while(octNum != 0):bit.append(octNum%2)octNum = int(octNum/2)for i in range(64-len(bit)):bit.append(0)sig = []
startBit = []
length = []
setValue = []
#输入CAN信号
while True:input_str = input()if not len(input_str):breakif(input_str.count(":")<4):print("输入格式错误,参数缺少setValue,请重新输入!")continueif(input_str.split(":")[4]==""):print("setValue参数不能为空,请重新输入!")continuesig.append(input_str)
#解析CAN信号
for i in range(len(sig)):startBit.append(int(sig[i].split(":")[0]))length.append(int(sig[i].split(":")[1]))setValue.append(int(sig[i].split(":")[4]))
#CAN数组存放CAN报文值
CAN = []
for i in range(64):CAN.append(-1)
for i in range(len(startBit)):#长度超过1Byte的情况,暂不支持if(length[i]>16):print("CAN信号长度超过2Byte,暂不支持!!!")sys.stdin.readline()sys.exit()#长度未超过1Byte的情况且未跨字节的信号if((startBit[i]%8 + length[i])<=8):for j in range(length[i]):bit = []#setValue的二进制值按字节位从低到高填octToBin(setValue[i],bit)#填满字节长度值if(CAN[startBit[i]+j]==-1):CAN[startBit[i]+j] = bit[j]#字节存在冲突else:print(sig[i] + "字节位存在冲突,生成CAN报文失败!!!")sys.stdin.readline()sys.exit()#跨字节的信号else:#高位位数和低位位数highLen = 8 - startBit[i]%8lowLen = length[i] - highLenbit = []#setValue的二进制值按字节位从低到高填octToBin(setValue[i],bit)#先填进信号的高位for j1 in range(highLen):if(CAN[startBit[i]+j1]==-1):CAN[startBit[i]+j1] = bit[j1]#字节存在冲突else:print(sig[i] + "字节位存在冲突,生成CAN报文失败!!!")sys.stdin.readline()sys.exit()#再填进信号的低位for j2 in range(lowLen):if(CAN[(int(startBit[i]/8)-1)*8+j2]==-1):CAN[(int(startBit[i]/8)-1)*8+j2] = bit[highLen+j2]#字节存在冲突else:print(sig[i] + "字节位存在冲突,生成CAN报文失败!!!")sys.stdin.readline()sys.exit()
#剩余位默认值设为0
for i in range(64):if(CAN[i]==-1):CAN[i] = 0
#----------------将二进制list每隔8位转换成十六进制输出----------------
#其中,map()将list中的数字转成字符串,按照Motorola格式每隔8位采用了逆序
# ''.join()将二进制list转换成二进制字符串,int()将二进制字符串转换成十进制
#hex()再将十进制转换成十六进制,upper()转换成大写,两个lstrip()将"0X"删除,
#zfill()填充两位,输出不换行,以空格分隔
print(hex(int(''.join(map(str,CAN[7::-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")
print(hex(int(''.join(map(str,CAN[15:7:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")
print(hex(int(''.join(map(str,CAN[23:15:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")
print(hex(int(''.join(map(str,CAN[31:23:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")
print(hex(int(''.join(map(str,CAN[39:31:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")
print(hex(int(''.join(map(str,CAN[47:39:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")
print(hex(int(''.join(map(str,CAN[55:47:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")
print(hex(int(''.join(map(str,CAN[63:55:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))

错误提示:

四、配置项模式

配置文件如下:

##注释
::start
#编码格式:0=Intel;1=Motorola
encodeType=1
#帧格式:0=标准帧;1=扩展帧;
canMode=0
#帧类型:0=数据帧;...
canType=0
#默认初始值(0~1)
defaultValue=0
#MSG定义
msgName=BCM_FrP01
msgID=0x2CD
#长度(BYTE)
msgLength=8
#signal定义
#sigName=name:startBit:length:minValue:maxValue:setValue
#sigName=ReverseSw:25:6:0:1:13
#sigName=Trunk_BackDoor_Sts:33:2:0:1:2
#sigName=DRVUnlockState:37:2:0:1:3
#sigName=HeadLampLowBeam:40:8:0:1:60
#sigName=HoodStatus:51:1:0:1:0
#sigName=HeadLampHighBeam:52:1:0:1:0
#sigName=RLDoorStatus:59:1:0:1:0
#sigName=RRDoorStatus:58:1:0:1:0
#sigName=PsgDoorStatus:57:2:0:1:0
sigName=One:0:8:0:255:165
sigName=Two:24:12:0:4095:1701
sigName=Three:54:5:0:31:25
::end
::start
#编码格式:0=Intel;1=Motorola
encodeType=1
#帧格式:0=标准帧;1=扩展帧;
canMode=0
#帧类型:0=数据帧;...
canType=0
#默认初始值(0~1)
defaultValue=0
#MSG定义
msgName=BCM_FrP
msgID=0x2CD
#长度(BYTE)
msgLength=8
#signal定义
#sigName=name:startBit:length:minValue:maxValue:setValue
#sigName=ReverseSw:25:6:0:1:13
#sigName=Trunk_BackDoor_Sts:33:2:0:1:2
#sigName=DRVUnlockState:37:2:0:1:3
#sigName=HeadLampLowBeam:40:8:0:1:60
#sigName=HoodStatus:51:1:0:1:0
#sigName=HeadLampHighBeam:52:1:0:1:0
#sigName=RLDoorStatus:59:1:0:1:0
#sigName=RRDoorStatus:58:1:0:1:0
#sigName=PsgDoorStatus:57:2:0:1:0
sigName=One:35:1:0:1:1
::end

代码如下:

#!/usr/bin/python
defaultValue = 0
sigName = []
startBit = []
length = []
minValue = []
maxValue = []
setValue = []
#CAN数组存放CAN报文值
CAN = []
logFile = open("log.txt","w")
def parseConfig():config = open("Config.txt","r")count = 0isError = Falsefor line in config:line = line.strip()#注释if(line.find("#")>=0):continue#开始标记elif(line.find("::start")>=0):count = count + 1isError = Falseif(count>1):sigName.clear()startBit.clear()length.clear()setValue.clear()continueelse:continueelif(isError == True):continue#编码格式elif(line.find("encodeType")>=0):encodeType = line.split("=")[1]if(encodeType != "1"):isError = Trueprint(str(count) + ". CAN报文生成失败!!!目前仅支持Motorola编码格式,暂不支持Intel编码格式!")logFile.write("%d. CAN报文生成失败!!!目前仅支持Motorola编码格式,暂不支持Intel编码格式!n" % count)continue#帧格式elif(line.find("canMode")>=0):canMode = line.split("=")[1]if(canMode != "0"):isError = Trueprint(str(count) + ". CAN报文生成失败!!!目前仅支持标准帧,暂不支持扩展帧!")logFile.write("%d. CAN报文生成失败!!!目前仅支持标准帧,暂不支持扩展帧!n" % count)continue#帧类型elif(line.find("canType")>=0):canType = line.split("=")[1]if(canType != "0"):isError = Trueprint(str(count) + ". CAN报文生成失败!!!目前仅支持数据帧,暂不支持其他帧!")logFile.write("%d. CAN报文生成失败!!!目前仅支持数据帧,暂不支持其他帧!n" % count)continue#默认初始值elif(line.find("defaultValue")>=0):global defaultValuedefaultValue = int(line.split("=")[1])#MSG名称elif(line.find("msgName")>=0):msgName = line.split("=")[1]#MSGIDelif(line.find("msgID")>=0):msgID = line.split("=")[1]#MSG长度elif(line.find("msgLength")>=0):msgLength = line.split("=")[1]#signal定义elif(line.find("sigName")>=0):sigName.append(line.split(":")[0].split("=")[1])startBit.append(int(line.split(":")[1]))length.append(int(line.split(":")[2]))#minValue.append(int(line.split(":")[3]))#maxValue.append(int(line.split(":")[4]))setValue.append(int(line.split(":")[5]))elif(line.find("::end")>=0):rV,errMsg = getCANMessage()if(rV == "-1"):isError = Trueprint(str(count) + ". CAN报文生成失败!!!" + errMsg)logFile.write("%d. CAN报文生成失败!!!%sn" % (count,errMsg))continueprint(str(count) + ". CAN报文生成成功!!!")logFile.write("%d. CAN报文生成成功!!!n" % count)#----------------------------输出标题信息----------------------------print("msgNamettmsgIDttmsgLenttmsgData")logFile.write("msgNamettmsgIDttmsgLenttmsgDatan")if(len(msgName)<8):print(msgName + "tt",end="")logFile.write("%stt" % msgName)else:print(msgName + "t",end="")logFile.write("%st" % msgName)print(msgID + "tt",end="")logFile.write("%stt" % msgID)print(msgLength + "tt",end="")logFile.write("%stt" % msgLength)#----------------将二进制list每隔8位转换成十六进制输出----------------#其中,map()将list中的数字转成字符串,按照Motorola格式每隔8位采用了逆序# ''.join()将二进制list转换成二进制字符串,int()将二进制字符串转换成十进制#hex()再将十进制转换成十六进制,upper()转换成大写,两个lstrip()将"0X"删除,#zfill()填充两位,输出不换行,以空格分隔print(hex(int(''.join(map(str,CAN[7::-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")print(hex(int(''.join(map(str,CAN[15:7:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")print(hex(int(''.join(map(str,CAN[23:15:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")print(hex(int(''.join(map(str,CAN[31:23:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")print(hex(int(''.join(map(str,CAN[39:31:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")print(hex(int(''.join(map(str,CAN[47:39:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")print(hex(int(''.join(map(str,CAN[55:47:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2) + " ",end="")print(hex(int(''.join(map(str,CAN[63:55:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%s " % hex(int(''.join(map(str,CAN[7::-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%s " % hex(int(''.join(map(str,CAN[15:7:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%s " % hex(int(''.join(map(str,CAN[23:15:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%s " % hex(int(''.join(map(str,CAN[31:23:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%s " % hex(int(''.join(map(str,CAN[39:31:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%s " % hex(int(''.join(map(str,CAN[47:39:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%s " % hex(int(''.join(map(str,CAN[55:47:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))logFile.write("%sn" % hex(int(''.join(map(str,CAN[63:55:-1])),2)).upper().lstrip("0").lstrip("X").zfill(2))config.close()#十进制转换成二进制list
def octToBin(octNum, bit):while(octNum != 0):bit.append(octNum%2)octNum = int(octNum/2)for i in range(64-len(bit)):bit.append(0)#获取CAN报文值
def getCANMessage():CAN.clear()for i in range(64):CAN.append(-1)for i in range(len(startBit)):#长度超过1Byte的情况,暂不支持if(length[i]>16):errMsg = " CAN信号长度超过2Byte,暂不支持!!!"#print(sigName[i] + errMsg)return "-1",errMsg#长度未超过1Byte的情况且未跨字节的信号if((startBit[i]%8 + length[i])<=8):for j in range(length[i]):bit = []#setValue的二进制值按字节位从低到高填octToBin(setValue[i],bit)#填满字节长度值if(CAN[startBit[i]+j]==-1):CAN[startBit[i]+j] = bit[j]#字节存在冲突else:errMsg = " 字节位存在冲突,生成CAN报文失败!!!"#print(sigName[i] + errMsg)return "-1",errMsg#跨字节的信号else:#高位位数和低位位数highLen = 8 - startBit[i]%8lowLen = length[i] - highLenbit = []#setValue的二进制值按字节位从低到高填octToBin(setValue[i],bit)#先填进信号的高位for j1 in range(highLen):if(CAN[startBit[i]+j1]==-1):CAN[startBit[i]+j1] = bit[j1]#字节存在冲突else:errMsg = " 字节位存在冲突,生成CAN报文失败!!!"#print(sigName[i] + errMsg)return "-1",errMsg#再填进信号的低位for j2 in range(lowLen):if(CAN[(int(startBit[i]/8)-1)*8+j2]==-1):CAN[(int(startBit[i]/8)-1)*8+j2] = bit[highLen+j2]#字节存在冲突else:errMsg = " 字节位存在冲突,生成CAN报文失败!!!"#print(sigName[i] + errMsg)return "-1",errMsg#剩余位设为默认值for i in range(64):if(CAN[i]==-1):CAN[i] = defaultValue#若无错误则返回正确值return "0","success!"if __name__ == "__main__":#调用parseConfig()函数开始执行程序parseConfig()

运行结果:

1. CAN报文生成成功!!!
msgName     msgID       msgLen      msgData
BCM_FrP01   0x2CD       8       A5 00 06 A5 00 06 40 00
2. CAN报文生成成功!!!
msgName     msgID       msgLen      msgData
BCM_FrP     0x2CD       8       00 00 00 00 08 00 00 00

在将varchar值id转换为int时失败_Python—CAN报文转换工具教程相关推荐

  1. 在将varchar值id转换为int时失败_C++繁琐的类型转换,C++小知识之四种类型转换

    有时,编程的过程中需要将值从一种数据类型转换为另一种数据类型. 在C语言中,强制类型转换的方式为(Type)Expression,另外还有一种现在已经不用的旧式写法Type(Expression),这 ...

  2. 在将varchar值id转换为int时失败_MySQL令人咋舌的隐式转换

    导读 作者徐晨亮,MySQL DBA,知数堂学员.热衷于数据库优化,自动化运维及数据库周边工具开发,对MySQL源码有一定的兴趣 本文建议横屏观看,效果更佳 一.问题描述 root@mysqldb 2 ...

  3. 消息 245,级别 16,状态 1,第 1 行 在将 varchar 值 '2,8' 转换成数据类型 int 时失败。...

    错误问题: 消息 245,级别 16,状态 1,第 1 行 在将 varchar 值 '2,8' 转换成数据类型 int 时失败. ps: 这是在后台分配菜单权限这个功能时出现的问题 一,解决方法: ...

  4. 将 varchar 值 'ACCE5057EC423F7C' 转换成数据类型 int 时失败

    调试别人的存储过程,然后报错了 将 varchar 值 'ACCE5057EC423F7C' 转换成数据类型 int 时失败 这让我一通找.找了一个多小时. 通过这个错可以知道,错误肯定是在联表 字段 ...

  5. 佩特来项目经验小集合(2)___组合查询存储过程,报错 quot;varchar JBID=#39;#39; 转换成数据类型 int 时失败quot;...

       今天写一个组合查询的存储过程遇到这样一个问题:在将 varchar 值 'SELECT * FROM View_DLS_WXJD_Customer WHERE 1=1 and JBID ='' ...

  6. mysql in 数字类型_关于sql where id in 转换成数据类型 int 时失败

    有执行sql条件语句where id in(@参数)的时候,如果处理不当,就会出现问题: 有执行sql条件语句where id in(@参数)的时候,如果处理不当,就会出现问题: 如下面这个存储过程: ...

  7. 异常处理·MSSQL·在将nvarchar值‘XXX‘转换成数据类型int时失败

    阅文时长 | 0.16分钟 字数统计 | 260.8字符 主要内容 | 1.引言&背景 2.声明与参考资料 『异常处理·MSSQL·在将nvarchar值'XXX'转换成数据类型int时失败』 ...

  8. sql server将字符串转换为 uniqueidentifier 时失败

    sql server将字符串转换为 uniqueidentifier 时失败 sql server查询中出现 将字符串转换为 uniqueidentifier 时失败异常 原因为id设置为unique ...

  9. 将字符串转换为 uniqueidentifier 时失败的解决方法

    将字符串转换为 uniqueidentifier 时失败的解决方法 参考文章: (1)将字符串转换为 uniqueidentifier 时失败的解决方法 (2)https://www.cnblogs. ...

最新文章

  1. 应届生web前端面试题_2020最新Web前端经典面试题试题及答案(持续更新)
  2. 记-curl post json数据,服务器后端$_POST接收不到数据
  3. 《Linux高性能服务器编程》学习笔记
  4. 【倍增】【线段树】雨林跳跃(luogu 7599[APIO 2021 T2])
  5. 漫步最优化三十七——共轭梯度法
  6. zblog php 调用缩略图,缩略图插件
  7. 让 AI 教机器自己玩俄罗斯方块
  8. Wpf ScrollBar自定义样式
  9. java类加载器用途_对于java类加载器的认识(2)
  10. 国家地理相关资源数据库
  11. python制作股票图表-专题:Python matplotlib 绘制股票走势图
  12. python turtle画表情包
  13. 什么是CPU?什么是计算机?
  14. Installation failed with message Failed to finalize session : INSTALL_FAILED_INVALID_APK:
  15. 饼图加引导线_如何在饼形图中添加引导线(Excel)/
  16. Python 进阶(七): Word 基本操作
  17. afrog 进阶篇(实战)
  18. C语言吞食鱼,大鱼吃小鱼.cpp · 2019春C语言/programming-1 - Gitee.com
  19. 元宇宙赛道火热已是共识!上市公司正加码布局,基础设施支撑待完善
  20. 新时达工业机器人技术储备_建成年产万台机器人工厂后, 新时达在想些什么?...

热门文章

  1. 364 页 PyTorch 版《动手学深度学习》PDF 开源了(全中文,支持 Jupyter 运行)
  2. 炼丹侠必知的9大池化操作​汇总
  3. SpringMVC-RestfulCRUD
  4. 奶茶妹妹亏本甩卖悉尼豪宅 当年与刘强东澳洲办盛大婚礼
  5. html常用样式margin、border怎么使用
  6. 对Javascript 类、原型链、继承的理解
  7. 图的基本操作实现(数据结构实验)
  8. https和server-status配置案例
  9. 带你攀顶云端高级认证,有这回事?
  10. js 控制按钮点击后不可用(用于短信或者邮箱验证)