PySerial 丢失数据
Posted
技术标签:
【中文标题】PySerial 丢失数据【英文标题】:PySerial loses data 【发布时间】:2013-07-23 01:15:44 【问题描述】:我的问题是,PySerial 似乎丢失了一些数据包,我不知道为什么。
我有两个 python 脚本,第一个从文本文件中读取数据并将其写入微控制器,在微控制器中处理数据。然后,微控制器通过不同的串行端口将修改后的数据发送回 PC。 (澄清一下:我需要两个串口,因为在最终应用中,脚本会在不同的PC上运行。但是,出于测试目的,在一台PC上运行两个脚本更容易)
所以基本上,我的硬件设置如下:
PC ----(serial port 1)----> microcontroller
<---(serial port 2)-----
将数据写入微控制器后,我希望能得到一定数量的数据字节。如果我使用终端程序(如超级终端)来监控接收到的数据,一切看起来都很好。但是,如果我尝试使用 Python 脚本读取数据,我只会得到预期数据字节的一小部分。
例如:
+--------------------+--------------------+
| with HyperTerminal | with Python script |
+--------------------+--------------------+
| 1:W:00522 | 1:W:00522 |
| 1:W:00532 | 1:W:00532 |
| 1:W:00518 | 1:W:00522 |
| 1:W:00522 | 1:W:00526 |
| 1:W:00522 | 1:W:00514 |
| 1:W:00526 | 1:W:00520 |
| 1:W:00514 | 1:W:00514 |
| 1:W:00520 | 1:W:00522 |
| 1:W:00520 | 1:W:00526 |
| 1:W:00514 | 1:W:00520 |
| 1:W:00516 | 1:W:00526 |
| 1:W:00522 | 1:W:00520 |
| 1:W:00526 | 1:W:00524 |
| 1:W:00520 | 1:W:00526 |
| 1:W:00520 | 1:W:00532 |
| 1:W:00526 | 1:W:00506 |
| 1:W:00522 | 1:W:00520 |
| 1:W:00520 | 1:W:00526 |
| 1:W:00524 | 1:W:00524 |
| 1:W:00522 | 1:W:00526 |
| 1:W:00526 | 1:W:00514 |
| 1:W:00514 | 1:W:00522 |
| 1:W:00532 | 1:W:00520 |
| 1:W:00506 | 1:W:00510 |
| 1:W:00522 | 1:W:00506 |
| 1:W:00520 | |
| 1:W:00526 | |
| 1:W:00530 | |
| 1:W:00524 | |
| 1:W:00526 | |
| 1:W:00514 | |
| 1:W:00514 | |
| 1:W:00522 | |
| 1:W:00524 | |
| 1:W:00520 | |
| 1:W:00510 | |
| 1:W:00506 | |
+--------------------+--------------------+
如您所见,如果我尝试使用 Python 脚本从串行端口读取数据,则会丢失一些数据。由于事实上,如果我使用终端程序,我会得到预期的数据,我假设我的 Python 脚本有错误。
我用于向微控制器发送数据的 Python 脚本如下所示:
import serial
import re
import time
class digiRealTest():
def __init__(self):
#configure serial port
self.ser = serial.Serial(7, 9600, parity=serial.PARITY_NONE)
def main(self):
filepath = 'C:\\Users\\Bernhard\\Desktop\\TomatoView\\Qt\\test_output.txt'
with open(filepath, 'r') as content_file:
content = content_file.read().decode("hex")
for match in re.finditer('[\02](.*?)[\03]', content, re.S):
res = match.group(1)
complete = '\x02' + res + '\x03'
# time.sleep(0.3) <-- if i uncomment this line, it work's!!!
self.ser.write(complete)
if __name__ == "__main__": #wenn Modul direkt ausgefuehrt wird
d = digiRealTest()
d.main()
我的用于接收微控制器发送的数据的 Python 脚本:
import Queue
import threading
import serial
class mySerial(threading.Thread):
def __init__(self, queue):
super(mySerial, self).__init__()
self.queue = queue #the received data is put in a queue
self.buffer = ''
#configure serial connection
self.ser = serial.Serial(timeout = 0, port = 3, baudrate=9600)
def run(self):
while True:
self.buffer += self.ser.read(self.ser.inWaiting()) #read all char in buffer
if '\n' in self.buffer: #split data line by line and store it in var
var, self.buffer = self.buffer.split('\n')[-2:]
self.queue.put(var) #put received line in the queue
time.sleep(0.01) #do not monopolize CPU
class Base():
def __init__(self):
self.queue = Queue.Queue(0) #create a new queue
self.ser = mySerial(self.queue)
self.ser.start() #run thread
def main(self ):
while(True):
try:
var = self.queue.get(False) #try to fetch a value from queue
except Queue.Empty:
pass #if it is empty, do nothing
else:
print(var)
if __name__ == '__main__':
b = Base()
b.main()
我不知道为什么,但如果我在发送脚本中取消注释 #time.sleep(0.3)
行,一切正常,我会得到预期的数据。所以对我来说,似乎不知何故我从串口读取数据的脚本太慢了....但是为什么呢?
【问题讨论】:
【参考方案1】:当你睡觉时,什么都没有发生......串行缓冲区相当小,可能只是在睡眠所需的时间内填满(在接收器上)......一旦它满了,在你阅读之前它不能再花更多时间了这样其他位就会丢失(或者它们可能会覆盖缓冲区中的位)......因为串行没有握手说嘿我收到了这些位
当您取消注释发送方的 sleep 行时,让它休眠,直到接收方读取整个流并将其清除以获取更多数据
或者试试
var, self.buffer = self.buffer.split('\n',1) #this will only split once
因为信息可能会丢失
var, self.buffer = self.buffer.split('\n')[-2:]
如果您已收到 2 个(或更多)\n
【讨论】:
如果我说对了,我应该删除接收脚本中的睡眠吗?我试过了,但没有任何变化。 更新答案以反映我在您的脚本中看到的其他潜在问题 感谢您的好建议,我没想到!理论上应该不可能连续收到两个(或更多)\n
,但它让程序更防弹,所以我会添加它。谢谢!【参考方案2】:
您的接收器的拆分正在丢线。这应该会更好:
def run(self):
while True:
self.buffer += self.ser.read(self.ser.inWaiting()) #read all char in buffer
while '\n' in self.buffer: #split data line by line and store it in var
var, self.buffer = self.buffer.split('\n', 1)
self.queue.put(var) #put received line in the queue
time.sleep(0.01) #do not monopolize CPU
您还可以通过在创建串行端口时摆脱超时来摆脱轮询/睡眠,并在队列中没有任何内容时请求 1 个字节。
class mySerial(threading.Thread):
def __init__(self, queue):
super(mySerial, self).__init__()
self.queue = queue #the received data is put in a queue
self.buffer = ''
#configure serial connection
self.ser = serial.Serial(port = 3, baudrate=9600)
def run(self):
while True:
self.buffer += self.ser.read(self.ser.inWaiting() or 1) #read all char in buffer
while '\n' in self.buffer: #split data line by line and store it in var
var, self.buffer = self.buffer.split('\n', 1)
self.queue.put(var) #put received line in the queue
【讨论】:
以上是关于PySerial 丢失数据的主要内容,如果未能解决你的问题,请参考以下文章