概述
前段时间做一个项目,我们的系统使用串口与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