这篇文章主要讲解了Python实现CAN报文转换的方法,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。
成都创新互联公司是一家专业提供郊区企业网站建设,专注与网站制作、成都网站制作、H5响应式网站、小程序制作等业务。10年已为郊区众多企业、政府机构等服务。创新互联专业网站制作公司优惠进行中。一、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
或:35: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): break if(input_str.count(":")<4): print("输入格式错误,参数缺少setValue,请重新输入!") continue if(input_str.split(":")[4]==""): print("setValue参数不能为空,请重新输入!") continue sig.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]%8 lowLen = length[i] - highLen bit = [] #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))
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。