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

Arduino实时串口数据绘图无法自动更新,需手动关闭窗口问题

解决Matplotlib实时绘图无法自动更新的问题

我明白你的问题了——每次测完数据都得手动关窗口才能看到新图,这确实挺烦的。问题出在你每次循环都重新创建FuncAnimation实例并调用plt.show(),而plt.show()是阻塞式的,必须关掉窗口才会继续执行后面的代码。下面给你调整后的代码,解决这个实时更新的问题:

关键修改点

  • 将动画初始化和plt.show()移到主循环外,只执行一次,避免重复创建窗口
  • 用全局变量存储最新的均值数据,让animate函数定时获取并更新图表
  • 移除循环内的绘图相关调用,把更新逻辑交给动画函数处理
  • 给串口添加超时设置,防止读取数据时程序卡住

修改后的完整代码

import serial
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import threading

# 全局变量存储最新的均值数据,供动画函数使用
latest_mean = [0, 0]
x_vals = []
y_vals = []
plt.style.use('fivethirtyeight')
num_averages = 10
filename = "E:/Python/Data/TemperatureReadPlotreadings.csv"
port = "COM3"
baudrate = 9600

# 初始化串口,添加超时设置防止卡住
arduino = serial.Serial(port, baudrate, timeout=2)
arduino.flush()

def readdata():
    dataline = arduino.readline()
    try:
        y = dataline.decode("ascii").strip().split(",")
        # 确保读取到两组有效数据
        if len(y) != 2:
            raise ValueError("数据格式不完整")
        for i in range(len(y)):
            y[i] = float(y[i])
        return y
    except (ValueError, UnicodeDecodeError):
        arduino.flush()
        return [0, 0]

def save_data(filename, mean, stddev):
    print("Saving data")
    # 使用with语句自动管理文件,避免遗漏关闭
    with open(filename, 'a') as datafile:
        datafile.write(f"{mean[0]:6.2f},{stddev[0]:6.3f},{mean[1]:9.2f},{stddev[1]:9.3f}\n")

def animate(i):
    # 引用全局变量获取最新均值
    global latest_mean
    # 过滤初始无效的0值
    if latest_mean[0] != 0 or latest_mean[1] != 0:
        x_vals.append(latest_mean[0])
        y_vals.append(latest_mean[1])
    plt.cla()
    plt.plot(x_vals, y_vals, label="LM35")
    plt.legend(loc='upper left')
    plt.xlabel('时间计量')
    plt.ylabel('温度读数')

# 初始化动画,间隔设置为10秒(和你的采样周期匹配)
ani = FuncAnimation(plt.gcf(), animate, interval=10000)

def main_loop():
    global latest_mean
    run = True
    while run:
        try:
            data = np.zeros((2, num_averages))
            mean = np.zeros(2)
            stddev = np.zeros(2)
            # 读取10组原始数据
            for i in range(num_averages):
                data_new = readdata()
                data[0, i] = data_new[0]
                data[1, i] = data_new[1]
            # 计算均值和标准差
            for i in range(2):
                mean[i] = np.mean(data[i, :])
                stddev[i] = np.std(data[i, :])
            # 更新全局均值变量,供动画函数使用
            latest_mean = mean.copy()
            save_data(filename, mean, stddev)
        except KeyboardInterrupt:
            print('\nExiting')
            run = False
            arduino.close()

if __name__ == "__main__":
    # 把数据读取循环放在子线程,避免阻塞绘图主线程
    thread = threading.Thread(target=main_loop)
    thread.daemon = True
    thread.start()
    
    plt.tight_layout()
    plt.show()

额外说明

  1. 串口超时:添加timeout=2让串口在2秒内无数据时返回空,避免程序卡住。
  2. 文件操作优化:改用with语句自动关闭文件,比手动调用close()更安全可靠。
  3. 线程分离:将数据读取的主循环放在子线程中,避免阻塞Matplotlib的绘图主线程,确保动画能正常定时更新。
  4. 数据校验:增加了数据长度检查,避免读取到不完整或格式错误的数据导致程序报错。

现在运行代码,你会看到一个持续自动更新的绘图窗口,不用再手动关闭旧窗口啦!

内容的提问来源于stack exchange,提问作者CMJE96

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 19:32:40