Python 3.x g='gray' 单个按钮位置(relx=0.85,RELn=0.5,锚定=中心) #---第2帧--- #---第3帧--- frame3=tk.Frame(根,bd=5)#删除了这个bg='#80c1ff'(我用它来查看帧的边框) frame3.place(relx=0,rely=0.2,relheight=0.07,relwidth=1,anchor='nw') #“停止测量”按钮 #这将在最初禁用,并且仅在正在进行测量时启用 按钮停止=tk.按钮(第3帧,text=“停止测量”,bg='#80c1ff',fg='红色',state='disabled',command=stop\u测量) 按钮位置(relx=0.5,RELn=0.5,锚定=中心) #---第3帧--- #---第4帧--- frame4=tk.Frame(根,bd=5) frame4.place(relx=0,rely=0.3,relheight=0.09,relwidth=1,anchor='nw') label2=tk.Label(frame4,text=“选择要打印数据的传感器:”) 标签2.位置(relx=0.1,rely=0.3,relwidth=0.3,relheight=0.5) clickedForPlotting=tk.StringVar() clickedForPlotting.set(选项[0])#默认值 dropPlot=tk.OptionMenu(第4帧,单击打印,*选项) dropPlot.place(relx=0.5,rely=0.5,anchor='center') #改天 #dropDownButton=tk.Button(frame4,text=“Plot sensor data”,bg='#80c1ff',fg='red',command=single_sensor)#bg='gray' #下拉按钮。放置(relx=0.85,rely=0.5,anchor='center') #---第4帧--- #第5帧将保存为txt文件 #第6帧将是带有文本字段的区域 #---第6帧--- frame6=tk.Frame(根,bg='#80c1ff')#稍后删除颜色 frame6.place(relx=0.0,rely=0.4,relheight=1,relwidth=1,anchor='nw') text_frame=tk.frame(frame6) text_frame.place(relx=0,rely=0,relheight=0.6,relwidth=1,anchor='nw') text=tk.text(文本框架) text.place(relx=0,rely=0,relheight=1,relwidth=1,anchor='nw') vsb=tk.滚动条(文本框) vsb.pack(侧边='right',填充='y') text.config(yscrollcommand=vsb.set) vsb.config(命令=text.yview) #---第6帧--- 停止=真#“停止”标志。如果未进行测量,则为True root.mainloop()#这里我们运行我们的应用程序 #---梅因---

Python 3.x g='gray' 单个按钮位置(relx=0.85,RELn=0.5,锚定=中心) #---第2帧--- #---第3帧--- frame3=tk.Frame(根,bd=5)#删除了这个bg='#80c1ff'(我用它来查看帧的边框) frame3.place(relx=0,rely=0.2,relheight=0.07,relwidth=1,anchor='nw') #“停止测量”按钮 #这将在最初禁用,并且仅在正在进行测量时启用 按钮停止=tk.按钮(第3帧,text=“停止测量”,bg='#80c1ff',fg='红色',state='disabled',command=stop\u测量) 按钮位置(relx=0.5,RELn=0.5,锚定=中心) #---第3帧--- #---第4帧--- frame4=tk.Frame(根,bd=5) frame4.place(relx=0,rely=0.3,relheight=0.09,relwidth=1,anchor='nw') label2=tk.Label(frame4,text=“选择要打印数据的传感器:”) 标签2.位置(relx=0.1,rely=0.3,relwidth=0.3,relheight=0.5) clickedForPlotting=tk.StringVar() clickedForPlotting.set(选项[0])#默认值 dropPlot=tk.OptionMenu(第4帧,单击打印,*选项) dropPlot.place(relx=0.5,rely=0.5,anchor='center') #改天 #dropDownButton=tk.Button(frame4,text=“Plot sensor data”,bg='#80c1ff',fg='red',command=single_sensor)#bg='gray' #下拉按钮。放置(relx=0.85,rely=0.5,anchor='center') #---第4帧--- #第5帧将保存为txt文件 #第6帧将是带有文本字段的区域 #---第6帧--- frame6=tk.Frame(根,bg='#80c1ff')#稍后删除颜色 frame6.place(relx=0.0,rely=0.4,relheight=1,relwidth=1,anchor='nw') text_frame=tk.frame(frame6) text_frame.place(relx=0,rely=0,relheight=0.6,relwidth=1,anchor='nw') text=tk.text(文本框架) text.place(relx=0,rely=0,relheight=1,relwidth=1,anchor='nw') vsb=tk.滚动条(文本框) vsb.pack(侧边='right',填充='y') text.config(yscrollcommand=vsb.set) vsb.config(命令=text.yview) #---第6帧--- 停止=真#“停止”标志。如果未进行测量,则为True root.mainloop()#这里我们运行我们的应用程序 #---梅因---,python-3.x,tkinter,serial-port,pyserial,Python 3.x,Tkinter,Serial Port,Pyserial,我的代码的问题是它确实不一致 有时它会工作得很好。大多数时候,它不会启动。我一直按“测量所有传感器”按钮,它被卡住了。我重新启动了三次,得到了相同的结果。第四次尝试时,它可以工作(通常,我必须按“测量所有传感器”按钮两次) 当我按下rx按钮时,它几乎总是失败。有一次,它成功了。相同的代码 即使程序确实成功了。有时它会工作得很好。其他时候,字符的显示速度会比正常情况下慢,当我对传感器(电位计)进行更改时,字符的更改将需要一些时间。然后在缓冲了大量数据后,字符将开始出现混合,程序将崩溃 我的代码的行

我的代码的问题是它确实不一致

  • 有时它会工作得很好。大多数时候,它不会启动。我一直按“测量所有传感器”按钮,它被卡住了。我重新启动了三次,得到了相同的结果。第四次尝试时,它可以工作(通常,我必须按“测量所有传感器”按钮两次)
  • 当我按下
    rx
    按钮时,它几乎总是失败。有一次,它成功了。相同的代码
  • 即使程序确实成功了。有时它会工作得很好。其他时候,字符的显示速度会比正常情况下慢,当我对传感器(电位计)进行更改时,字符的更改将需要一些时间。然后在缓冲了大量数据后,字符将开始出现混合,程序将崩溃
  • 我的代码的行为真的是不一致的,我不明白为什么它有时有效,有时无效

    我做每件事都是按部就班的。到目前为止,还没有人能帮助我,甚至没有人能给我一个关于为什么会发生这种行为的指导


    我已经陷入这个“简单”的问题两个月了。我在这一点上感到绝望。如果有人想要贝宝捐款或什么的,为了帮助我,我在。请帮帮我。

    您不应该多次调用
    measure\u all()
    (与
    measure\u single()
    相同),否则它将创建多个同时运行的定期任务(调用
    readSerial()
    )。
    import tkinter as tk
    import tkinter.ttk as ttk
    import serial.tools.list_ports #for a list of all the COM ports
    from tkinter import scrolledtext
    from time import sleep
    
    
    #to be used on our canvas
    HEIGHT = 800
    WIDTH = 800
    
    #hardcoded baud rate
    baudRate = 9600
    
    # this is the global variable that will hold the serial object value
    ser = None #initial  value. will change at 'on_select()'
    
    after_id = None
    
    #this is the global variable that will hold the value from the dropdown for the sensor select
    dropdown_value = None
    
    
    
    # --- functions ---
    
    #the following two functtions are for the seria port selection, on frame 1
    
    #this function populates the combobox on frame1, with all the serial ports of the system
    def serial_ports():
        return serial.tools.list_ports.comports()
    
    
    #when the user selects one serial port from the combobox, this function will execute
    def on_select(event=None):
        global ser
        COMPort = cb.get()
        string_separator = "-"
        COMPort = COMPort.split(string_separator, 1)[0] #remove everything after '-' character
        COMPort = COMPort[:-1] #remove last character of the string (which is a space)
        ser = serial.Serial(port = COMPort, baudrate=9600, timeout=0.1)
    
    
    def readSerial():
        global after_id
        try:
           ser_bytes = ser.readline()
           ser_bytes = ser_bytes.decode("utf-8")
        except UnicodeExceptionError:
           print("Oops")
        text.insert("end", ser_bytes)
        if vsb.get()[1]==1.0: #if the scrollbar is down to the bottom, then autoscroll
           text.see("end")
        after_id=root.after(50,readSerial)
    
    # this function is triggered, when a value is selected from the dropdown
    def dropdown_selection(*args):    
       global dropdown_value
       dropdown_value = clicked.get()
       button_single['state'] = 'normal' #when a selection from the dropdown happens, change the state of the 'Measure This Sensor' button to normal
    
    
    # this function is triggered, when button 'Measure all Sensors' is pressed, on frame 2
    def measure_all():    
       global stop_
       stop_ = False
       button_stop['state']='normal' #make the 'Stop Measurement' button accessible
       ser.write("rf".encode()) #Send string 'rf to arduino', which means Measure all Sensors
       sleep(0.05) # 50 milliseconds
       readSerial() #Start Reading data
    
    
    # this function is triggered, when button 'Measure this Sensor' is pressed, on frame 2
    def measure_single():    
       global stop_
       stop_=False
       button_stop['state']='normal'
       ser.write(dropdown_value.encode()) #Send string 'rf to arduino', which means Measure all Sensors!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       readSerial()
    
    
    # this function is triggered, when button 'STOP measurement(s)' is pressed, on frame 2
    def stop_measurement():    
        global stop_
        stop_=True
        button_stop['state']='disabled'
        ser.write("c".encode())
        root.after_cancel(after_id) #do i need after_id to be global?
    # --- functions ---
    
    
    
    # --- main ---
    root = tk.Tk() #here we create our tkinter window
    root.title("Sensor Interface")
    
    #we use canvas as a placeholder, to get our initial screen size (we have defined HEIGHT and WIDTH)
    canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
    canvas.pack()
    
    #we use frames to organize all the widgets in the screen
    
    '''
    relheight, relwidth − Height and width as a float between 0.0 and 1.0, as a fraction of the height and width of the parent widget.
    relx, rely − Horizontal and vertical offset as a float between 0.0 and 1.0, as a fraction of the height and width of the parent widget.
    '''
    
    # --- frame 1 ---
    frame1 = tk.Frame(root)
    frame1.place(relx=0, rely=0.05, relheight=0.03, relwidth=1, anchor='nw') #we use relheight and relwidth to fill whatever the parent is - in this case- root
    
    label0 = tk.Label(frame1, text="Select the COM port that the device is plugged in: ")
    label0.config(font=("TkDefaultFont", 8))
    label0.place(relx = 0.1, rely=0.3, relwidth=0.3, relheight=0.5)
    
    
    cb = ttk.Combobox(frame1, values=serial_ports())
    cb.place(relx=0.5, rely=0.5, anchor='center')
    # assign function to combobox, that will run when an item is selected from the dropdown
    cb.bind('<<ComboboxSelected>>', on_select)
    # --- frame 1 ---
    
    
    
    # --- frame 2 ---
    frame2 = tk.Frame(root, bd=5) #REMOVED THIS bg='#80c1ff' (i used it to see the borders of the frame)
    frame2.place(relx=0, rely=0.1, relheight=0.07, relwidth=1, anchor='nw')
    
    #Button for 'Measure All Sensors'
    #it will be enabled initially
    button_all = tk.Button(frame2, text="Measure all Sensors", bg='#80c1ff', fg='red', state='normal', command=measure_all)  #bg='gray'
    button_all.place(relx=0.2, rely=0.5, anchor='center')
    
    #label
    label1 = tk.Label(frame2, text="OR, select a single sensor to measure: ")
    label1.config(font=("TkDefaultFont", 9))
    label1.place(relx = 0.32, rely=0.3, relwidth=0.3, relheight=0.4)
    
    #dropdown
    #OPTIONS = [0,1,2,3,4,5,6,7]
    OPTIONS = list(range(8)) #[0,1,2,3,4,5,6,7]
    clicked = tk.StringVar(master=frame2) # Always pass the `master` keyword argument, in order to run the function when we select from the dropdown
    clicked.set(OPTIONS[0]) # default value
    clicked.trace("w", dropdown_selection) #When a value from the dropdown is selected, function dropdown_selection() is executed
    drop = tk.OptionMenu(frame2, clicked, *OPTIONS)
    drop.place(relx = 0.65, rely=0.25, relwidth=0.08, relheight=0.6)
    
    #Button for 'Measure Single Sensor'
    #this will be disabled initially, and will be enabled when an item from the dropdown is selected
    button_single = tk.Button(frame2, text="Measure this Sensor", bg='#80c1ff', fg='red', state='disabled', command=measure_single) #bg='gray'
    button_single.place(relx = 0.85, rely=0.5, anchor='center')
    # --- frame 2 ---
    
    
    # --- frame 3 ---
    frame3 = tk.Frame(root, bd=5) #REMOVED THIS bg='#80c1ff' (i used it to see the borders of the frame)
    frame3.place(relx=0, rely=0.2, relheight=0.07, relwidth=1, anchor='nw')
    
    #Button for 'STOP Measurement(s)'
    #this will be disabled initially, and will be enabled only when a measurement is ongoing
    button_stop = tk.Button(frame3, text="STOP measurement(s)", bg='#80c1ff', fg='red', state='disabled', command=stop_measurement)
    button_stop.place(relx=0.5, rely=0.5, anchor='center')
    # --- frame 3 ---
    
    
    
    # --- frame 4 ---
    frame4 = tk.Frame(root, bd=5)
    frame4.place(relx=0, rely=0.3, relheight=0.09, relwidth=1, anchor='nw')
    
    label2 = tk.Label(frame4, text="Select a sensor to plot data: ")
    label2.place(relx = 0.1, rely=0.3, relwidth=0.3, relheight=0.5)
    
    clickedForPlotting = tk.StringVar()
    clickedForPlotting.set(OPTIONS[0]) # default value
    dropPlot = tk.OptionMenu(frame4, clickedForPlotting, *OPTIONS)
    dropPlot.place(relx=0.5, rely=0.5, anchor='center')
    
    #CHANGE LATER
    #dropDownButton = tk.Button(frame4, text="Plot sensor data", bg='#80c1ff', fg='red', command=single_Sensor) #bg='gray'
    #dropDownButton.place(relx = 0.85, rely=0.5, anchor='center')
    # --- frame 4 ---
    
    
    #frame 5 will be the save to txt file
    
    
    #frame 6 will be the area with the text field
    # --- frame 6 ---
    frame6 = tk.Frame(root, bg='#80c1ff') #remove color later
    frame6.place(relx=0.0, rely=0.4, relheight=1, relwidth=1, anchor='nw')
    
    text_frame=tk.Frame(frame6)
    text_frame.place(relx=0, rely=0, relheight=0.6, relwidth=1, anchor='nw')
    text=tk.Text(text_frame)
    text.place(relx=0, rely=0, relheight=1, relwidth=1, anchor='nw')
    vsb=tk.Scrollbar(text_frame)
    vsb.pack(side='right',fill='y')
    text.config(yscrollcommand=vsb.set)
    vsb.config(command=text.yview)
    # --- frame 6 ---
    
    
    
    
    stop_=True # 'Stop' flag. True when no measuring is happening
    
    root.mainloop() #here we run our app
    # --- main ---