在 Tkinter 文本框中显示时从串口读取的问题处理数据
Issue processing data read from serial port, when displaying it in a Tkinter textbox
所以我正在读取(并用 tkinter 文本框显示)来自串行连接的数据,但我无法按照我的意愿处理返回的数据,以便 运行 我的测试。更简单地说,即使显示 machine response = 0x1
,我也无法从全局 serBuffer
.
读取它
在将其显示给 textbox
之前,我会从测试 function
内部读取,然后检查响应是否在 string
中,但现在我传递了读取数据(字符串)到一个全局变量然后尝试读取它,它似乎不起作用,除非我从 readserial
中删除 serBuffer = ""
。但这导致了一个新问题。当我按下按钮发送命令时,它会发送它,但只有在我第二次按下它之后以及每次之后才收到响应。因此,结果我得到 Fail
如果我 运行 测试一次,但我每次都通过。
具有期望响应的图片(test function
未读取 0x1 且始终 returns 失败)
带有非期望响应的图片(仅在第二次按下后以及每次按下后才收到响应。因此,如果我 运行 测试过一次,但我每次都通过)。
import tkinter as tk
import serial
from serial import *
serialPort = "COM3"
baudRate = 115200
ser = Serial(serialPort, baudRate, timeout=0, writeTimeout=0) #ensure non-blocking
#make a TkInter Window
mainWindow = tk.Tk()
mainWindow.wm_title("Reading Serial")
mainWindow.geometry('1650x1000+500+100')
scrollbar = tk.Scrollbar(mainWindow)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
log = tk.Text ( mainWindow, width=60, height=60, takefocus=0)
log.pack()
log.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=log.yview)
#make our own buffer
#useful for parsing commands
#Serial.readline seems unreliable at times too
serBuffer = ""
ser.write(b'\r\n')
def readSerial():
while True:
c = (ser.read().decode('utf-8', 'ignore')) # attempt to read a character from Serial
# was anything read?
if len(c) == 0:
break
# get the buffer from outside of this function
global serBuffer
# check if character is a delimeter
if c == '\r':
serBuffer += "\n" # don't want returns. chuck it
if c == '\n':
serBuffer += "\n" # add the newline to the buffer
# add the line to the TOP of the log
log.insert('1.1', serBuffer)
serBuffer = "" # empty the buffer
else:
serBuffer += c # add to the buffer
mainWindow.after(100, readSerial) # check serial again soon
def test():
command = b" test command \r\n"
ser.write(command)
global serBuffer
time.sleep(0.5)
if "0x1" in serBuffer:
print('PASS')
return 'PASS'
else:
print('FAIL')
return 'FAIL'
button = tk.Button(mainWindow, text="Pone Test", font=40, bg='#b1c62d', command=test)
button.place(relx=0.8, rely=0, relwidth=0.1, relheight=0.05)
# after initializing serial, an arduino may need a bit of time to reset
mainWindow.after(100, readSerial)
mainWindow.mainloop()
Comment: but only receives the response after the second time a press it, and every time after. So as a result i get a Fail if i run the test once, but i get a pass everytime after
提高第一个,超时从 100
到 500
或更多。
# after initializing serial, an arduino may need a bit of time to reset
mainWindow.after(100, self.readSerial)
要找出第一个响应的延迟,请尝试以下操作:
Note: You have to do this without running def readSerial
, to prevent concurent empty the in buffer
"
command = b" test command \r\n"
self.ser.write(command)
delay = 0.0
# wait until you get `.in_waiting` data.
while not self.ser.in_waiting:
time.sleep(0.1)
delay += 0.1
print('.', end='')
if delay >= 10:
print('BREAK after {} no in_waiting'.format(int(delay * 10)))
break
print('Delay:{}, in_waiting:{}'.format(delay, self.ser.in_waiting))
以下适合我。
Note: I use OOP
syntax.
last_command
serBuffer = ""
last_command = None
将准备好的read_buffer
复制到last_command
,只空read_buffer
def readSerial(self):
while True:
c = (self.ser.read().decode('utf-8', 'ignore')) # attempt to read a character from Serial
# was anything read?
if len(c) == 0:
break
# get the buffer from outside of this function
global serBuffer
# check if character is a delimeter
if c == '\r':
serBuffer += "\n" # don't want returns. chuck it
if c == '\n':
serBuffer += "\n" # add the newline to the buffer
global last_command
last_command = serBuffer
# add the line to the TOP of the log
# log.insert('1.1', last_command)
print('readSerial.last_command:"{}"'.format(bytes(last_command, 'utf-8')))
serBuffer = "" # empty the buffer
else:
serBuffer += c # add to the buffer
print('readSerial:"{}"'.format(bytes(serBuffer, 'utf-8')))
self.after(100, self.readSerial) # check serial again soon
做test()
def test(self, write=True):
print('test(write={})'.format(write))
if write:
command = b" test command \r\n"
self.ser.write(command)
self.after(500, self.test, False)
elif last_command is not None:
print('last_command:{}'.format(bytes(last_command, 'utf-8')))
if "0x1" in last_command:
print('PASS')
else:
print('FAIL')
else:
# ATTENTION: This could lead to a infinit loop
# self.after(500, self.test, False)
pass
Output:
test(write=True)
readSerial:"b' '"
readSerial:"b' t'"
readSerial:"b' te'"
readSerial:"b' tes'"
readSerial:"b' test'"
readSerial:"b' test '"
readSerial:"b' test c'"
readSerial:"b' test co'"
readSerial:"b' test com'"
readSerial:"b' test comm'"
readSerial:"b' test comma'"
readSerial:"b' test comman'"
readSerial:"b' test command'"
readSerial:"b' test command '"
readSerial:"b' test command \n\r'"
readSerial.last_command:"b' test command \n\r\n'"
test(write=False)
last_command:b' test command \n\r\n'
FAIL
Note: I get FAIL
, because there is no 0x1
in last_command
as i use PORT = 'loop://'
which echo what is writen!
我做了一些修改,检查这个。
def readSerial():
while True:
c = (ser.read(1).decode('utf-8', 'ignore')) from Serial
if len(c) == 0:
break
global serBuffer
if c == '\r':
serBuffer += ""
if c == '\n':
serBuffer += "\n"
log.insert(tk.END, serBuffer)
log.see(tk.END)
log.update_idletasks()
serBuffer = ""
else:
serBuffer += c
mainWindow.after(500, readSerial)
所以我正在读取(并用 tkinter 文本框显示)来自串行连接的数据,但我无法按照我的意愿处理返回的数据,以便 运行 我的测试。更简单地说,即使显示 machine response = 0x1
,我也无法从全局 serBuffer
.
在将其显示给 textbox
之前,我会从测试 function
内部读取,然后检查响应是否在 string
中,但现在我传递了读取数据(字符串)到一个全局变量然后尝试读取它,它似乎不起作用,除非我从 readserial
中删除 serBuffer = ""
。但这导致了一个新问题。当我按下按钮发送命令时,它会发送它,但只有在我第二次按下它之后以及每次之后才收到响应。因此,结果我得到 Fail
如果我 运行 测试一次,但我每次都通过。
具有期望响应的图片(test function
未读取 0x1 且始终 returns 失败)
带有非期望响应的图片(仅在第二次按下后以及每次按下后才收到响应。因此,如果我 运行 测试过一次,但我每次都通过)。
import tkinter as tk
import serial
from serial import *
serialPort = "COM3"
baudRate = 115200
ser = Serial(serialPort, baudRate, timeout=0, writeTimeout=0) #ensure non-blocking
#make a TkInter Window
mainWindow = tk.Tk()
mainWindow.wm_title("Reading Serial")
mainWindow.geometry('1650x1000+500+100')
scrollbar = tk.Scrollbar(mainWindow)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
log = tk.Text ( mainWindow, width=60, height=60, takefocus=0)
log.pack()
log.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=log.yview)
#make our own buffer
#useful for parsing commands
#Serial.readline seems unreliable at times too
serBuffer = ""
ser.write(b'\r\n')
def readSerial():
while True:
c = (ser.read().decode('utf-8', 'ignore')) # attempt to read a character from Serial
# was anything read?
if len(c) == 0:
break
# get the buffer from outside of this function
global serBuffer
# check if character is a delimeter
if c == '\r':
serBuffer += "\n" # don't want returns. chuck it
if c == '\n':
serBuffer += "\n" # add the newline to the buffer
# add the line to the TOP of the log
log.insert('1.1', serBuffer)
serBuffer = "" # empty the buffer
else:
serBuffer += c # add to the buffer
mainWindow.after(100, readSerial) # check serial again soon
def test():
command = b" test command \r\n"
ser.write(command)
global serBuffer
time.sleep(0.5)
if "0x1" in serBuffer:
print('PASS')
return 'PASS'
else:
print('FAIL')
return 'FAIL'
button = tk.Button(mainWindow, text="Pone Test", font=40, bg='#b1c62d', command=test)
button.place(relx=0.8, rely=0, relwidth=0.1, relheight=0.05)
# after initializing serial, an arduino may need a bit of time to reset
mainWindow.after(100, readSerial)
mainWindow.mainloop()
Comment: but only receives the response after the second time a press it, and every time after. So as a result i get a Fail if i run the test once, but i get a pass everytime after
提高第一个,超时从 100
到 500
或更多。
# after initializing serial, an arduino may need a bit of time to reset
mainWindow.after(100, self.readSerial)
要找出第一个响应的延迟,请尝试以下操作:
Note: You have to do this without running
def readSerial
, to prevent concurent empty thein buffer
"
command = b" test command \r\n"
self.ser.write(command)
delay = 0.0
# wait until you get `.in_waiting` data.
while not self.ser.in_waiting:
time.sleep(0.1)
delay += 0.1
print('.', end='')
if delay >= 10:
print('BREAK after {} no in_waiting'.format(int(delay * 10)))
break
print('Delay:{}, in_waiting:{}'.format(delay, self.ser.in_waiting))
以下适合我。
Note: I use
OOP
syntax.
last_command
serBuffer = "" last_command = None
将准备好的
read_buffer
复制到last_command
,只空read_buffer
def readSerial(self): while True: c = (self.ser.read().decode('utf-8', 'ignore')) # attempt to read a character from Serial # was anything read? if len(c) == 0: break # get the buffer from outside of this function global serBuffer # check if character is a delimeter if c == '\r': serBuffer += "\n" # don't want returns. chuck it if c == '\n': serBuffer += "\n" # add the newline to the buffer global last_command last_command = serBuffer # add the line to the TOP of the log # log.insert('1.1', last_command) print('readSerial.last_command:"{}"'.format(bytes(last_command, 'utf-8'))) serBuffer = "" # empty the buffer else: serBuffer += c # add to the buffer print('readSerial:"{}"'.format(bytes(serBuffer, 'utf-8'))) self.after(100, self.readSerial) # check serial again soon
做
test()
def test(self, write=True): print('test(write={})'.format(write)) if write: command = b" test command \r\n" self.ser.write(command) self.after(500, self.test, False) elif last_command is not None: print('last_command:{}'.format(bytes(last_command, 'utf-8'))) if "0x1" in last_command: print('PASS') else: print('FAIL') else: # ATTENTION: This could lead to a infinit loop # self.after(500, self.test, False) pass
Output:
test(write=True) readSerial:"b' '" readSerial:"b' t'" readSerial:"b' te'" readSerial:"b' tes'" readSerial:"b' test'" readSerial:"b' test '" readSerial:"b' test c'" readSerial:"b' test co'" readSerial:"b' test com'" readSerial:"b' test comm'" readSerial:"b' test comma'" readSerial:"b' test comman'" readSerial:"b' test command'" readSerial:"b' test command '" readSerial:"b' test command \n\r'" readSerial.last_command:"b' test command \n\r\n'" test(write=False) last_command:b' test command \n\r\n' FAIL
Note: I get
FAIL
, because there is no0x1
inlast_command
as i usePORT = 'loop://'
which echo what is writen!
我做了一些修改,检查这个。
def readSerial():
while True:
c = (ser.read(1).decode('utf-8', 'ignore')) from Serial
if len(c) == 0:
break
global serBuffer
if c == '\r':
serBuffer += ""
if c == '\n':
serBuffer += "\n"
log.insert(tk.END, serBuffer)
log.see(tk.END)
log.update_idletasks()
serBuffer = ""
else:
serBuffer += c
mainWindow.after(500, readSerial)