基于python的串口助手,可收发Hex数据包,不自动发送换行

main.py

import serial
import serial.tools.list_ports
import time
import tkinter as tk
from tkinter import ttk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import threading
from queue import Queue
import LightSwitch

# 全局变量-----------------------------------------------------------------------
receivedata = []  # 接收数据列表
drawdata = []  # 画图列表
serialName = []  # 串口端口列表
ser = serial.Serial()  # 串口实例对象
stop_event = threading.Event()
threadLock = threading.Lock()
data_queue = Queue()

# 函数和事件定义-----------------------------------------------------------------
# 接收和显示串口数据
def showdata():
    global receivedata
    while not stop_event.is_set():
        if ser.is_open:
            s = ser.read_all()
            if s:
                if var_Get.get():#Hex接收
                    try:
                        decoded_data = s.hex()
                        print(type(decoded_data),decoded_data)
                        if decoded_data:
                            with threadLock:
                                receivedata.append(decoded_data)
                                data_queue.put(decoded_data)
                            t0.insert('end', decoded_data)
                            t0.see('end')  # 自动滚动到最新接收到的数据
                    except UnicodeDecodeError as e:
                        print(f"Error decoding data: {e}")
                elif not var_Get.get():
                    try:
                        decoded_data = s.decode('utf-8')#将字节对象转换为字符串对象
                        print(type(decoded_data),decoded_data)
                        if decoded_data:
                            with threadLock:
                                receivedata.append(decoded_data)#将字符串对象添加到队列
                                data_queue.put(decoded_data)#通过队列在线程中传输数据
                            t0.insert('end', decoded_data)
                            t0.see('end')  # 自动滚动到最新接收到的数据
                    except UnicodeDecodeError as e:
                        print(f"Error decoding data: {e}")

# 设置串口参数
def setPort(*args):
    ser.port = comboxlist0.get()

def setbaudrate(*args):
    ser.baudrate = int(comboxlist1.get())

def setShujv(*args):
    ser.bytesize = int(comboxlist2.get())

check = {"N": serial.PARITY_NONE, "E": serial.PARITY_EVEN, "O": serial.PARITY_ODD}
def setcheck(*args):
    ser.parity = check[comboxlist3.get()]

stop = {"1": serial.STOPBITS_ONE, "1.5": serial.STOPBITS_ONE_POINT_FIVE, "2": serial.STOPBITS_TWO}
def setstop(*args):
    ser.stopbits = stop[comboxlist4.get()]

# 打开和关闭串口
def opencom():
    global light_flag
    if ser.is_open:
        ser.close()
        light.turn_off()
        light_flag = 0
    else:
        ser.open()
        light.turn_on()
        light_flag = 1

# 发送数据
def send():
    if not ser.is_open:
        print("串口未打开")
        return

    elif var.get():  # Hex发送 单选框的值
        demo = e0.get().strip() #发送输入文本框的值获取到并去掉 原始字符串的开头和结尾删除给定的字符默认为空格
        demo = demo.replace(" ", "")
        demo = demo.replace("0x", "")
        if len(demo) % 2 != 0 and len(demo)>1:
            demo = demo[:-1]+'0'+demo[-1]
        try:
            #demo[i:i+2]切片从i到i+2的2字符,将提取的2字符转换为16禁止的整数,int('48', 16) 会返回整数值 72,将所有转换后的整数转换为字节对象,hex_bytes为字节对象队列
            hex_bytes = bytes(int(demo[i:i + 2], 16) for i in range(0, len(demo), 2))#i从0-len,步长2
            ser.write(hex_bytes)#发送字节对象
            print(f"Hex Bytes: {hex_bytes}")
        except ValueError as e:
            print(f"Error: {e}")
    else:  # 字符串发送
        demo = e0.get().strip()#获取文本框值,并去掉空格和换行,并将其编码为字节序列
        demo = demo.replace(" ", "")
        demo = demo.encode()
        ser.write(demo)

# 清除接收数据
def clearreceive():
    with threadLock:
        receivedata.clear()
        t0.delete(1.0, 'end')

# 单选框选择 - Hex发送
def selectionvar():
    global on_hit
    on_hit = var.get()

#单选框选择 - Hex接收
def selectionvarGet():
    global on_hit
    on_hit = var.get()

# 停止所有线程
def Stop_EVEN():
    stop_event.set()
    time.sleep(1)
    th0.join()
    #th1.join()
    ser.close()
    window.quit()

# 初始化窗口和控件
window = tk.Tk()
window.title('chenyuean的串口助手')
window.geometry('900x600+200+100')

# 获取可用串口列表
port_list = list(serial.tools.list_ports.comports())
for port in port_list:
    serialName.append(port[0])

# 创建文本控件和下拉列表控件
label0 = tk.Label(window, text='串口', font=10)
label0.place(y=50, x=50)
label1 = tk.Label(window, text='波特率', font=10)
label1.place(y=100, x=50)
label2 = tk.Label(window, text='数据位', font=10)
label2.place(y=150, x=50)
label3 = tk.Label(window, text='校验位', font=10)
label3.place(y=200, x=50)
label4 = tk.Label(window, text='停止位', font=10)
label4.place(y=250, x=50)

#端口号下拉框
comvalue0 = tk.StringVar()
comboxlist0 = ttk.Combobox(window, textvariable=comvalue0)
comboxlist0["values"] = tuple(serialName)
comboxlist0.bind("<<ComboboxSelected>>", setPort)
comboxlist0.place(y=50, x=150)

#波特率下拉框
comvalue1 = tk.StringVar()
comboxlist1 = ttk.Combobox(window, textvariable=comvalue1)
comboxlist1["values"] = ("1200", "2400", "4800", "9600", "14400", "19200", "115200", "256000")
comboxlist1.current(6)
comboxlist1.bind("<<ComboboxSelected>>", setbaudrate)
comboxlist1.place(y=100, x=150)

#数据位下拉框
comvalue2 = tk.StringVar()
comboxlist2 = ttk.Combobox(window, textvariable=comvalue2)
comboxlist2["values"] = ("8", "7", "6", "5")
comboxlist2.current(0)
comboxlist2.bind("<<ComboboxSelected>>", setShujv)
comboxlist2.place(y=150, x=150)

#校验位下拉框
comvalue3 = tk.StringVar()
comboxlist3 = ttk.Combobox(window, textvariable=comvalue3)
comboxlist3["values"] = ("N", "E", "O")
comboxlist3.current(0)
comboxlist3.bind("<<ComboboxSelected>>", setcheck)
comboxlist3.place(y=200, x=150)

#停止位下拉框
comvalue4 = tk.StringVar()
comboxlist4 = ttk.Combobox(window, textvariable=comvalue4)
comboxlist4["values"] = ("1", "1.5", "2")
comboxlist4.current(0)
comboxlist4.bind("<<ComboboxSelected>>", setstop)
comboxlist4.place(y=250, x=150)

b0 = tk.Button(window, text='打开串口', width=35, height=1, command=opencom)
b0.place(y=300, x=50)

stop_EV = tk.Button(window, text='关闭线程和程序', width=20, height=1, font=2, command=Stop_EVEN)
stop_EV.place(y=0, x=0)

light = LightSwitch.BooleanLight(window, size=35, x=10, y=295)#串口连接状态显示灯
btn_turn_on = tk.Button(window, text="Turn On", command=light.turn_on)

b1 = tk.Button(window, text='清除接收', width=35, height=1, command=clearreceive)
b1.place(y=350, x=50)

#发送输入文本框
e0 = tk.Entry(window, show=None, width=35)
e0.place(y=400, x=50)

#输入文本框Hex选择框
var = tk.IntVar(value=1)
c1 = tk.Checkbutton(window, text='Hex发送', variable=var, onvalue=1, offvalue=0, command=selectionvar)
c1.place(y=450, x=50)

#发送按钮
b1 = tk.Button(window, text='Send', width=20, height=1, command=send)
b1.place(y=450, x=150)

#接收文本框Hex选择框
var_Get = tk.IntVar(value=1)
c1 = tk.Checkbutton(window, text='Hex接收', variable=var_Get, onvalue=1, offvalue=0, command=selectionvarGet)
c1.place(y=0, x=350)

#接收显示
t0 = tk.Text(window, width=65, height=2)
t0.place(y=50, x=350)

label5 = tk.Label(window, text='Canvas', font=10)
label5.place(y=100, x=350)
# 图像参数
canvas = tk.Canvas(window,width=320, height=240,bg='#{:02x}{:02x}{:02x}'.format(*(255,255,255)),bd=1,highlightthickness=1,relief="groove")
canvas.pack()
canvas.place(x=420, y=125)


if __name__ == '__main__':
    stop_event = threading.Event()#等待线程停止事件
    th0 = threading.Thread(target=showdata)
    th0.start()
    # th1 = threading.Thread(target=startdraw)
    # th1.start()

    window.mainloop()

LightSwitch.py

import tkinter as tk
class BooleanLight(tk.Canvas):
    def __init__(self, master=None, size=50, x=0, y=0):
        super().__init__(master, width=size, height=size)
        self.pack()
        self.place(x=x, y=y)
        self.size = size
        self.is_light_on = False  # 初始状态为关闭

        # 创建初始的圆形表示灯的状态
        self.light = self.create_oval(5, 5, size - 5, size - 5, fill="gray")

    def turn_on(self):
        """打开灯"""
        self.itemconfig(self.light, fill="green")
        self.is_light_on = True

    def turn_off(self):
        """关闭灯"""
        self.itemconfig(self.light, fill="gray")
        self.is_light_on = False

    def toggle(self):
        """切换灯的状态"""
        if self.is_light_on:
            self.turn_off()
        else:
            self.turn_on()

 可完成功能,接收文本数据和Hex数据,发送文本数据和Hex数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值