How to clear out or flush the arduino serial buffer

Hi,

Scott here from Salem. My program goal. Press 1 on the key board and an led lights up on the arduino. Press 2 and it goes off. Press anything else and the command port prints out “invalid”. I then want to clear the serial port to erase anything else, because if I press a bunch of numbers e.g. 3456, it prints out invalid several times. I would like it to print out invalid only once. I read that Serial.flush() no longer works. I have tried byte = discard Serial.read() but this does not work. Can someone help me with how to flush the serial port of the remaining data?

Here is the code;

  int val = 0;
int led = 13;
void setup()
{
  Serial.begin(9600);
  pinMode(led,OUTPUT);
}

void loop()

{
  while(Serial.available()== 0);  //stays on this line until something's in the buffer
  val = Serial.read() - 48;  // gives me the correct ascii output character
  
  Serial.println(val);
  
  if(val == 1)
  {
    digitalWrite(led,HIGH);
    
  }
    else if (val == 2)
    {
      digitalWrite(led,LOW);
    } 
      else
      {
        Serial.println("invalid");
        
        for (int i = 0; i < 18; i++)  // This is where I want to flush any remaing data
        byte discard = Serial.read();
      }
      
}

thank you,

Scott

This seems like the wrong approach to solving your problem. You know when you see the second invalid input, why print out the unwanted message in the first place?

Hi Philba,

Thanks for responding. I was trying to follow Jeremy Blum’s tutorial on utube and he used serial.flush to erase the buffer. Perhaps I may need this on some future project. Since serial.flush is not longer used to erase the buffer. Is there another way to erase what’s in the buffer?

Thanks,

Scott

For input, you could just read (and ignore) it until it’s empty. For output, maybe .begin() flushes.

void serial_flush_buffer()
{
  while (Serial.read() >= 0)
   ; // do nothing
}

Note that this doesn’t flush “characters in transit.” If you send “3456” at 9600bps, the 5 will arrive avour 1ms after the 4, and won’t get flushed if you call the function immediately after receiving the 4. (however, this is the way the old flush function worked as well.)

westfw:

void serial_flush_buffer()

{
while (Serial.read() >= 0)
; // do nothing
}



Note that this doesn't flush "characters in transit." If you send "3456" at 9600bps, the 5 will arrive avour 1ms after the 4, and won't get flushed if you call the function immediately after receiving the 4. (however, this is the way the old flush function worked as well.)

What if your serial input is coming faster than you can read? Point being, you are going to waste precious processing time ‘flushing’ the serial buffer by performing a read for each piece of data in the buffer (when all you want to do is reset your buffer index to 0 so serial.available() returns 0). I just realized that they completely changed the serial.flush() function…which was probably a bad idea since ‘flush’ means to empty! Now flush ‘waits’ for transmitting data to complete.

I’m looking into the original flush() operation, will post a fix comparable to the original function (if I can come up with one)

For anyone curious about the serial.flush() code change…

New (Arduino 1.0+ Serial.Flush())

void HardwareSerial::flush()
{
  while (_tx_buffer->head != _tx_buffer->tail)
    ;
}

Old (Arduino 23- Serial.Flush())

void HardwareSerial::flush()
{
  _rx_buffer->head = _rx_buffer->tail;
}

What I did to return this function to my current Arduino version, was add a new function to HardwareSerial.h.

virtual void flushRX(void);

Then, add the above (old) flush() function to HardwareSerial.cpp (but name it flushRX). Worked like a charm.

void HardwareSerial::flushRX()
{
  _rx_buffer->head = _rx_buffer->tail;
}

I did not realize they changed the function, and have been debugging code that USED to work… and suddenly stopped working.

Good Luck!

I did as advised, but there was an error:

C:\Program Files\Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.cpp:192:35: error: request for member ‘tail’ in ‘(unsigned char)(&((HardwareSerial*)this)->HardwareSerial::_rx_buffer)’, which is of non-class type ‘unsigned char’

_rx_buffer->head = _rx_buffer->tail;

^

exit status 1

I added a line in HardwareSerial.cpp:

void HardwareSerial::flushRX()

{

_rx_buffer->head = _rx_buffer->tail;

}

void HardwareSerial::flush()

{

// If we have never written a byte, no need to flush. This special

// case is needed since there is no way to force the TXC (transmit

// complete) bit to 1 during initialization

if (!_written)

return;

while (bit_is_set(_ucsrb, UDRIE0) || bit_is_clear(_ucsra, TXC0)) {

if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))

// Interrupts are globally disabled, but the DR empty

// interrupt should be enabled, so poll the DR empty flag to

// prevent deadlock

if (bit_is_set(*_ucsra, UDRE0))

_tx_udr_empty_irq();

}

I added a line in HardwareSerial.h:

public:

inline HardwareSerial(

volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,

volatile uint8_t *ucsra, volatile uint8_t *ucsrb,

volatile uint8_t *ucsrc, volatile uint8_t *udr);

void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }

void begin(unsigned long, uint8_t);

void end();

void flushRX(void);

virtual int available(void);

virtual int peek(void);

virtual int read(void);

int availableForWrite(void);

virtual void flush(void);

virtual size_t write(uint8_t);

inline size_t write(unsigned long n) { return write((uint8_t)n); }

inline size_t write(long n) { return write((uint8_t)n); }

inline size_t write(unsigned int n) { return write((uint8_t)n); }

inline size_t write(int n) { return write((uint8_t)n); }

using Print::write; // pull in write(str) and write(buf, size) from Print

operator bool() { return true; }

// Interrupt handlers - Not intended to be called externally

inline void _rx_complete_irq(void);

void _tx_udr_empty_irq(void);

};

Please help me to understand whats wrong?

I got the same error and fixed by changing following code

void HardwareSerial::flushRX()
{
_rx_buffer->head = _rx_buffer->tail;
}

with

void HardwareSerial::flushRX()
{
  _rx_buffer_head = _rx_buffer_tail;
}

But the problem is that even if this is not returning any errors, the Serial input is not getting flushed. :expressionless: