Pyserial readline() 永远挂起程序而不读取串行数据

Posted

技术标签:

【中文标题】Pyserial readline() 永远挂起程序而不读取串行数据【英文标题】:Pyserial readline() hangs the program forever without reading serial data 【发布时间】:2018-02-13 10:40:21 【问题描述】:

调用 pyserial.readline() 函数时,我的程序挂起。我在程序上运行了一个跟踪,底部循环不断重复。

transport.py(47):             self.sensor_data = self.serif.readline()
 --- modulename: serialposix, funcname: read
serialposix.py(477):         if not self.is_open:
serialposix.py(479):         read = bytearray()
serialposix.py(480):         timeout = Timeout(self._timeout)
 --- modulename: serialutil, funcname: __init__
serialutil.py(125):         self.is_infinite = (duration is None)
serialutil.py(126):         self.is_non_blocking = (duration == 0)
serialutil.py(127):         self.duration = duration
serialutil.py(128):         if duration is not None:
serialutil.py(129):             self.target_time = self.TIME() + duration
serialposix.py(481):         while len(read) < size:
serialposix.py(482):             try:
serialposix.py(483):                 ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
 --- modulename: serialutil, funcname: time_left
serialutil.py(139):         if self.is_non_blocking:
serialutil.py(141):         elif self.is_infinite:
serialutil.py(144):             delta = self.target_time - self.TIME()
serialutil.py(145):             if delta > self.duration:
serialutil.py(150):                 return max(0, delta)
serialposix.py(484):                 if self.pipe_abort_read_r in ready:
serialposix.py(491):                 if not ready:
serialposix.py(493):                 buf = os.read(self.fd, size - len(read))
serialposix.py(496):                 if not buf:
serialposix.py(503):                 read.extend(buf)
serialposix.py(516):             if timeout.expired():
 --- modulename: serialutil, funcname: expired
serialutil.py(135):         return self.target_time is not None and self.time_left() <= 0
 --- modulename: serialutil, funcname: time_left
serialutil.py(139):         if self.is_non_blocking:
serialutil.py(141):         elif self.is_infinite:
serialutil.py(144):             delta = self.target_time - self.TIME()
serialutil.py(145):             if delta > self.duration:
serialutil.py(150):                 return max(0, delta)
serialposix.py(481):         while len(read) < size:
serialposix.py(518):         return bytes(read)

我驱动定义为“serif”的接口的串行设置如下。

    self.serif = serial.Serial('/dev/ttyS1', 9600)
    self.serif.bytesize = serial.EIGHTBITS
    self.serif.parity = serial.PARITY_NONE
    self.serif.stopbits = serial.STOPBITS_ONE
    self.serif.timeout = 0.3

我尝试在开始读取函数之前添加函数self.serif.reset_input_buffer(),但这似乎让事情变得更糟。

这是readline() 函数之前的相关函数的副本。

def rcv_data(self):
    """Receives data, cleans it and returns it to main()"""
    # CHECKS FOR DATA IN BUFFER
    serial_buffer = self.serif.inWaiting()
    if serial_buffer > 0:
        cnt = 0
        print("serial_buffer = %i" % serial_buffer)
        while self.serif.read().encode('hex') != '02':
            cnt += 1
            serial_buffer -= 1
        print("Eliminated %i peices of garbage" % (cnt))
        # Reads data from the buffer
        self.sensor_data = self.serif.readline()

我无法弄清楚为什么这段代码似乎卡在了 serialposix.py 循环中。如果有人可以帮助我,我将不胜感激!

谢谢,如果我需要发送更多信息,请告诉我。

【问题讨论】:

【参考方案1】:

编辑

为什么我以前让它工作不再是一个谜。我为我的设备和 RS485 电路上拉/下拉电阻器供电的电源不稳定。因此,我在我的 SOF 或 EOF 应该在的地方收到了噪音,因此程序一直在继续阅读。话虽如此,我仍然保留了以下解决方法,因为它更清楚我在做什么(虽然更长......)

此外,我在下面的答案中添加了一个中断,以防在一定数量的读取周期中找不到 SOF 或 EOF。

EDIT_END

不是特别的答案,而是一种解决方法。我将首先强调以下内容。

    readline() 正在循环,因为它期望 EOF 为 \n0x11 十六进制)i,而我的串行数据从未提供过这个。为什么我之前让它工作是个谜。 我仍然不知道为什么在设置的超时后它没有停止循环。

我的解决方法基本上是在某种意义上创建我自己的 readline() 函数,并指定我自己的 EOF。我使用以下代码来执行此操作。

def readline(self):
    SOF = '02'
    EOF = '03'
    # FIND START OF FRAME
    while serif.read().encode('hex') != SOF:
        continue
    # RECORD UNTIL END OF FRAME
    while True:
        temp = serif.read()
        if temp.encode('hex') == EOF:
            break
        else:
            sensor_data += temp

我原来的函数现在看起来像这样。

def rcv_data(self):
    """Receives data cleans it and returns it to main()"""
    # CHECKS FOR DATA IN BUFFER
    if serif.inWaiting() > 0:
        readline()
    return sensor_data

【讨论】:

以上是关于Pyserial readline() 永远挂起程序而不读取串行数据的主要内容,如果未能解决你的问题,请参考以下文章

Pyserial readline() 并等到收到一个值才能继续

提高 pyserial readline 速度

在另一个线程中中断 pySerial readline

python pyserial readline 不工作,但 screen 有点工作,在 ubuntu 16 中工作

PySerial 读取问题

pyserial相关资料整理