python解析与打包串口数据

概述

前段时间做一个项目,我们的系统使用串口与MCU进行数据交互,系统侧代码已按照双方约定的数据包协议写好了解析与发送数据的代码,但是MCU侧还未完成代码,我们不能等待他们完成之后在进行代码的调试,这样会耽误项目的进度,网上查阅了相关资料后。最后决定使用python脚本来完成数据的解析与打包进行模拟测试,网上也查了不少资料,最终实现了模拟数据完成了代码的调试,此脚本主要使用了python的两个模块serial(串口操作)与struct(打包成c语言的字节串)。一些简要说明:

serial模块

主要用户串口操作,网络上资料也挺多的,这里直接上代码进行注释说明

class ComThread:
 def __init__(self, Port='COM56'): #打开COM56
  self.l_serial = None 
  self.alive = False
  self.waitEnd = None
  self.port = Port
  self.ID = None
  self.data = None

 def waiting(self):
  if not self.waitEnd is None:
   self.waitEnd.wait()

 def SetStopEvent(self):
  if not self.waitEnd is None:
   self.waitEnd.set()
  self.alive = False
  self.stop()

 def start(self):
  self.l_serial = serial.Serial()
  self.l_serial.port = self.port
  self.l_serial.baudrate = 115200 #串口波特率
  self.l_serial.timeout = 2 #超时时间
  self.l_serial.open()
  if self.l_serial.isOpen():
   self.waitEnd = threading.Event()
   self.alive = True
   self.thread_read = None
   self.thread_read = threading.Thread(target=self.FirstReader)
   self.thread_read.setDaemon(1)
   self.thread_read.start()
   return True
  else:
   return False

 def SendDate(self,i_msg,send):
  #lmsg = ''
  isOK = False
  #发送数据到相应的处理组件
  print(i_msg)
  send_buf = nwy_create_send_msg(i_msg, send)
  self.l_serial.write(send_buf)
  print("send success")
  return True
 def FirstReader(self):
  while self.alive:
   time.sleep(0.1)
   data = ''
   data = data.encode('utf-8')
   n = self.l_serial.inWaiting()
   if n:
    data = data + self.l_serial.read(n)
    print(len(data))#打印收到的数据
    print(data.hex()) #按照十六进制打印

 def stop(self):
  self.alive = False
  self.thread_read.join()
  if self.l_serial.isOpen():
   self.l_serial.close()
   
def quit(signum, frame):
 print("Bye Bye!")
 sys.exit(0)

#调用串口,测试串口
def main():
 rt = ComThread()
 rt.sendport = '**1*80*'
 try:
  if  rt.start():
   signal.signal(signal.SIGINT, quit)
   print(rt.l_serial.name)
   #rt.waiting()
   #print("The data is:%s,The Id is:%s"%(rt.data,rt.ID))
   #t.stop()
  else:
   pass
 except Exception as se:
  print(str(se))
  print ('End OK .')
 return rt

if __name__ == '__main__':
 mSerial = main()
 while True:
  time.sleep(1)

struct模块

串口数据解析,这里并没有使用unpack进行解析,这里是按照当前的定义进行的解析

def parse_read_data(data, len):
 print(data)
 print(len)
 #check head
 if 0x0F != data[0]:#判断数据头
  print ("head is not 0x0F data head is " + hex(data[0]))
  return False
 #get msg id 
 msg_id = data[1] << 8 | data[2] #获取消息ID
 msg_len = data[3] << 8 | data[4] #获取数据长度
 data_crc = data[7+msg_len] #获取数据的校验和
 Cal_crc = Calculation_crc(data[1:len-2]) #计算数据的校验和
 if data_crc != Cal_crc: #判断数据的校验和
  print ("crc error ")
  return False
 print ("data is good")
  #do something 
 #处理数据 
 return True

将需要发送的数据打包成固定格式的字节串,具体打包要按照实际的协议打包 ,strcut的详细解释资料太多,这里不再赘述

def create_send_msg(i_msg, send):
 msg_len = len(send)
 msg_len_2 = ~msg_len
 #下面就类似于c预言的printf 不过可以查查struct中对应的类型
 # !表示大端
 # H unsigned short
 # h singned short 这里用h主要是长度的反码如果有无符号会提示存不下,所以用有符号
 # %ds 这个比较特殊,s为字节串,长度为%d 
 # B byte
 psh = struct.pack('!HHh%ds'%len(send), i_msg, msg_len, msg_len_2,send)
 # 计算crc
 crc = Calculation_crc(psh)
  # c语言的结构体定义如下
 # struct{
 #  unsigned char  header
 #  unsigned short msgid
 #  unsigned short msglen
 #  signed short   unmsglen
 #  char *data
 #  unsigned char   crc
 #  unsigned char   end
 # }
 pshhh = struct.pack('!BHHh%dsBB' %len(send), MSG_HEADER, i_msg, msg_len, msg_len_2,send, crc, MSG_END)
 return pshhh

完整的示例代码如下

import struct
import binascii
import sys
import signal
import threading
import time
import serial
import random
MSG_HEADER=0x0F
MSG_END=0xF0
MCU_MSG_ID=0x0001

def create_send_msg(i_msg, send):
 msg_len = len(send)
 msg_len_2 = ~msg_len
 #下面就类似于c预言的printf 不过可以查查struct中对应的类型
 # !表示大端
 # H unsigned short
 # h singned short 这里用h主要是长度的反码如果有无符号会提示存不下,所以用有符号
 # %ds 这个比较特殊,s为字节串,长度为%d 
 # B byte
 psh = struct.pack('!HHh%ds'%len(send), i_msg, msg_len, msg_len_2,send)
 # 计算crc
 crc = Calculation_crc(psh)
  # c语言的结构体定义如下
 # struct{
 #  unsigned char  header
 #  unsigned short msgid
 #  unsigned short msglen
 #  signed short   unmsglen
 #  char *data
 #  unsigned char   crc
 #  unsigned char   end
 # }
 pshhh = struct.pack('!BHHh%dsBB' %len(send), MSG_HEADER, i_msg, msg_len, msg_len_2,send, crc, MSG_END)
 return pshhh

def send_mcu_data(data):
 msg = "FF000000FFECFFD7FC03000000000000"; #模拟的一包数据
 by = binascii.a2b_hex(msg)
 mSerial.SendDate(MCU_MSG_ID, by)
 return

#计算校验和  
def Calculation_crc(data): 
 crc = 0
 for i in range(len(data)): 
  crc ^= data[i]
 return crc

def parse_read_data(data, len):
 print(data)
 print(len)
 #check head
 if 0x0F != data[0]:#判断数据头
  print ("head is not 0x0F data head is " + hex(data[0]))
  return False
 #get msg id 
 msg_id = data[1] << 8 | data[2] #获取消息ID
 msg_len = data[3] << 8 | data[4] #获取数据长度
 data_crc = data[7+msg_len] #获取数据的校验和
 Cal_crc = Calculation_crc(data[1:len-2]) #计算数据的校验和
 if data_crc != Cal_crc: #判断数据的校验和
  print ("crc error ")
  return False
 print ("data is good")
  #do something 
 #处理数据 
 return True
class ComThread:
 def __init__(self, Port='COM56'):
  self.l_serial = None
  self.alive = False
  self.waitEnd = None
  self.port = Port
  self.ID = None
  self.data = None
 def waiting(self):
  if not self.waitEnd is None:
   self.waitEnd.wait()
 def SetStopEvent(self):
  if not self.waitEnd is None:
   self.waitEnd.set()
  self.alive = False
  self.stop()

 def start(self):
  self.l_serial = serial.Serial()
  self.l_serial.port = self.port
  self.l_serial.baudrate = 230400
  self.l_serial.timeout = 2
  self.l_serial.open()
  if self.l_serial.isOpen():
   self.waitEnd = threading.Event()
   self.alive = True
   self.thread_read = None
   self.thread_read = threading.Thread(target=self.FirstReader)
   self.thread_read.setDaemon(1)
   self.thread_read.start()
   return True
  else:
   return False
 def SendDate(self,i_msg,send):
  send_buf = create_send_msg(i_msg, send)
  self.l_serial.write(send_buf)
  print("send success")
  return True

 def FirstReader(self):
  while self.alive:
   time.sleep(0.1)
   data = ''
   data = data.encode('utf-8')
   n = self.l_serial.inWaiting()
   if n:
    data = data + self.l_serial.read(n)
    #print(len(data))
    #print(data.hex())
    parse_read_data(data, len(data))
 def stop(self):
  self.alive = False
  self.thread_read.join()
  if self.l_serial.isOpen():
   self.l_serial.close()
  def quit(signum, frame):
 print("Bye Bye!")
 sys.exit(0)
#调用串口,测试串口
def main():
 rt = ComThread()
 rt.sendport = '**1*80*'
 try:
  if  rt.start():
   signal.signal(signal.SIGINT, quit)
   print(rt.l_serial.name)
  else:
   pass
 except Exception as se:
  print(str(se))
  print ('End OK .')
 return rt
if __name__ == '__main__':
 mSerial = main()
 while True:
  time.sleep(1)
  #发送给系统数据
  send_mcu_data(mSerial)

以上就是我的分享,如果有需要探讨的可以加qq 991410485

猜你喜欢

转载自blog.csdn.net/weixin_35933684/article/details/108288943