Python serial (pySerial) Чтение строк с помощью EOL \r вместо \n

Я общаюсь с синхронным усилителем SR830 через кабель RS232. При чтении данных, как в следующем коде:

import serial

def main():
    ser = serial.Serial(
        port='COM6',
        baudrate=19200,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS)
    ser.timeout=1
    ser.write("OUTP? 1 \r\n".encode()) #Asks the Lock-in for x-value
    ser.write("++read\r\n".encode())
    x=ser.readline()
    print (x)
if __name__ == '__main__': main()

Я получаю строку байтов, например b'-3.7486e-008\r'. Однако функция ser.readline() не распознает \r как EOL. Поэтому мне приходится ждать тайм-аута каждый раз, когда я считываю данные, что будет проблематично, так как я хочу набрать как можно больше точек как можно быстрее. И длина числа сильно меняется, поэтому я не могу просто использовать, например, ser.read(12). Я пытался использовать io.TextIOWrapper, но мне не ясно, как это реализовать. Вот моя попытка:

import serial
import io
def main():
    ser = serial.Serial(
        port='COM6',
        baudrate=19200,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS)
    ser.timeout=1
    sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))
    sio.write("OUTP? 1 \r\n") #Asks the Lock-in for x-value
    sio.write("++read\r\n")
    x=sio.readline()
    print (x)
if __name__ == '__main__': main()

Который просто печатает пустое место. Любая помощь будет высоко оценена, спасибо.

РЕДАКТИРОВАТЬ: вот мой рабочий код после ответов, используя цикл:

import serial
def main():
    ser = serial.Serial(
        port='COM6',
        baudrate=19200,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS)
    ser.timeout=5
    ser.write("OUTP? 1 \r\n".encode()) #Asks the Lock-in for x-value
    ser.write("++read\r\n".encode())
    buffer = ""
    while True:
        oneByte = ser.read(1)
        if oneByte == b"\r":    #method should returns bytes
            print (buffer)
            break
        else:
            buffer += oneByte.decode()
if __name__ == '__main__': main()

person Calum Beck    schedule 20.07.2017    source источник
comment
Возможный дубликат pySerial 2.6: укажите конец строки в строке чтения ()   -  person SiHa    schedule 20.07.2017
comment
Вам нужно как минимум newline='\r' в этом TextIOWrapper, иначе он будет искать \n тоже.   -  person Eric    schedule 20.07.2017


Ответы (3)


Как насчет использования простого цикла для чтения?

def readData():
    buffer = ""
    while True:
        oneByte = ser.read(1)
        if oneByte == b"\r":    #method should returns bytes
            return buffer
        else:
            buffer += oneByte.decode("ascii")

Вы можете проверить файл serialutil.py из пакета Pyserial. Они используют тот же способ для достижения метода read_until.

person Erik Šťastný    schedule 20.07.2017
comment
Я бы не рекомендовал это в качестве общего решения из-за ужасной производительности, но теперь, когда мы говорим о низкоскоростных последовательных интерфейсах, это, вероятно, сработает. - person juhist; 20.07.2017
comment
Вы имеете в виду \r, а не \n. - person Błotosmętek; 20.07.2017
comment
@juhist Я использую этот метод для связи с мультиметром и т. Д. Через RS232, где ответы длиннее 100 мс, и в этом случае это абсолютно не влияет на производительность. - person Erik Šťastný; 20.07.2017
comment
AttributeError: объект 'str' не имеет атрибута 'append' - person juhist; 20.07.2017
comment
@juhist снова исправил. - person Erik Šťastný; 20.07.2017
comment
Да, я добавил += и .decode(), и это сработало! Я просто проверю другие ответы, чтобы увидеть, какой из них самый быстрый. Большое спасибо, Эрик. - person Calum Beck; 20.07.2017
comment
@Calum Beck Я обновил ответ, pyserial использует тот же подход для метода read_until. - person Erik Šťastný; 20.07.2017
comment
Я также добавил функцию прерывания - person Calum Beck; 20.07.2017

Из документов для readline():

Ограничитель строки всегда b'\n' для двоичных файлов; для текстовых файлов аргумент newline для open() можно использовать для выбора распознаваемых разделителей строк.

Конечно, здесь нельзя использовать open. Но что вы можете сделать, так это использовать io.TextIOWrapper для преобразования потока байтов в текстовый поток:

ser_text = io.TextIOWrapper(ser, newline='\r')
ser_text.readline()
person Eric    schedule 20.07.2017
comment
BufferedRWPair нужен? - person Eric; 20.07.2017
comment
Хм, на самом деле, только что понял, что даже с этим кодом он все еще ждет тайм-аута. Я просто буду придерживаться петли. Я вижу, что происходит таким образом. - person Calum Beck; 20.07.2017
comment
Почему бы тогда не установить тайм-аут на 0? - person Eric; 20.07.2017
comment
Продолжайте получать ошибку AttributeError: 'Serial' object has no attribute 'read1'... - person spitz; 22.04.2019
comment
@spitz: я бы отправил запрос об ошибке / функции против pyserial для этого - person Eric; 22.04.2019

Вместо этого используйте read_until():

ser.read_until(b'\r')

Будьте осторожны, не забудьте b. В противном случае, даже если она прочитает '\r', функция не вернется, пока не будет достигнуто время ожидания, установленное на порту.

person Girl Spider    schedule 10.10.2019