Python语言实现串口接收报文、由帧格式进行解析
整体概述
好的! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
说明:(基于 Python3.7、Windows平台)
一、需求:通过232串口接收实时报文,解析为YX、YC
1、需要判断指示器的类型,根据不同类型进行解析;
2、显示对应的告警信息,包括:过温、电池电压、故障信息、温度值、电池电压值、电流值等;
3、报文接收,实时解析并打印显示;
4、将解析后的报文按格式另存为本地文件,用于后续的数据分析。
二、关键功能
1、报文帧格式解析
2、字符串分割(2字节)
3、进制转换(十六 ~ 二进制)
4、温度转换(华氏度℉ ~ 摄氏度℃)
4、报文拼接、格式化输出
三、依赖moudule:serial、re、tkinker、time
1、串口实现
from serial import * # py3 安装:pip install pyserial
ser = Serial(port_x, bps, timeout=time_x)
bw = ser.readline(11).hex().upper()
2、字符串分割
new_list = ser.findall(r’{2}’, bw)
3、文件保存函数 fileSave()
fileSave(str(new_list)) # 保存为log.txt
4、进制转换
list1 = [‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’]
报文帧重组:bin(), oct(), int(), hex()
5、温度转换
华氏°F = ℃×9/5+32 | 摄氏℃ = 5/9(°F-32)
6、格式化输出
print(‘我说%s’ % ss )
print(‘我说{0}’.format(ss))
四、具体实现展示
1)控制台串口
输入实际串口号,开始接收报文,超时设置为 2S
# 函数 mainTask()
try:
print('''欢迎使用,**型故指报文解析工具 V1.0
接下来:
请查看:我的电脑 -> 管理 -> 设备管理:COM ?
''')
dk = input('默认端口号:')
port_x = "COM{0}".format(dk)
ser = serial.Serial(port_x, 9600, timeout=2) # 具体参数设置请查看开源文档
# print('串口详情:', ser)
# 写数据
# result = ser.write("总召唤".encode("gbk"))
# time.sleep(1)
# print("写总字节数=", result)
time.sleep(1)
print('提示:等待报文...... 等,就对了~\n')
# 读取串口数据
while True:
bw = ser.readline(11).hex().upper() # 串口接收
...
...
except Exception as e:
print('异常', e)
2)将报文按一定格式,保存为本地文件
判断报文帧的报头、报文长度len(o)、处理不完整报文帧
# 函数 fileSave()
def fileSave(cont): # 加入形参“cont”,复用多次追加写入(str类型)
# 时间戳
now_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 小写Y 显示“19”
# 写入的内容
# print(bw, len(bw), type(bw))
with open('log.txt', 'a', encoding='utf-8') as f: # r只读,w可写,a追加
if len(cont) == 0: # 报文为空,过滤
pass
elif len(cont) == 2: # 报文为None,过滤
pass
elif 2 < len(cont) < 11: # 报文不完整,追加
f.write(cont)
# 打印当前报文
print('报文段:', cont, '追加为完整报文')
# print('追加为完整报文')
# bw = new_list.split(' ')
# print(bw, type(bw))
else: # 报文完整,写入后,换行
f.write(now_time + ':' + cont)
f.write('\n')
# f.close() # 该方法无需手动关闭文件 with open() as f:
3)报文解析实现
指示器使用内部规约进行通信,了解到对应的报文帧格式进行解析
此处只讲遇到的问题:
1、进制准换(转换二进制,解析每一个bit位的开/合状态)
2、温度转换
# 函数 gzAnasis()
...
...
# 十六进制 -> 二进制 去除'0b'帧
gz = list(bin(int(x[6], 16))) # 故障帧
# gz2 = list(bin(int(x[7], 16))) # update status
# print(gz, type(gz))
del gz[0]
# 解决二进制转换后,报文帧无法点位问题
list1 = ['0', '0', '0', '0', '0', '0', '0', '0'] # 默认列表
# print(list1, len(list1), type(list1))
if len(gz) < 8: # 低4位,高4位
list1.extend(gz)
if len(list1) > 8:
del list1[0]
# print(list1)
print('故障:', list1[5])
# print('debug')
bat = (int(x[8], 16) + int(x[9], 16) * 256) / 100 # 指示器电池电压:3.64V
# 温度转换
def hs2ss(k):
tem = 5 / 9 * (k - 32)
temp = round(tem, 1) # 保留1位小数
return temp
inf = ('A lot of things'.format()) # 格式化输出
print(inf)
fileSave(inf) # 调用函数,将结果写入文件
...
...
4)目前还使用控制台界面进行实时展示,后续结合tkinker进行界面生成,把数据一抛,完整的小工具就OK 啦 哈哈~
print('^_^' * 100)
# 函数 Gui()
from tkinker import *
tk = TK()
...
…………