-->

Reading a Serial Port - Ignore portion of data wri

2020-07-24 03:38发布

问题:

I would like to read data coming and Arduino on a serial port on intervals. So essentially something like

  1. Take a reading
  2. Wait
  3. Take a reading
  4. Wait
  5. Take ...

etc.

The problem I am facing is that the port will buffer its information so as soon as I call a wait function the data on the serial port will start buffering. Once the wait function finishes I try and read the data again but I am reading from the beginning of the buffer and the data is not current anymore, but instead is the reading taken at roughly the time the wait function began.

My question is whether there is a way that I am unaware of to ignore the portion of data read in during that wait period and only read what is currently being delivered on the serial port?

I have this something analogous to this so far:

import serial

s = serial.Serial(path_to_my_serial_port,9600)

while True:
    print s.readline()
    time.sleep(.5)

For explanation purposes I have the Arduino outputting the time since it began its loop. By the python code, the time of each call should be a half second apart. By the serial output the time is incrementing in less than a millisecond. These values do not change regardless of the sleep timing.

Sample output:

504

504

504

504

505

505

505

...

As an idea of my end goal, I would like to measure the value of the port, wait a time delay, see what the value is then, wait again, see what the value is then, wait again.

I am currently using Python for this but am open to other languages.

回答1:

If you want to get rid of what may be in the input buffer before you perform your next read, you can flush your input buffer with s.flushInput() (you could also check the bytes in your input buffer with s.inWaiting()).

So, adding the flush call will make sure that you read whatever bytes arrive from that moment:

while True:
    s.flushInput()
    print s.readline()
    time.sleep(.5)

You may also want to consider using a read timeout (when you create your serial.Serial object as, with timeout parameter). In this case you would need to deal with empty readings when there is a timeout, but you would guarantee that if the sender stops for any reason, your reader will not be waiting forever.



回答2:

What you are trying to do is quite possible. However, you need to consider (and address) all sorts of race conditions. The Arduino might start/finish sending data while the Python code is sleeping. That's probably exactly what you hope for. However, the Arduino might also start to send data while the Python code is running. All sorts of overlap conditions might occur.

In my opinion, readline() isn't as helpful as you might think. Of course, readline() will return a line. However, it might only return the last part of a line. The first part (depending on timing) might get flushed.

My suggestion is to make the the data stream (of bytes) coming from the Arduino self-documenting. In other words, something like <value>, where value is the data you actually want from the Arduino.

The Python code might be something like

while True:  
#
# Loop reading for a '<' character. Skip everything until you get a '<'. 
#
  while True:  
    if s.inWaiting() > 0:  
      c = s.read()  
      if c == '<':  
        break  
#
# Read the actual data value. Stop when we get to a '>'. 
#
  value = ''
  while True:
    if s.inWaiting() > 0:
      c = s.read()
      if c == '>':
        break
      value = value + c
#
# We now have the value we actually care about. However, there might
# be more data in the buffer. If the buffer is now empty we are done.
# If the buffer is not empty, then we need to start over.
#
  if s.inWaiting() == 0:
    break

The general idea should be clear. Read complete complete values from the input stream until the input stream is empty. If you happen to start reading when the input stream contains an incomplete value, the Python code will automatically resync.

Let me apologize for any and all Python coding errors. My Python is rusty.