功能函数部分代码
import threading
import tkinter as tk
import serial
import serial.tools.list_ports
from tkinter import ttk
from tkinter import scrolledtext
from tkinter import END
import tkinter.messagebox
import binascii
import time
SerialPort = serial.Serial()
##创建窗口
GUI = tk.Tk()
GUI.title("松下伺服串口调试助手.(All copyrights reserved by Dage)")
GUI.geometry("530x380")
GUI.resizable(0, 0)
##发送函数
def WriteData():
try:
#global DataSend
DataSend = EntrySend.get()
DataSend = calc_crc16_modbus(DataSend)
if CrcStatus.get() == 1:
Information_Window.insert("end", '发送指令为:' + DataSend + '\n')
Information_Window.see("end")
DataSendHex = binascii.a2b_hex(DataSend)
SerialPort.write(DataSendHex)
else:
DataSend = DataSend[:-4]
Information_Window.insert("end", '发送指令为:' + DataSend + '\n')
Information_Window.see("end")
DataSendHex = binascii.a2b_hex(DataSend)
SerialPort.write(DataSendHex)
except:
tk.messagebox.showinfo('Port Error', '串口未打开')
return None
##接收函数
def ReceiveData():
while SerialPort.isOpen():
try:
ReceiveDataStr = SerialPort.readline().hex()
if len(ReceiveDataStr) != 0:
global TRANSDATA
TRANSDATA = ReceiveDataStr
ReturnData = ReceiveDataStr[:-4]
ReturnCRC = calc_crc16_modbus(ReturnData)[-4:]
if ReturnCRC == ReceiveDataStr[-4:]:
Receive_Window.insert("end", ReceiveDataStr + ' √'+'\n')
Receive_Window.see("end")
else:
Receive_Window.insert("end", ReceiveDataStr + ' ×'+'\n')
Receive_Window.see("end")
except:
SerialPort.close()
##关闭串口
def Close_Serial():
tk.Label(option, background='tomato', text="串口已关闭").grid(column=1, row=2,sticky='w')
SerialPort.close()
##打开串口
def Open_Serial():
SerialPort.port = Port_list.get()
SerialPort.baudrate = BaudRate_list.get()
SerialPort.bytesize = 8
SerialPort.stopbits = 1
SerialPort.timeout = 0.1
try:
SerialPort.open()
except:
tk.messagebox.showwarning('Port Error', '串口已打开或无此串口')
return None
if SerialPort.isOpen():
tk.Label(option, background='lime',text="串口已开启").grid(column=1, row=2,sticky='w')
t = threading.Thread(target=ReceiveData)
t.setDaemon(True)
t.start()
##增加CRC校验码
def calc_crc16_modbus(string):
data = bytearray.fromhex(string)
#data = string
crc = 0xFFFF
for pos in data: #pos是position的缩写是data的substr
crc ^= pos
for i in range(8):
if ((crc & 1) == 1):
crc >>= 1
crc ^= 0xA001
else:
crc >>= 1
A=hex(((crc & 0xff) << 8) + (crc >> 8))
B=data.hex()
return (B+A[2:6])
##清除所有窗口
def ClearAllDisplay():
Information_Window.delete(0.0, END)
Receive_Window.delete(0.0, END)
##读取编码器数值
def ReadRecoder():
try:
Data = '01 03 42 02 00 02'
Data = calc_crc16_modbus(Data)
DataSendHex = binascii.a2b_hex(Data)
SerialPort.write(DataSendHex)
time.sleep(0.2)
t2.delete(1.0,tkinter.END)
#print(int(TRANSDATA[10:14]+TRANSDATA[6:10],16))
t2.insert(1.0,int(TRANSDATA[10:14]+TRANSDATA[6:10],16))
except:
tk.messagebox.showinfo('Port Error', '串口未打开或读取编码器数值失败')
return None
##读取圈数
def ReadRounds():
try:
Data = '01 03 42 04 00 01'
Data = calc_crc16_modbus(Data)
DataSendHex = binascii.a2b_hex(Data)
SerialPort.write(DataSendHex)
t1.delete(1.0,tkinter.END)
print ('22222')
if TRANSDATA[0:7] == '010302f':
#print( (65535- int(TRANSDATA[6:10],16) ) )
t1.insert(1.0,'-')
t1.insert(1.1 ,(65535- int(TRANSDATA[6:10],16) ))
elif TRANSDATA[0:7] == '0103020':
#print(int(TRANSDATA[6:10],16))
t1.insert(1.0,'+')
t1.insert(1.1, int(TRANSDATA[6:10], 16))
else:
return None
except:
tk.messagebox.showinfo('Port Error', '串口未打开或读取圈数失败')
return None
##圈数清零
def ClearRounds():
try:
Data = '01 06 41 00 61 65'
Data = calc_crc16_modbus(Data)
DataSendHex = binascii.a2b_hex(Data)
SerialPort.write(DataSendHex)
except:
tk.messagebox.showinfo('Port Error', '串口未打开或圈数清零失败')
return None
def ChangeCrcSelText():
if CrcStatus.get() == 1:
CrcSelText.set('CrcSel')
else:
CrcSelText.set('CrcUnSel')
UI部分代码
#*************************** UI ****************************
######串口设定#####
option = tk.LabelFrame(GUI, text="串口设定", padx=10, pady=10) # 水平,垂直方向上的边距均为10
option.place(x=10, y=10, width=250) # 定位坐标
tk.Label(option, text=" 串口号: ").grid(column=0, row=0,sticky='w') # 添加串口号标签
tk.Label(option, text=" 波特率: ").grid(column=0, row=1,sticky='w') # 添加波特率标签
tk.Label(option, text="串口已关闭").grid(column=1, row=2,sticky='w')
tk.Button(option, text="打开串口", command=Open_Serial).grid(column=0, row=3)
tk.Button(option, text="关闭串口", command=Close_Serial).grid(column=1,row=3)
Port = tk.StringVar() # 端口号字符串
Port_list = ttk.Combobox(option, width=15, textvariable=Port, state='readonly')
ListPorts = list(serial.tools.list_ports.comports())
Port_list['values'] = [i[0] for i in ListPorts]
Port_list.current(0)
Port_list.grid(column=1, row=0)
BaudRate = tk.StringVar()
BaudRate_list = ttk.Combobox(option, width=15, textvariable=BaudRate, state='readonly')
BaudRate_list['values'] = (1200, 2400, 4800, 9600, 14400, 19200, 38400, 43000, 57600, 76800, 115200)
BaudRate_list.current(10)
BaudRate_list.grid(column=1, row=1)
######操作指令#####
Send = tk.LabelFrame(GUI, text="操作指令", padx=5, pady=5) # 水平,垂直方向上的边距均为 10
Send.place(x=10, y=155)
DataSend = tk.StringVar() # 定义DataSend为保存文本框内容的字符串
EntrySend = tk.StringVar()
Send_Window = ttk.Entry(Send, textvariable=EntrySend, width=25)
Send_Window.grid()
tk.Button(Send, text="发送", command=WriteData).grid(pady=5, sticky=tk.E)
######CRC校验后的操作指令#####
Information = tk.LabelFrame(GUI, text="增加CRC校验后的操作指令", padx=5, pady=5) # 水平,垂直方向上的边距均为10
Information.place(x=270, y=10)
Information_Window = scrolledtext.ScrolledText(Information, width=30, height=5, padx=5, pady = 10,wrap = tk.WORD)
Information_Window.grid()
######接收指令#####
Receive = tk.LabelFrame(GUI, text="接收指令", padx=5, pady=5) # 水平,垂直方向上的边距均为 10
Receive.place(x=270, y=130)
Receive_Window = scrolledtext.ScrolledText(Receive, width=30, height=5, padx=5, pady=10, wrap=tk.WORD)
Receive_Window.grid()
######清除按钮#####
tk.Button(text="清除", command=ClearAllDisplay).place(x=220,y=170)
######CRC选择######
CrcSelText = tk.StringVar()
CrcSelText.set('CrcUnSel')
CrcStatus = tk.IntVar()
tk.Checkbutton(GUI, variable=CrcStatus,command=ChangeCrcSelText).place(x=225,y=210) # 给Checkbutton添加选中事件
tk.Label(GUI, textvariable=CrcSelText).place(x=210,y=230)
######读回编码器信息#####
Recoder = tk.LabelFrame(GUI, text="编码器信息读取", padx=5, pady=5) # 水平,垂直方向上的边距均为10
Recoder.place(x=10, y=250)
tk.Label(Recoder, text=" 圈数解析:").grid(column=0, row=0)
t1 = tk.Text(Recoder,width=15, height=1)
t1.grid(column=1, row=0)
tk.Label(Recoder, text="编码值解析:").grid(column=0, row=2)
t2 = tk.Text(Recoder,width=15, height=1)
t2.grid(column=1, row=2)
tk.Button(Recoder, text="读取圈数", command=ReadRounds).grid(column=3, row=0)
tk.Button(Recoder, text="圈数清零", command=ClearRounds).grid(column=5, row=0)
tk.Button(Recoder, text="读编码值", command=ReadRecoder).grid(column=3, row=2)
tk.Label(Recoder, text="").grid(column=0, row=1)
tk.Label(Recoder, text="").grid(column=2, row=0)
tk.Label(Recoder, text="").grid(column=4, row=0)
GUI.mainloop()