从函数设置串行对象(从 tkinter 交互调用)
Posted
技术标签:
【中文标题】从函数设置串行对象(从 tkinter 交互调用)【英文标题】:Setting up the serial object from a function (called from tkinter interaction) 【发布时间】:2021-03-06 21:37:32 【问题描述】:我设法让我的 tkinter 应用程序在文本字段上显示文本。
我通过硬编码 COM 端口和波特率来做到这一点,然后在我的程序开始时设置一个串行对象。
baudRate = 9600
ser = serial.Serial('COM16', baudRate)
然后我的所有代码都会运行。
但问题在于所有内容都是硬编码的。 我希望用户能够从下拉列表中选择 COM 端口。 当他选择一个端口时,串行通信应该开始了。
所以我就是这样做的。这是我的相关代码。
#hardcoded baud rate
baudRate = 9600
# this is the global variable that will hold the serial object value
ser = 0 #initial value. will change at 'on_select()'
#this function populates the dropdown 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 dropdown, 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)
return ser
readSerial() #start reading
#this function reads the incoming data and inserts them into a text frame
def readSerial():
ser_bytes = ser.readline()
ser_bytes = ser_bytes.decode("utf-8")
text.insert("end", ser_bytes)
if vsb.get()[1]==1.0:
text.see("end")
root.after(100, readSerial)
当我从下拉列表中选择一个 COM 端口时会发生什么,我在设备的 LED 按钮上看到了传输。
但是,文本框架上没有显示任何内容。之前,当我对所有内容进行硬编码并在程序开始时设置串行对象,并在程序结束时声明readSerial()
函数时,一切正常。
【问题讨论】:
【参考方案1】:在您的on_select
函数中,您在调用readSerial()
函数之前调用了return
。 return
语句终止函数的执行,它后面的任何语句都不会被执行。删除它会使程序正常工作。
另外,由于on_select
是下拉列表的回调,return
语句是多余的,因为它没有任何地方可以返回。 global ser
负责将新值全局分配给 ser
变量。
您无需在每次选择新选项时调用readSerial()
函数(否则,每次都会增加预定调用次数)。您可以拥有一个在初始配置后调用它的按钮,然后从on_select
中删除对readSerial()
的调用,或者创建一个标志以确保它只被调用一次。
根据您的评论,我创建了以下示例,您可以尝试这样的操作
from tkinter import *
def on_select(event):
global value
value=option.get()
if stop_:
start_button['state']='normal'
def start():
global stop_
stop_=False
readSerial()
start_button['state']='disabled'
stop_button['state']='normal'
def stop():
global stop_
stop_=True
root.after_cancel(after_id)
start_button['state']='normal'
stop_button['state']='disabled'
def readSerial():
global after_id
text.insert(END,value)
after_id=root.after(100,readSerial)
root=Tk()
text=Text(root)
text.pack(side='bottom')
options=['1','2']
option=StringVar()
om=OptionMenu(root,option,*options,command=on_select)
om.pack(side='left')
start_button=Button(root,text='start',command=start,state='disabled')
start_button.pack(side='left')
stop_button=Button(root,text='stop',command=stop,state='disabled')
stop_button.pack(side='left')
stop_=True
root.mainloop()
【讨论】:
很好的解释 我正试图弄清楚。 1.完全删除return语句。关于你的第三段......我不太明白......在我的代码中,我还必须能够停止 readSerial() 函数。因为我的 arduino 程序只会在触发时发送数据。因此,当我从 tkinter 发送 STOP TRANSMIT 命令时,我还必须停止 readSerial()。哇什么是最好的方法。也许是一个通过设置串行对象来启动串行通信的按钮。另一个按钮将启动 readSerial() 并设置一个标志,另一个按钮将发送 StopTransmit 命令到 arduino,但它也必须停止 readSerial(),有可能吗? @user1584421 我已经用一个例子更新了答案,我相信你正在寻找类似的东西,如果有帮助,请告诉我。 此代码有效吗?在 readSerial() 中,当标志 (stop_) 设置为 True 时,这两行将不会执行。所以它不会打印到文本字段。但是如果 root.after(100,readSerial) 已经启动,那么你的 readSerial() 函数将不会停止它的执行。如果已经启动,您的 readSerial() 是否还应该包含主动停止定期执行的代码?我看到 _cancel 是这样做的。所以也许readSerial()会把一个flag转成True,停止按钮会检查是否设置了True,如果是,就会调用id上的_cancel函数。以上是关于从函数设置串行对象(从 tkinter 交互调用)的主要内容,如果未能解决你的问题,请参考以下文章
在 Tkinter 文本框中显示从串行端口读取的数据时,发出处理数据
将串行从 Raspberry 传递到 Arduino USB HID
如何从 tkinter 滑块/刻度重复输出,以便我可以通过串行向另一台设备发送恒定的数字流?