基于python+tkinter+pyserial实现的串口PID调试助手

以下为源码,有问题请留言:

#coding=utf-8
from tkinter import *
import serial
import serial.tools.list_ports
from tkinter import messagebox
import threading
from decimal import *
import struct
from pynput.keyboard import Controller,Key,Listener

order={
    'sendData':            0x01,
    'requestData':         0x02,
    'dataOk':              0x03,
    'dataFailed':          0x04,
    'controlData':         0x05,
}


class Application(Frame):
    serialReadBuf = [] #串口读取数据
    serialReadCnt=0
    serialPort=None    #串口号
    keyDowmFlag=0
    def __init__(self,master):
        super().__init__(master)
        self._serial=None
        self.comIsCon=False
        self.create_widget()
        self.pack()
    def create_widget(self):
        #加载主画布
        self.canvas = Canvas(width=1200,height=800,)
        self.canvas.place(x=0,y=0)
        global mainImage
        mainImage = PhotoImage(file="../Image/界面.png")
        self.canvas.create_image(465, 0, anchor='n', image=mainImage)
        #加载输入框
        global addImageButton
        global minusImageButton
        addImageButton = PhotoImage(file="../Image/加.png")   #85x30
        minusImageButton = PhotoImage(file="../Image/减.png")   #85x30
        #角度P输入加载
        self.angleP = StringVar()
        self.angleP.set("0.00")
        self.anglePEntry = Entry(textvariable=self.angleP, font=('Asial', 25), highlightcolor='green', highlightthickness=2,
              insertbackground='black',bg='white',width=9)
        self.anglePEntry.place(x=160, y=130)
        Button(image=minusImageButton, command=self.angle_p_minus_click).place(x=330, y=128)
        Button(image=addImageButton, command=self.angle_p_add_click).place(x=390, y=128)
        #角度I输入加载
        self.angleI = StringVar()
        self.angleI.set("0.00")
        self.angleIEntry = Entry(textvariable=self.angleI, font=('Asial', 25), highlightcolor='green', highlightthickness=2,
              insertbackground='black',bg='white',width=9)
        self.angleIEntry.place(x=160, y=256)
        Button(image=minusImageButton, command=self.angle_I_minus_click).place(x=330, y=256)
        Button(image=addImageButton, command=self.angle_I_add_click).place(x=390, y=256)
        #角度D输入加载
        self.angleD = StringVar()
        self.angleD.set("0.00")
        self.angleDEntry = Entry(textvariable=self.angleD, font=('Asial', 25), highlightcolor='green', highlightthickness=2,
              insertbackground='black',bg='white',width=9)
        self.angleDEntry.place(x=160, y=381)
        Button(image=minusImageButton, command=self.angle_D_minus_click).place(x=330, y=381)
        Button(image=addImageButton, command=self.angle_D_add_click).place(x=390, y=381)
        #速度P输入加载
        self.speedP = StringVar()
        self.speedP.set("0.00")
        self.speedPEntry = Entry(textvariable=self.speedP, font=('Asial', 25), highlightcolor='green', highlightthickness=2,
              insertbackground='black',bg='white',width=9)
        self.speedPEntry.place(x=550, y=130)
        Button(image=minusImageButton, command=self.speed_p_minus_click).place(x=720, y=128)
        Button(image=addImageButton, command=self.speed_p_add_click).place(x=780, y=128)
        #速度I输入加载
        self.speedI = StringVar()
        self.speedI.set("0.00")
        self.speedIEntry = Entry(textvariable=self.speedI, font=('Asial', 25), highlightcolor='green', highlightthickness=2,
              insertbackground='black',bg='white',width=9)
        self.speedIEntry.place(x=550, y=256)
        Button(image=minusImageButton, command=self.speed_I_minus_click).place(x=720, y=256)
        Button(image=addImageButton, command=self.speed_I_add_click).place(x=780, y=256)
        #速度D输入加载
        self.speedD = StringVar()
        self.speedD.set("0.00")
        self.speedDEntry = Entry(textvariable=self.speedD, font=('Asial', 25), highlightcolor='green', highlightthickness=2,
              insertbackground='black',bg='white',width=9)
        self.speedDEntry.place(x=550, y=381)
        Button(image=minusImageButton, command=self.speed_D_minus_click).place(x=720, y=381)
        Button(image=addImageButton, command=self.speed_D_add_click).place(x=780, y=381)
        #发送按钮加载
        global sendImageButton
        sendImageButton = PhotoImage(file="../Image/发送.png")   #85x30
        Button(image=sendImageButton, command=self.send_click).place(x=720, y=440)
        #读取按钮加载
        global readImageButton
        readImageButton = PhotoImage(file="../Image/读取.png")   #85x30
        Button(image=readImageButton, command=self.read_click).place(x=550, y=440)
        #串口打开按钮加载
        global openImageButton
        openImageButton = PhotoImage(file="../Image/打开.png")   #85x30
        self.openReadButton=Button(image=openImageButton, command=self.open_click)
        self.openReadButton.place(x=380, y=440)
        #刷新按钮加载
        global updateImageButton
        updateImageButton = PhotoImage(file="../Image/刷新.png")   #85x30
        self.updateserialButton=Button(image=updateImageButton, command=self.update_click)
        self.updateserialButton.place(x=210, y=440)
        self.update_click()
        #发送成功失败显示加载
        global buttonOkImage
        global buttonFailedImage
        global buttonStateImage
        buttonOkImage = PhotoImage(file="../Image/成功.png")   #85x30
        buttonFailedImage = PhotoImage(file="../Image/失败.png")   #85x30
        buttonStateImage = PhotoImage(file="../Image/状态.png")  # 85x30

        self.state = Canvas(width=39, height=39)
        self.state.place(x=880, y=440)
        self.state.create_image(2, 2, anchor='nw', image=buttonOkImage)
        #控制按钮加载
        global upImage,dowmImage,leftImage,rightImage,clickImage
        upImage = PhotoImage(file="../Image/上.png")   #85x30
        dowmImage = PhotoImage(file="../Image/下.png")   #85x30
        leftImage = PhotoImage(file="../Image/左.png")  # 85x30
        rightImage = PhotoImage(file="../Image/右.png")  # 85x30
        clickImage = PhotoImage(file="../Image/点击.png")

        self.upButton = Canvas(width=50, height=50)
        self.upButton.place(x=1000, y=370)
        self.upButton.create_image(2, 2, anchor='nw', image=upImage)

        self.downButton = Canvas(width=50, height=50)
        self.downButton.place(x=1000, y=470)
        self.downButton.create_image(2, 2, anchor='nw', image=dowmImage)

        self.leftButton = Canvas(width=50, height=50)
        self.leftButton.place(x=940, y=420)
        self.leftButton.create_image(2, 2, anchor='nw', image=leftImage)

        self.rightButton = Canvas(width=50, height=50)
        self.rightButton.place(x=1060, y=420)
        self.rightButton.create_image(2, 2, anchor='nw', image=rightImage)
    def move_state_update(self,dir):
        global upButton
        if dir == 'U':
            self.upButton.create_image(2, 2, anchor='nw', image=clickImage)
        elif dir == "D":
            self.downButton.create_image(2, 2, anchor='nw', image=clickImage)
        elif dir == "L":
            self.leftButton.create_image(2, 2, anchor='nw', image=clickImage)
        elif dir == "R":
            self.rightButton.create_image(2, 2, anchor='nw', image=clickImage)
        else:
            self.upButton.create_image(2, 2, anchor='nw', image=upImage)
            self.downButton.create_image(2, 2, anchor='nw', image=dowmImage)
            self.leftButton.create_image(2, 2, anchor='nw', image=leftImage)
            self.rightButton.create_image(2, 2, anchor='nw', image=rightImage)
    def angle_p_add_click(self):
        self.angleP.set(Decimal(self.angleP.get())+Decimal("0.01"))
    def angle_p_minus_click(self):
        if self.angleP.get() not in "0.00":
            self.angleP.set(Decimal(self.angleP.get())-Decimal("0.01"))
    def angle_I_add_click(self):
        self.angleI.set(Decimal(self.angleI.get())+Decimal("0.01"))
    def angle_I_minus_click(self):
        if self.angleI.get() not in "0.00":
            self.angleI.set(Decimal(self.angleI.get())-Decimal("0.01"))
    def angle_D_add_click(self):
        self.angleD.set(Decimal(self.angleD.get())+Decimal("0.01"))
    def angle_D_minus_click(self):
        if self.angleD.get() not in "0.00":
            self.angleD.set(Decimal(self.angleD.get())-Decimal("0.01"))
    def speed_p_add_click(self):
        self.speedP.set(Decimal(self.speedP.get())+Decimal("0.01"))
    def speed_p_minus_click(self):
        if self.speedP.get() not in "0.00":
            self.speedP.set(Decimal(self.speedP.get()) - Decimal("0.01"))
    def speed_I_add_click(self):
        self.speedI.set(Decimal(self.speedI.get())+Decimal("0.01"))
    def speed_I_minus_click(self):
        if self.speedI.get() not in "0.00":
            self.speedI.set(Decimal(self.speedI.get()) - Decimal("0.01"))
    def speed_D_add_click(self):
        self.speedD.set(Decimal(self.speedD.get())+Decimal("0.01"))
    def speed_D_minus_click(self):
        if self.speedD.get() not in "0.00":
            self.speedD.set(Decimal(self.speedD.get()) - Decimal("0.01"))
    def send_click(self):
        sendBuf=[]
        angleP = self.float_to_hex(float(self.angleP.get()))
        angleI = self.float_to_hex(float(self.angleI.get()))
        angleD = self.float_to_hex(float(self.angleD.get()))
        speedP = self.float_to_hex(float(self.speedP.get()))
        speedI = self.float_to_hex(float(self.speedI.get()))
        speedD = self.float_to_hex(float(self.speedD.get()))
        sendBuf.append(0xFF)
        sendBuf.append(order['sendData'])
        sendBuf.append(angleP >> 24 & 0xFF)
        sendBuf.append(angleP >> 16 & 0xFF)
        sendBuf.append(angleP >> 8 & 0xFF)
        sendBuf.append(angleP & 0xFF)
        sendBuf.append(angleI >> 24 & 0xFF)
        sendBuf.append(angleI >> 16 & 0xFF)
        sendBuf.append(angleI >> 8 & 0xFF)
        sendBuf.append(angleI & 0xFF)
        sendBuf.append(angleD >> 24 & 0xFF)
        sendBuf.append(angleD >> 16 & 0xFF)
        sendBuf.append(angleD >> 8 & 0xFF)
        sendBuf.append(angleD & 0xFF)
        sendBuf.append(speedP >> 24 & 0xFF)
        sendBuf.append(speedP >> 16 & 0xFF)
        sendBuf.append(speedP >> 8 & 0xFF)
        sendBuf.append(speedP & 0xFF)
        sendBuf.append(speedI >> 24 & 0xFF)
        sendBuf.append(speedI >> 16 & 0xFF)
        sendBuf.append(speedI >> 8 & 0xFF)
        sendBuf.append(speedI & 0xFF)
        sendBuf.append(speedD >> 24 & 0xFF)
        sendBuf.append(speedD >> 16 & 0xFF)
        sendBuf.append(speedD >> 8 & 0xFF)
        sendBuf.append(speedD & 0xFF)
        crc=0
        for i in range(1,len(sendBuf)):
            crc+=sendBuf[i]
        sendBuf.append(crc>>8&0xFF)
        sendBuf.append(crc& 0xFF)
        sendBuf.append(0xFF)
        if not self.comIsCon:
            messagebox.showerror(title='串口错误', message='请先打开串口')
            return
        self._serial.write(sendBuf)
        self.state.create_image(2, 2, anchor='nw', image=buttonStateImage)
    def read_click(self):
        if not self.comIsCon:
            messagebox.showerror(title='串口错误', message='请先打开串口')
            return
        sendBuf=[]
        sendBuf.append(0xFF)
        sendBuf.append(order['requestData'])
        for i in range(24):
            sendBuf.append(0x00)
        crc=0
        for i in range(1,len(sendBuf)):
            crc+=sendBuf[i]
        sendBuf.append(crc>>8&0xFF)
        sendBuf.append(crc& 0xFF)
        sendBuf.append(0xFF)
        self._serial.write(sendBuf)
    def open_click(self):
        if self.serialPort.get() == None:
            messagebox.showerror(title='串口错误',message='串口号为空,请先插入设备')
            return
        else:
            serialPort = self.serialPort.get()
            charPos = serialPort.find('-')
            Application.serialPort = serialPort[0:int(charPos-1)]
            # 打开串口
            try:
                self._serial = serial.Serial(port=Application.serialPort,baudrate='115200')
            except Exception as e:
                print(e)
                messagebox.showerror(title='串口错误', message='串口号错误,请检查设备')
                return
            self.comIsCon=True
            self.serialPortMenu["state"]=DISABLED
            self.openReadButton["state"]=DISABLED
            self.updateserialButton['state']=DISABLED
            #启动接收线程
            tDataReceived = threading.Thread(target=self.__serial_read)
            tDataReceived.setDaemon(True)
            tDataReceived.start()
    def update_click(self):
        #串口号选择
        self.serialPort = StringVar()
        port_list = list(serial.tools.list_ports.comports())
        print(port_list)
        self.serialPort.set(port_list[0])
        self.serialPortMenu=OptionMenu(self.master,self.serialPort,*port_list)
        self.serialPortMenu['width'] = 23
        self.serialPortMenu.place(x=0,y=470)
    def __serial_read(self):
        while self.comIsCon:
            try:
                self.serialReadData = self._serial.read()  # 串口读取数据
            except:  #串口有异常退出
                self.comIsCon=False
                self.serialPortMenu["state"] = NORMAL
                self.openReadButton["state"] = NORMAL
                self.updateserialButton['state'] = NORMAL
                break
            Application.serialReadBuf.insert(Application.serialReadCnt, self.serialReadData)  # 将读取到的数据放入缓冲区中
            if Application.serialReadBuf[0] == b'\xff':  # 判断包头是不是0xFF
                Application.serialReadCnt += 1
                if Application.serialReadCnt > 1:
                    if (Application.serialReadBuf[Application.serialReadCnt - 1] == b'\xff'):  # 接受到了包尾
                        if Application.serialReadBuf[1]== b'\x01':
                            a=self.hex_to_str(Application.serialReadBuf[2],Application.serialReadBuf[3],Application.serialReadBuf[4],Application.serialReadBuf[5])
                            data=struct.unpack('<f', bytes.fromhex(a))[0]#小端
                            self.angleP.set(str(Decimal(data)+Decimal(0.001))[0:4])

                            a=self.hex_to_str(Application.serialReadBuf[6],Application.serialReadBuf[7],Application.serialReadBuf[8],Application.serialReadBuf[9])
                            data=struct.unpack('<f', bytes.fromhex(a))[0]#小端
                            self.angleI.set(str(Decimal(data)+Decimal(0.001))[0:4])

                            a=self.hex_to_str(Application.serialReadBuf[10],Application.serialReadBuf[11],Application.serialReadBuf[12],Application.serialReadBuf[13])
                            data=struct.unpack('<f', bytes.fromhex(a))[0]#小端
                            self.angleD.set(str(Decimal(data)+Decimal(0.001))[0:4])

                            a=self.hex_to_str(Application.serialReadBuf[14],Application.serialReadBuf[15],Application.serialReadBuf[16],Application.serialReadBuf[17])
                            data=struct.unpack('<f', bytes.fromhex(a))[0]#小端
                            self.speedP.set(str(Decimal(data)+Decimal(0.001))[0:4])

                            a=self.hex_to_str(Application.serialReadBuf[18],Application.serialReadBuf[19],Application.serialReadBuf[20],Application.serialReadBuf[21])
                            data=struct.unpack('<f', bytes.fromhex(a))[0]#小端
                            self.speedI.set(str(Decimal(data)+Decimal(0.001))[0:4])

                            a=self.hex_to_str(Application.serialReadBuf[22],Application.serialReadBuf[23],Application.serialReadBuf[24],Application.serialReadBuf[25])
                            data=struct.unpack('<f', bytes.fromhex(a))[0]#小端
                            self.speedD.set(str(Decimal(data)+Decimal(0.001))[0:4])

                            Application.serialReadCnt=0
                            Application.serialReadBuf.clear()
                        elif Application.serialReadBuf[1]== b'\x03':  #成功
                            self.state.create_image(2, 2, anchor='nw', image=buttonOkImage)
                            Application.serialReadCnt=0
                            Application.serialReadBuf.clear()
                        elif Application.serialReadBuf[1]== b'\x04':  #失败
                            self.state.create_image(2, 2, anchor='nw', image=buttonFailedImage)
                            Application.serialReadCnt=0
                            Application.serialReadBuf.clear()
            else:
                self.serialReadCnt = 0
        print ("read thread over")
    def float_to_hex(self,s):
        return struct.unpack('<I', struct.pack('>f', s))[0]
    def hex_to_str(self,a,b,c,d):
        e=str(hex(a[0]))[2:]
        if len(e)==1:
            e='00'
        f=str(hex(b[0]))[2:]
        if len(f)==1:
            f='00'
        g=str(hex(c[0]))[2:]
        if len(g)==1:
            g='00'
        h=str(hex(d[0]))[2:]
        if len(h)==1:
            h='00'
        return e+f+g+h
    def key_press(self,key):
        if Application.keyDowmFlag != 1:
            Application.keyDowmFlag = 1
        else:
            return
        sendBuf = []
        sendBuf.append(0xFF)
        sendBuf.append(order['controlData'])
        if not self.comIsCon:
            messagebox.showerror(title='串口错误', message='请先打开串口')
            return
        try:
            print("正在按压:", format(key.char))
        except AttributeError:
                if key == Key.up:
                    self.move_state_update("U")
                    sendBuf.append(0x01)
                elif key == Key.down:
                    self.move_state_update("D")
                    sendBuf.append(0x02)
                elif key == Key.left:
                    self.move_state_update("L")
                    sendBuf.append(0x03)
                elif key == Key.right:
                    self.move_state_update("R")
                    sendBuf.append(0x04)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        crc=0
        for i in range(1,len(sendBuf)):
            crc+=sendBuf[i]
        sendBuf.append(crc>>8&0xFF)
        sendBuf.append(crc& 0xFF)
        sendBuf.append(0xFF)
        self._serial.write(sendBuf)
    def key_release(self,key):
        if Application.keyDowmFlag == 0:
            return
        if not self.comIsCon:
            messagebox.showerror(title='串口错误', message='请先打开串口')
            return
        Application.keyDowmFlag = 0
        self.move_state_update("A")
        sendBuf = []
        sendBuf.append(0xFF)
        sendBuf.append(order['controlData'])
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        sendBuf.append(0x00)
        crc=0
        for i in range(1,len(sendBuf)):
            crc+=sendBuf[i]
        sendBuf.append(crc>>8&0xFF)
        sendBuf.append(crc& 0xFF)
        sendBuf.append(0xFF)
        self._serial.write(sendBuf)
    def start_listen(self):
        with Listener(on_press=self.key_press,on_release=self.key_release) as listener:
            listener.join()

if __name__ == '__main__':
    root = Tk()
    root.geometry("1500x530")
    root.title("PID调试上位机")
    root.resizable(0,0)
    app = Application(root)
    keyListion = threading.Thread(target=app.start_listen)
    keyListion.setDaemon(True)
    keyListion.start()
    root.mainloop()


主界面:
在这里插入图片描述
还在更新中,有问题及时联系

原创文章 81 获赞 48 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_15181569/article/details/102554957
今日推荐