pySerial inWaiting返回不正确的字节数

时间:2013-10-03 14:22:41

标签: python pyserial

我有一个简单的程序来测试串行功能。我的串行设备对两个输入作出反应。如果用户输入“a”,则以“fg”响应。如果用户输入任何其他字符/字节,则以“z”响应。如果我将'b'发送到串行设备,它将返回'z'就好了。当我发送'a'时,它应该返回'f'和'g',所以两个字节而不是一个。

见下面的代码。

#!/usr/bin/env python

import serial

ser = serial.Serial(
    port = '/dev/ttyUSB0',
    baudrate = 9600,
    parity = serial.PARITY_NONE,
    stopbits = serial.STOPBITS_ONE,
    bytesize = serial.EIGHTBITS
    )

ser.write('a')
byteData = ser.read(1) # read one, blocking
moreBytes = ser.inWaiting()

if moreBytes:
    byteData = byteData + ser.read(moreBytes)
    print byteData

print byteData


ser.close()

输出结果为:

user@ubuntu:~/code/native$ ./serialTesting.py 
f

inWaiting()给出值0,因此它永远不会读取第二个字节。如果我对代码做了一些小改动,并手动读取了两个预期的字节,那么它可以正常工作。

#!/usr/bin/env python

import serial

ser = serial.Serial(
    port = '/dev/ttyUSB0',
    baudrate = 9600,
    parity = serial.PARITY_NONE,
    stopbits = serial.STOPBITS_ONE,
    bytesize = serial.EIGHTBITS
    )

ser.write('a')
byteData = ser.read(2) # read two expected bytes for the result 'fg'

print byteData

ser.close()

输出符合预期:

user@ubuntu:~/code/native$ ./serialTesting.py 
fg

2 个答案:

答案 0 :(得分:3)

这有两个不错的解决方案。对于其中任何一个,你需要设置一个像jramirez已建议的超时:

ser = serial.Serial(
    port = '/dev/ttyUSB0',
    baudrate = 9600,
    parity = serial.PARITY_NONE,
    stopbits = serial.STOPBITS_ONE,
    bytesize = serial.EIGHTBITS,
    timeout=0.5, # IMPORTANT, can be lower or higher
    inter_byte_timeout=0.1 # Alternative
    )

解决方案1:简单有效

byteData = ser.read(size=800) #Set size to something high

这将读取最多800个字节,并且不会超过您设置的timeout。如果您改为设置inter_byte_timeoutread()将等待每个字节的时间。

这是一个快速解决方案,适用于您只收到已知最大大小的数据块的情况。

解决方案2:正确的方法

def read_all(port, chunk_size=200):
    """Read all characters on the serial port and return them."""
    if not port.timeout:
        raise TypeError('Port needs to have a timeout set!')

    read_buffer = b''

    while True:
        # Read in chunks. Each chunk will wait as long as specified by
        # timeout. Increase chunk_size to fail quicker
        byte_chunk = port.read(size=chunk_size)
        read_buffer += byte_chunk
        if not len(byte_chunk) == chunk_size:
            break

    return read_buffer

上面的代码段在CC0 1.0下获得许可。

然后,阅读:

byteData = read_all(ser)

基本上,这将以块的形式读取您的数据并每次等待以查看是否出现新字符。如果在timeout设置的时间内读取的字符较少,则认为传输已完成。

此解决方案始终有效,即使您收到大量数据或收到的数据非常缓慢。

答案 1 :(得分:1)

可能是因为波特率非常慢。在第二个字节到达缓冲区之前,您正在处理inwaiting()调用。当你执行ser.read(2)时,它会等待(阻塞),直到收到2个字节为止它的工作原理。尝试设置超时1秒,这应该可以解决您的问题。

ser = serial.Serial(
    port = '/dev/ttyUSB0',
    baudrate = 9600,
    parity = serial.PARITY_NONE,
    stopbits = serial.STOPBITS_ONE,
    bytesize = serial.EIGHTBITS,
    timeout=1 # add this
    )
ser.write('a')
byteData = ser.read(1) # read one, blocking
byteData += ser.read(ser.inWaiting())

print byteData

ser.close()