实例介绍
【实例简介】使用Pyserial库构建的简易版串口通讯
【实例截图】
【核心代码】
【实例截图】

【核心代码】
# serial_gui.py
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import serial
import serial.tools.list_ports
class SerialApp:
def __init__(self, root):
self.root = root
self.root.title("串口通信助手")
self.root.geometry("650x500")
self.serial_port = None # 串口对象
self.create_widgets()
self.refresh_ports() # 自动扫描可用端口
def create_widgets(self):
# === 参数设置区 ===
param_frame = ttk.LabelFrame(self.root, text="串口参数", padding=10)
param_frame.pack(padx=10, pady=10, fill=tk.X)
# 端口
ttk.Label(param_frame, text="端口:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)
self.port_combo = ttk.Combobox(param_frame, state="readonly", width=15)
self.port_combo.grid(row=0, column=1, padx=5, pady=5)
self.refresh_btn = ttk.Button(param_frame, text="刷新", command=self.refresh_ports)
self.refresh_btn.grid(row=0, column=2, padx=5, pady=5)
# 波特率
ttk.Label(param_frame, text="波特率:").grid(row=0, column=3, sticky=tk.W, padx=5, pady=5)
self.baud_combo = ttk.Combobox(param_frame, values=[
"300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"
], state="readonly", width=12)
self.baud_combo.set("115200")
self.baud_combo.grid(row=0, column=4, padx=5, pady=5)
# 数据位
ttk.Label(param_frame, text="数据位:").grid(row=1, column=0, sticky=tk.W, padx=5, pady=5)
self.bytesize_combo = ttk.Combobox(param_frame, values=["5", "6", "7", "8"], state="readonly", width=15)
self.bytesize_combo.set("8")
self.bytesize_combo.grid(row=1, column=1, padx=5, pady=5)
# 停止位
ttk.Label(param_frame, text="停止位:").grid(row=1, column=3, sticky=tk.W, padx=5, pady=5)
self.stopbits_combo = ttk.Combobox(param_frame, values=["1", "1.5", "2"], state="readonly", width=12)
self.stopbits_combo.set("1")
self.stopbits_combo.grid(row=1, column=4, padx=5, pady=5)
# 校验位
ttk.Label(param_frame, text="校验位:").grid(row=2, column=0, sticky=tk.W, padx=5, pady=5)
self.parity_combo = ttk.Combobox(param_frame, values=["无", "偶", "奇"], state="readonly", width=15)
self.parity_combo.set("无")
self.parity_combo.grid(row=2, column=1, padx=5, pady=5)
# 打开/关闭按钮
self.open_btn = ttk.Button(param_frame, text="打开串口", command=self.open_serial)
self.open_btn.grid(row=2, column=3, columnspan=2, pady=5)
# === 接收区 ===
recv_frame = ttk.LabelFrame(self.root, text="接收数据", padding=10)
recv_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
self.recv_text = scrolledtext.ScrolledText(recv_frame, height=12, state='disabled')
self.recv_text.pack(fill=tk.BOTH, expand=True)
# === 发送区 ===
send_frame = ttk.LabelFrame(self.root, text="发送数据", padding=10)
send_frame.pack(padx=10, pady=10, fill=tk.X)
# 输入框
self.send_text = tk.Entry(send_frame, width=60)
self.send_text.pack(side=tk.LEFT, padx=5, pady=5)
self.send_text.bind("<Return>", self.send_data) # 回车发送
# 是否添加回车换行
self.add_newline_var = tk.BooleanVar(value=False) # 默认BU开启
self.newline_check = ttk.Checkbutton(
send_frame,
text="回车换行",
variable=self.add_newline_var
)
self.newline_check.pack(side=tk.RIGHT, padx=5, pady=5)
# 发送按钮
self.send_btn = ttk.Button(send_frame, text="发送", command=self.send_data)
self.send_btn.pack(side=tk.RIGHT, padx=5, pady=5)
def refresh_ports(self):
"""刷新可用串口"""
ports = [port.device for port in serial.tools.list_ports.comports()]
self.port_combo['values'] = ports
if ports:
self.port_combo.current(0)
else:
self.port_combo.set("")
def open_serial(self):
if self.serial_port and self.serial_port.is_open:
self.serial_port.close()
self.open_btn.config(text="打开串口")
messagebox.showinfo("串口状态", "串口已关闭")
return
try:
port = self.port_combo.get()
baud = int(self.baud_combo.get())
bytesize = int(self.bytesize_combo.get())
stopbits = float(self.stopbits_combo.get())
parity_map = {"无": serial.PARITY_NONE, "偶": serial.PARITY_EVEN, "奇": serial.PARITY_ODD}
parity = parity_map[self.parity_combo.get()]
self.serial_port = serial.Serial(
port=port,
baudrate=baud,
bytesize=bytesize,
stopbits=stopbits,
parity=parity,
timeout=1
)
self.open_btn.config(text="关闭串口")
messagebox.showinfo("串口状态", f"已打开 {port}")
# 启动接收线程
self.root.after(100, self.read_serial)
except Exception as e:
messagebox.showerror("错误", f"无法打开串口: {str(e)}")
def read_serial(self):
"""非阻塞读取串口数据"""
if self.serial_port and self.serial_port.is_open:
try:
if self.serial_port.in_waiting > 0:
data = self.serial_port.read(self.serial_port.in_waiting).decode('utf-8', errors='replace')
self.display_recv(data)
except Exception as e:
self.display_recv(f"[错误: {str(e)}]\n")
# 继续轮询
if self.serial_port and self.serial_port.is_open:
self.root.after(50, self.read_serial)
def display_recv(self, text):
"""在接收区显示数据"""
self.recv_text.config(state='normal')
self.recv_text.insert(tk.END, text)
self.recv_text.see(tk.END)
self.recv_text.config(state='disabled')
def send_data(self, event=None):
"""发送数据"""
if not self.serial_port or not self.serial_port.is_open:
messagebox.showwarning("警告", "请先打开串口")
return
data = self.send_text.get().strip()
if not data:
return
# 根据选项决定是否添加回车换行
if self.add_newline_var.get():
# 添加 \r\n(CR LF)
send_bytes = (data '\r\n').encode('utf-8')
else:
send_bytes = data.encode('utf-8')
try:
self.serial_port.write(send_bytes)
# 显示发送内容(用 \r\n 表示回车换行)
data = data '\r\n' if self.add_newline_var.get() else data
self.display_recv(f"[发送]: {data}\n")
self.send_text.delete(0, tk.END)
except Exception as e:
messagebox.showerror("发送失败", str(e))
def on_closing(self):
"""关闭窗口时清理资源"""
if self.serial_port and self.serial_port.is_open:
self.serial_port.close()
self.root.destroy()
# === 主程序入口 ===
if __name__ == "__main__":
root = tk.Tk()
app = SerialApp(root)
# 绑定窗口关闭事件
root.protocol("WM_DELETE_WINDOW", app.on_closing)
root.mainloop()
好例子网口号:伸出你的我的手 — 分享!
相关软件
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论