问题
I've got a simple program to test serial functionality. My serial device reacts to two inputs. If the user enters 'a', it responds with 'fg'. If the user enters anything other character/byte, it responds with 'z'. If I send 'b' to the serial device, it will return 'z' just fine. When I send 'a', it should return both 'f' and 'g', so two bytes instead of one.
See code below.
#!/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()
The output is :
user@ubuntu:~/code/native$ ./serialTesting.py
f
inWaiting() gives the value of 0, thus it never reads the second byte. If I do a small change to the code, and manually read the two expected bytes, it works fine.
#!/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()
The output is as expected:
user@ubuntu:~/code/native$ ./serialTesting.py
fg
回答1:
There are two decent solutions for this. For either, you'll need to set a timeout like jramirez already suggested:
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
)
Solution 1: Simple and effective
byteData = ser.read(size=800) #Set size to something high
This will read up to 800 bytes and will take no more time than the timeout
you've set. If you've instead set an inter_byte_timeout
, read()
will wait up to that amount of time for each single byte.
This is a quick solution that will work for cases where you only receive a chunk of data of known maximum size.
Solution 2: The proper way
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
The code snippet above is licensed under CC0 1.0.
And then, to read:
byteData = read_all(ser)
Basically, this will read your data in chunks and wait every time to see if new characters appeared. If less characters were read in the time set by timeout
, the transmission is considered finished.
This solution will always work, even when you receive a lot of data or if you receive it very slowly.
回答2:
it could be because the baudrate is really slow. You are processing the inwaiting() call before the second byte gets to the buffer. When you do ser.read(2) it waits(blocks) until 2 bytes have been received thus why it works. Try setting a timeout of 1 second, that should fix your problem.
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()
来源:https://stackoverflow.com/questions/19161768/pyserial-inwaiting-returns-incorrect-number-of-bytes