我绝对是编码初学者,目前正在尝试使用 Arduino Uno 设计涡轮机性能显示器,该显示器将使用引脚 A1 的输入传达电压读数。
然后将该读数发送到 Python,然后发送到 Python GUI 是根据 Arduino 的原始串行输入显示电流等读数。根据我所学到的知识,我从 Arduino 端进行了简单的编码,然后使用 Figma 设计了一个 GUI 并对其进行了转换。我的问题是,数据仅显示为电压和电流的样本,但我无法随着电流或电压值的变化自动不断刷新数据。我缺少什么?当我尝试执行循环时,它会错误地显示整个代码。
这是我一直在循环中尝试的代码:
# Tkinter-Designer
from pathlib import Path
# from tkinter import *
# Explicit imports to satisfy Flake8
import serial
ser = serial.Serial ('COM4', baudrate = 9600, timeout = 1)
while:1
arduinoData = ser.readline().decode('ascii')
int(float(arduinoData))
voltageval = int(arduinoData)/204.6
currentval = int(arduinoData)/1.96
from tkinter import Tk, Canvas, Entry, Text, Button, PhotoImage
OUTPUT_PATH = Path(__file__).parent
ASSETS_PATH = OUTPUT_PATH / Path(r"C:\Users\haeyl\Downloads\tkinter\build\assets\frame0")
def relative_to_assets(path: str) -> Path:
return ASSETS_PATH / Path(path)
window = Tk()
window.geometry("1280x720")
window.configure(bg = "#600000")
canvas = Canvas(
window,
bg = "#600000",
height = 720,
width = 1280,
bd = 0,
highlightthickness = 0,
relief = "ridge"
)
canvas.place(x = 0, y = 0)
canvas.create_rectangle(
0.0,
0.0,
1280.0,
90.0,
fill="#474646",
outline="")
canvas.create_text(
423.0,
37.0,
anchor="nw",
text="TURBINE PERFORMANCE DISPLAY",
fill="#FFFFFF",
font=("Inter", 24 * -1)
)
image_image_1 = PhotoImage(
file=relative_to_assets("image_1.png"))
image_1 = canvas.create_image(
262.0,
182.0,
image=image_image_1
)
image_image_2 = PhotoImage(
file=relative_to_assets("image_2.png"))
image_2 = canvas.create_image(
909.0,
182.0,
image=image_image_2
)
image_image_3 = PhotoImage(
file=relative_to_assets("image_3.png"))
image_3 = canvas.create_image(
909.0,
344.0,
image=image_image_3
)
image_image_4 = PhotoImage(
file=relative_to_assets("image_4.png"))
image_4 = canvas.create_image(
262.0,
348.0,
image=image_image_4
)
image_image_5 = PhotoImage(
file=relative_to_assets("image_5.png"))
image_5 = canvas.create_image(
262.0,
519.0,
image=image_image_5
)
canvas.create_text(
105.0,
168.0,
anchor="nw",
text="VOLTAGE",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
752.0,
168.0,
anchor="nw",
text="RPM",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
740.0,
330.0,
anchor="nw",
text="POWER",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
105.0,
335.0,
anchor="nw",
text="CURRENT",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
105.0,
506.0,
anchor="nw",
text="TORQUE",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
323.0,
168.0,
anchor="nw",
text=(0 + voltageval),
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
970.0,
168.0,
anchor="nw",
text="rpmval",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
970.0,
330.0,
anchor="nw",
text="0 W ",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
323.0,
335.0,
anchor="nw",
text=(0 + currentval),
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
canvas.create_text(
323.0,
506.0,
anchor="nw",
text="0 N/M",
fill="#FFFFFF",
font=("Inter", 32 * -1)
)
image_image_6 = PhotoImage(
file=relative_to_assets("image_6.png"))
image_6 = canvas.create_image(
1132.0,
563.0,
image=image_image_6
)
button_image_1 = PhotoImage(
file=relative_to_assets("button_1.png"))
button_1 = Button(
image=button_image_1,
borderwidth=0,
highlightthickness=0,
command=lambda: print("button_1 clicked"),
relief="flat"
)
button_1.place(
x=709.0,
y=476.0,
width=264.0,
height=108.0
)
window.resizable(False, False)
window.mainloop()
你的代码的主要问题是你试图在 Tkinter 的主循环之外更新 GUI 元素。Tkinter 有一个内部循环,该循环处理诸如更新文本、处理事件等事件。你不能只是设置一次你的 GUI 然后通过更新一个变量来更新它。你需要告诉 Tkinter 使用
mainloop()
函数来更新它。
以下是如何修复代码的方法:
-
从无限
while
循环中移出 GUI 更新代码: 你不应该在while
循环中运行你的 Tkinter 应用程序。while
循环会阻止 Tkinter 的主循环,从而导致 GUI 无响应。 -
创建一个用于从 Arduino 读取数据并更新 GUI 的函数: 该函数将从串行端口读取数据,计算电压和电流,然后使用新的电压和电流值更新相应的 Tkinter 文本元素。
-
使用
after()
方法调用更新函数:after()
方法允许你安排一个函数在 Tkinter 主循环中的一段时间后运行。这将创建一个定期更新 GUI 的循环。
以下是代码:
import serial
import tkinter as tk
# Arduino 串口配置
ser = serial.Serial('COM4', baudrate=9600, timeout=1)
def update_gui():
"""从 Arduino 读取数据并更新 GUI。"""
try:
arduino_data = ser.readline().decode('ascii').strip()
if arduino_data: # 仅在接收到数据时更新
# 将数据转换为整数
arduino_data = int(float(arduino_data))
# 计算电压和电流
voltage_val = arduino_data / 204.6
current_val = arduino_data / 1.96
# 更新画布上的文本标签
canvas.itemconfig(voltage_text, text=f"{voltage_val:.2f}")
canvas.itemconfig(current_text, text=f"{current_val:.2f}")
except ValueError:
# 处理无效数据(例如,如果读取为空)
print("从 Arduino 收到无效数据。")
# 每 100 毫秒安排 update_gui() 再次运行
window.after(100, update_gui)
# 创建主窗口
window = tk.Tk()
window.geometry("1280x720")
window.configure(bg="#600000")
# 创建画布
canvas = tk.Canvas(window, bg="#600000", height=720, width=1280, bd=0, highlightthickness=0, relief="ridge")
canvas.place(x=0, y=0)
# ... (其余的画布元素,如矩形、图像和静态文本) ...
# 创建电压和电流文本标签
voltage_text = canvas.create_text(
323.0, 168.0, anchor="nw", text="0.00", fill="#FFFFFF", font=("Inter", 32 * -1)
)
current_text = canvas.create_text(
323.0, 335.0, anchor="nw", text="0.00", fill="#FFFFFF", font=("Inter", 32 * -1)
)
# ... (按钮和其他 GUI 元素) ...
# 启动更新函数
update_gui()
# 运行主循环
window.resizable(False, False)
window.mainloop()
此代码创建了一个名为
update_gui
的函数,该函数负责从 Arduino 读取数据并更新 GUI。然后,使用
window.after(100, update_gui)
方法安排此函数每 100 毫秒调用一次。这将创建定期更新 GUI 的循环。
此外,你应该确保 Arduino 代码不断向串口发送数据。
标签:python,tkinter,arduino,pyserial From: 78814062