Python基于TKinter的Arduino串口监视器绘图不显示问题求助
代码修复说明
- 删除无效导入
import self,补充缺失的线程类导入语句from threading import Thread - 替换已弃用的
time.clock()接口为time.perf_counter(),兼容Python3.8及以上版本 - 修正所有HTML转义的引号
"为正常双引号 - 将动画实例
anim绑定到Tkinter主窗口对象上,避免被垃圾回收导致绘图无法渲染更新 - 补充说明:如果你的Arduino输出数值范围不在默认的-1~1之间,请调整main函数中
ymin和ymax参数匹配你的实际数据范围;同时请确保Arduino端发送的二进制数据格式与Python端配置一致,比如numPlots=3、dataNumBytes=4对应Arduino连续发送3个float类型的二进制数据。
修复后完整代码
import serial import time import collections import matplotlib.pyplot as plt import matplotlib.animation as animation import struct import copy from threading import Thread from matplotlib.backends.backend_tkagg import FigureCanvasTk, NavigationToolbar2Tk import tkinter as Tk from tkinter.ttk import Frame import pandas as pd class serialPlot: def __init__(self, serialPort='COM12', serialBaud=9600, plotLength=100, dataNumBytes=2, numPlots=1): self.port = serialPort self.baud = serialBaud self.plotMaxLength = plotLength self.dataNumBytes = dataNumBytes self.numPlots = numPlots self.rawData = bytearray(numPlots * dataNumBytes) self.dataType = None if dataNumBytes == 2: self.dataType = 'h' # 2字节整数 elif dataNumBytes == 4: self.dataType = 'f' # 4字节浮点数 self.data = [] for me in range(numPlots): self.data.append(collections.deque([0] * plotLength, maxlen=plotLength)) self.isRun = True self.isReceiving = False self.thread = None self.plotTimer = 0 self.previousTimer = 0 print('尝试连接: ' + str(serialPort) + ' 波特率' + str(serialBaud)) try: self.serialConnection = serial.Serial(serialPort, serialBaud, timeout=4) print('已连接到' + str(serialPort) + ' 波特率' + str(serialBaud)) except: print("连接失败" + str(serialPort) + ' 波特率' + str(serialBaud)) def readSerialStart(self): if self.thread is None: self.thread = Thread(target=self.backgroundThread) self.thread.start() # 阻塞直到收到第一组数据 while not self.isReceiving: time.sleep(0.1) def getSerialData(self, frame, lines, lineValueText, lineLabel, timeText): currentTimer = time.perf_counter() self.plotTimer = int((currentTimer - self.previousTimer) * 1000) self.previousTimer = currentTimer timeText.set_text('绘图间隔 = ' + str(self.plotTimer) + 'ms') privateData = copy.deepcopy(self.rawData[:]) for me in range(self.numPlots): data = privateData[(me * self.dataNumBytes):(self.dataNumBytes + me * self.dataNumBytes)] value, = struct.unpack(self.dataType, data) self.data[me].append(value) lines[me].set_data(range(self.plotMaxLength), self.data[me]) lineValueText[me].set_text('[' + lineLabel[me] + '] = ' + str(value)) def backgroundThread(self): time.sleep(1.0) self.serialConnection.reset_input_buffer() while self.isRun: self.serialConnection.readinto(self.rawData) self.isReceiving = True def sendSerialData(self, data): self.serialConnection.write(data.encode('utf-8')) def close(self): self.isRun = False self.thread.join() self.serialConnection.close() print('已断开连接...') class Window(Frame): def __init__(self, figure, master, SerialReference): Frame.__init__(self, master) self.entry = None self.setPoint = None self.master = master self.serialReference = SerialReference self.initWindow(figure) def initWindow(self, figure): self.master.title("实时绘图") canvas = FigureCanvasTk(figure, master=self.master) toolbar = NavigationToolbar2Tk(canvas, self.master) canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) lbl1 = Tk.Label(self.master, text="缩放系数") lbl1.pack(padx=5, pady=5) self.entry = Tk.Entry(self.master) self.entry.insert(0, '1.0') self.entry.pack(padx=5) SendButton = Tk.Button(self.master, text='发送', command=self.sendFactorToMCU) SendButton.pack(padx=5) def sendFactorToMCU(self): self.serialReference.sendSerialData(self.entry.get() + '%') def main(): portName = 'COM12' # 请修改为你的实际串口号 baudRate = 9600 # 请修改为你的实际波特率 maxPlotLength = 100 dataNumBytes = 4 numPlots = 3 s = serialPlot(portName, baudRate, maxPlotLength, dataNumBytes, numPlots) s.readSerialStart() pltInterval = 50 xmin = 0 xmax = maxPlotLength ymin = -1 # 请根据实际数据范围调整 ymax = 1 # 请根据实际数据范围调整 fig = plt.figure(figsize=(10, 8)) ax = plt.axes(xlim=(xmin, xmax), ylim=(float(ymin - (ymax - ymin) / 10), float(ymax + (ymax - ymin) / 10))) ax.set_title('Arduino加速度计数据') ax.set_xlabel("时间") ax.set_ylabel("加速度计输出") root = Tk.Tk() app = Window(fig, root, s) lineLabel = ['X', 'Y', 'Z'] style = ['r-', 'c-', 'b-'] timeText = ax.text(0.70, 0.95, '', transform=ax.transAxes) lines = [] lineValueText = [] for me in range(numPlots): lines.append(ax.plot([], [], style[me], label=lineLabel[me])[0]) lineValueText.append(ax.text(0.70, 0.90 - me * 0.05, '', transform=ax.transAxes)) anim = animation.FuncAnimation(fig, s.getSerialData, fargs=(lines, lineValueText, lineLabel, timeText), interval=pltInterval) root.anim = anim # 绑定动画实例到主窗口,避免被回收 root.mainloop() s.close() if __name__ == '__main__': main()
内容的提问来源于stack exchange,提问作者Luqman sadozai
相关产品推荐
相关产品推荐

