You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:基于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()

关键改动说明:

  1. 硬件只初始化一次:把SPI、热电偶、GPIO的初始化都放到全局,避免每次读取都重复创建对象,减少资源冲突
  2. 用after()替代sleep():update_temp_and_log()函数最后调用self.parent.after(3000, self.update_temp_and_log),每3秒自动刷新一次,完全不会阻塞界面
  3. 变量作用域修正:read_temp()里用global temp来修改全局变量,确保温度值能同步到界面
  4. 正确的时间格式化:用time.strftime()生成可读的时间字符串,显示和记录都更清晰
  5. Treeview优化:设置了表头和列宽,还加了滚动条,数据多了也方便查看;每次刷新都插入一条新记录
  6. 异常处理:读取温度时加了try-except,避免传感器出错导致程序崩溃
  7. 资源清理:窗口关闭时调用GPIO.cleanup(),释放GPIO资源,避免下次运行出问题

备注:内容来源于stack exchange,提问作者Craciun Cornelia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 15:13:14