I have an Arduino connected to my computer running a loop, sending a value over the serial port back to the computer every 100 ms.
I want to make a Python scr
Slight modification to mtasic & Vinay Sajip's code:
While I found this code quite helpful to me for a similar application, I needed all the lines coming back from a serial device that would send information periodically.
I opted to pop the first element off the top, record it, and then rejoin the remaining elements as the new buffer and continue from there.
I realize that this is not what Greg was asking for, but I thought it was worth sharing as a side note.
def receiving(ser):
global last_received
buffer = ''
while True:
buffer = buffer + ser.read(ser.inWaiting())
if '\n' in buffer:
lines = buffer.split('\n')
last_received = lines.pop(0)
buffer = '\n'.join(lines)
from serial import *
from threading import Thread
last_received = ''
def receiving(ser):
global last_received
buffer = ''
while True:
# last_received = ser.readline()
buffer += ser.read(ser.inWaiting())
if '\n' in buffer:
last_received, buffer = buffer.split('\n')[-2:]
if __name__ == '__main__':
ser = Serial(
port=None,
baudrate=9600,
bytesize=EIGHTBITS,
parity=PARITY_NONE,
stopbits=STOPBITS_ONE,
timeout=0.1,
xonxoff=0,
rtscts=0,
interCharTimeout=None
)
Thread(target=receiving, args=(ser,)).start()
You can use ser.flushInput()
to flush out all serial data that is currently in the buffer.
After clearing out the old data, you can user ser.readline() to get the most recent data from the serial device.
I think its a bit simpler than the other proposed solutions on here. Worked for me, hope it's suitable for you.
You will need a loop to read everything sent, with the last call to readline() blocking until the timeout. So:
def readLastLine(ser):
last_data=''
while True:
data=ser.readline()
if data!='':
last_data=data
else:
return last_data
Here's an example using a wrapper that allows you to read the most recent line without 100% CPU
class ReadLine:
"""
pyserial object wrapper for reading line
source: https://github.com/pyserial/pyserial/issues/216
"""
def __init__(self, s):
self.buf = bytearray()
self.s = s
def readline(self):
i = self.buf.find(b"\n")
if i >= 0:
r = self.buf[:i + 1]
self.buf = self.buf[i + 1:]
return r
while True:
i = max(1, min(2048, self.s.in_waiting))
data = self.s.read(i)
i = data.find(b"\n")
if i >= 0:
r = self.buf + data[:i + 1]
self.buf[0:] = data[i + 1:]
return r
else:
self.buf.extend(data)
s = serial.Serial('/dev/ttyS0')
device = ReadLine(s)
while True:
print(device.readline())
These solutions will hog the CPU while waiting for characters.
You should do at least one blocking call to read(1)
while True:
if '\n' in buffer:
pass # skip if a line already in buffer
else:
buffer += ser.read(1) # this will block until one more char or timeout
buffer += ser.read(ser.inWaiting()) # get remaining buffered chars
...and do the split thing as before.