求助:基于Tkinter实现树莓派热电偶温度与时间实时显示及记录至树视图的问题
求助:基于Tkinter实现树莓派热电偶温度与时间实时显示及记录至树视图的问题
嘿,我仔细看了你的代码和需求,你现在遇到的核心问题是无法实时更新温度显示,只能重启窗口才会刷新,而且Treeview的记录逻辑也没跑起来对吧?其实问题主要出在没用到Tkinter的定时刷新机制,加上一些变量作用域、重复初始化硬件的小问题,我帮你调整一下,应该就能实现实时显示温度+记录时间到树视图的功能了!
先说说你代码里的几个关键问题:
- 变量作用域问题:你的
READ()函数里的temp是局部变量,修改后不会同步到全局的temp,所以界面读取的还是初始值 - 阻塞主循环:用
time.sleep()会卡住Tkinter的主事件循环,导致界面假死,Tkinter里必须用after()来做定时任务 - 重复初始化硬件:每次读取温度都重新初始化SPI、CS引脚和热电偶对象,这不仅没必要,还可能导致硬件资源冲突
- 时间获取错误:直接把
time模块赋值给标签,这根本不是当前时间,得用格式化的时间字符串 - Treeview插入逻辑不对:你的
insert_data()函数里的循环会被time.sleep()卡住,而且没有真正触发实时插入
下面是修改后的完整代码,我加了详细注释,你可以直接用:
import tkinter from tkinter import ttk import time import board import psutil import digitalio import adafruit_max31856 import RPi.GPIO as GPIO Heat_PIN = 24 temp = 0.0 # 初始化硬件(只做一次!) # 先清理可能存在的libgpiod进程 for proc in psutil.process_iter(): if proc.name() in ['libgpiod_pulsein', 'libgpiod_pulsei']: proc.kill() # 初始化GPIO和加热引脚 GPIO.setmode(GPIO.BCM) GPIO.setup(Heat_PIN, GPIO.OUT) GPIO.output(Heat_PIN, GPIO.LOW) # 初始化热电偶传感器(全局只初始化一次) spi = board.SPI() cs = digitalio.DigitalInOut(board.D5) cs.direction = digitalio.Direction.OUTPUT thermocouple = adafruit_max31856.MAX31856(spi, cs) class Begueradj(tkinter.Frame): def __init__(self, parent): tkinter.Frame.__init__(self, parent) self.parent = parent self.initialize_user_interface() # 启动定时刷新任务(每3秒刷新一次,可自行调整时间) self.update_temp_and_log() def initialize_user_interface(self): self.parent.title("温度监控系统") self.parent.grid_rowconfigure(0, weight=1) self.parent.grid_columnconfigure(0, weight=1) self.parent.config(background="lavender") # 温度显示标签组 self.temp_label = tkinter.Label(self.parent, text="当前温度:") self.temp_label.grid(row=0, column=0, sticky=tkinter.W, padx=5, pady=5) self.temp_value_label = tkinter.Label(self.parent, text="-- °C", font=('Arial', 12)) self.temp_value_label.grid(row=0, column=1, sticky=tkinter.W, padx=5, pady=5) # 时间显示标签组 self.date_label = tkinter.Label(self.parent, text="记录时间:") self.date_label.grid(row=1, column=0, sticky=tkinter.W, padx=5, pady=5) self.date_value_label = tkinter.Label(self.parent, text="--", font=('Arial', 10)) self.date_value_label.grid(row=1, column=1, sticky=tkinter.W, padx=5, pady=5) # 初始化Treeview表格(优化表头和列布局) self.tree = ttk.Treeview(self.parent, columns=('温度', '记录时间'), show='headings') self.tree.heading('温度', text='温度(°C)') self.tree.heading('记录时间', text='记录时间') self.tree.column('温度', width=100, anchor='center') self.tree.column('记录时间', width=150, anchor='center') self.tree.grid(row=4, columnspan=2, sticky='nsew', padx=5, pady=10) # 给表格加滚动条(数据多了方便浏览) scrollbar = ttk.Scrollbar(self.parent, orient="vertical", command=self.tree.yview) scrollbar.grid(row=4, column=2, sticky='ns') self.tree.configure(yscrollcommand=scrollbar.set) def read_temp(self): """读取当前温度,同时控制加热元件""" global temp try: temp = thermocouple.temperature # 加热逻辑:温度低于设定值时开启,高于时关闭(这里阈值设为30°C,可自行修改) if temp < 30: GPIO.output(Heat_PIN, GPIO.HIGH) else: GPIO.output(Heat_PIN, GPIO.LOW) return temp except Exception as e: print(f"读取温度出错: {e}") return None def update_temp_and_log(self): """更新温度显示并记录到Treeview""" current_temp = self.read_temp() current_time = time.strftime("%Y-%m-%d %H:%M:%S") # 格式化当前时间为可读字符串 if current_temp is not None: # 更新实时温度标签 self.temp_value_label.config(text=f"{current_temp:.1f} °C") # 更新当前时间标签 self.date_value_label.config(text=current_time) # 插入新记录到Treeview末尾 self.tree.insert('', 'end', values=(f"{current_temp:.1f}", current_time)) # 3秒后再次执行这个函数,实现循环刷新(单位毫秒,3000=3秒) self.parent.after(3000, self.update_temp_and_log) def on_closing(): """窗口关闭时清理GPIO资源,避免下次运行出错""" GPIO.cleanup() root.destroy() def main(): global root root = tkinter.Tk() # 绑定窗口关闭事件,确保资源被清理 root.protocol("WM_DELETE_WINDOW", on_closing) d = Begueradj(root) root.mainloop() if __name__ == "__main__": main()
关键改动说明:
- 硬件只初始化一次:把SPI、热电偶、GPIO的初始化都放到全局,避免每次读取都重复创建对象,减少资源冲突
- 用
after()替代sleep():update_temp_and_log()函数最后调用self.parent.after(3000, self.update_temp_and_log),每3秒自动刷新一次,完全不会阻塞界面 - 变量作用域修正:
read_temp()里用global temp来修改全局变量,确保温度值能同步到界面 - 正确的时间格式化:用
time.strftime()生成可读的时间字符串,显示和记录都更清晰 - Treeview优化:设置了表头和列宽,还加了滚动条,数据多了也方便查看;每次刷新都插入一条新记录
- 异常处理:读取温度时加了
try-except,避免传感器出错导致程序崩溃 - 资源清理:窗口关闭时调用
GPIO.cleanup(),释放GPIO资源,避免下次运行出问题
备注:内容来源于stack exchange,提问作者Craciun Cornelia
相关产品推荐
相关产品推荐

