【问题标题】:pySerial 2.6: specify end-of-line in readline()pySerial 2.6:在 readline() 中指定行尾
【发布时间】:2013-05-09 20:51:58
【问题描述】:

我正在使用 pySerial 向 Eddie 发送命令。我需要在我的 readline 中指定一个回车,但是 pySerial 2.6 摆脱了它......有解决方法吗?

Eddie command set 列在此 PDF 的第二页和第三页。在 PDF 无法访问的情况下,这里是 backup image

一般命令形式:

Input:              <cmd>[<WS><param1>...<WS><paramN>]<CR>
Response (Success): [<param1>...<WS><paramN>]<CR>
Response (Failure): ERROR[<SP>-<SP><verbose_reason>]<CR> 

如您所见,所有回复都以\r 结尾。我需要告诉 pySerial 停止。

我现在拥有的:

def sendAndReceive(self, content):
  logger.info('Sending {0}'.format(content))
  self.ser.write(content + '\r')
  self.ser.flush();
  response = self.ser.readline() # Currently stops reading on timeout...
  if self.isErr(response):
    logger.error(response)
    return None
  else:
    return response

【问题讨论】:

    标签: python serial-port pyserial


    【解决方案1】:

    我遇到了同样的问题并实现了我自己的 readline() 函数,我从 pyserial 包中的 serialutil.py 文件中复制和修改了该函数。

    串行连接是该函数所属类的一部分,并保存在属性“self.ser”中

    def _readline(self):
        eol = b'\r'
        leneol = len(eol)
        line = bytearray()
        while True:
            c = self.ser.read(1)
            if c:
                line += c
                if line[-leneol:] == eol:
                    break
            else:
                break
        return bytes(line)
    

    与等待超时相比,这是一种更安全、更好、更快的选择。

    编辑: 我在尝试使 io.TextIOWrapper 方法工作时遇到了this 帖子(感谢zmo)。 因此,您可以使用以下方法,而不是使用上面提到的自定义 readline 函数:

    self.ser = serial.Serial(port=self.port,
                             baudrate=9600,
                             bytesize=serial.EIGHTBITS,
                             parity=serial.PARITY_NONE,
                             stopbits=serial.STOPBITS_ONE,
                             timeout=1)
    self.ser_io = io.TextIOWrapper(io.BufferedRWPair(self.ser, self.ser, 1),  
                                   newline = '\r',
                                   line_buffering = True)
    self.ser_io.write("ID\r")
    self_id = self.ser_io.readline()
    

    确保将参数1 传递给BufferedRWPair,否则它不会在每个字节后将数据传递给TextIOWrapper,从而导致串行连接再次超时。

    line_buffering 设置为True 时,您不再需要在每次写入后调用flush 函数(如果写入以换行符终止)。

    编辑: TextIOWrapper 方法实际上适用于 small 命令字符串,但它的行为是未定义的,并且在传输超过几个字节时可能导致errors。最安全的做法是实现您自己的readline 版本。

    【讨论】:

      【解决方案2】:

      来自 pyserial 3.2.1(默认来自 debian Stretch)read_until 可用。如果您想将墨盒从默认 ('\n') 更改为 '\r',只需执行以下操作:

      import serial
      ser=serial.Serial('COM5',9600)
      ser.write(b'command\r')  # sending command
      ser.read_until(b'\r')   # read until '\r' appears
      

      b'\r' 可以更改为您将用作回车符的任何内容。

      【讨论】:

      • 这是一个简短的最佳答案。 Y=我使用 serial_for_url('socket://.... 使用 '\r\n' 作为 EOL 进行了测试,它可以工作。谢谢张
      • 由于某种原因 ser.read_until('\r') 对我不起作用。但是 ser.read_until(serial.serialutil.CR) 确实有效。
      • 这是最好的答案。 @Onderbetaald 您需要将其指定为字节: b'\r'
      • 唯一适合我的答案。花了一些时间弄清楚发生了什么。 b'\r' 在 python3 上绝对是必须的。自己想通了,然后发现@rdh 也报告了这一点。
      • btw @Onderbetaald 建议的 CR 定义为 CR = to_bytes([13])b'\r' 完全相同
      【解决方案3】:

      来自 pyserial 的 documentation:

      (原文如此)

      注意:

      当 pySerial 在模块 io 可用的较新 Python 版本 (V2.6+) 上运行时,不再支持 readline()eol 参数。 停产

      要为readline() 指定EOL 字符或使用通用换行模式,建议使用io.TextIOWrapper

      import serial
      import io
      ser = serial.serial_for_url('loop://', timeout=1)
      sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))
      
      sio.write(unicode("hello\n"))
      sio.flush() # it is buffering. required to get the data out *now*
      hello = sio.readline()
      print hello == unicode("hello\n")
      

      【讨论】:

      • io 模块文档说:Warning: BufferedRWPair does not attempt to synchronize accesses to its underlying raw streams. You should not pass it the same object as reader and writer; use BufferedRandom instead. 所以我不确定这是否是一个完全犹太洁食的解决方案。虽然有效!
      【解决方案4】:

      从端口3读取10条数据,板速38400,传入数据时用\n字符分隔

      import serial as self
      ser=self.Serial("COM3", 38400)  
      buffer = []
      count = 0.0
      c = "\0"
      while count < 10:
          c = "\0"
          if ser.inWaiting():
              while True:
                  val = ser.read(1)
                  if "\n" in val:
                      break
                  else:
                      c += val
              buffer.append(c) # stores all data received into a list   
              count += 1
      print buffer
      

      【讨论】:

        【解决方案5】:

        似乎发生超时是因为readline() 等待来自串行设备的'\n' 字符,它从不发送。

        根据pyserial documentation,可以指定行尾字符:

        response = self.ser.readline(eol='\r')
        

        这行得通吗?

        【讨论】:

        • 该函数的签名已在 2.6 中更改。我在上面已经说明了这一点。 readline(size=None, eol='\n') 改为 readline(size=None)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多