3

我有一个简单的程序来测试串行功能。我的串行设备对两个输入做出反应。如果用户输入“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
4

2 回答 2

6

有两个不错的解决方案。对于任何一个,您都需要像 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
    )

解决方案一:简单有效

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

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

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

解决方案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,则认为传输完成。

即使您收到大量数据或接收速度非常慢,此解决方案也将始终有效。

于 2017-12-03T01:49:16.910 回答
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()
于 2013-10-24T21:04:54.750 回答