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
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.
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