Example: SerialBlinkWithoutDelay

So here is an example I wanted to make sure was posted: It’s a version of BlinkWithoutDelay that also services the serial port. Just another example of how to handle the serial port while you do other things.

// Constants 
const byte MAX_STRING_LEN = 40;
const byte LED_PIN        = 13;
const int  BLINK_INTERVAL = 1000;

// Variables
char inputString[MAX_STRING_LEN];  // a string to hold incoming data
unsigned long previousMillis = 0;  // Last time we blinked
byte ledState = LOW;               // Current state of LED (HIGH=On)
byte strLen   = 0;                 // current length of rec'd string

void setup() {
  Serial.begin(19200);             // Change baud rate to suit
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  // Check the serial port for any pending data
  if (processSerial()) {
    // Received a complete string. For now, just echo it back
    Serial.println(inputString);

    // Finally setup for the next string
    inputString[0] = '\0';         // Make sure array is empty
    strLen         = 0;            // reset length to zero
  }   

  // Here is where you do the processing that needs to be done each
  // pass thru the loop (such as checking to see if it's time to blink)
  if(millis() - previousMillis > BLINK_INTERVAL) {
    // save the last time you blinked the LED 
    previousMillis = millis();   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable
    digitalWrite(LED_PIN, ledState);
  }  
}

// Check the Serial port and gather any pending data
boolean processSerial() {
  while (Serial.available()) {
    char inChar = (char)Serial.read(); 

    // We are done receiving the string if we received a return (or line feed)
    if ((inChar == '\n') || (inChar == '\r')) {
      return true;
    }

    // add it to the inputString if we have room
    if (strLen < (MAX_STRING_LEN - 1)) {
      inputString[strLen++] = inChar;
      inputString[strLen]   = '\0';
    }
  }

  return false;
}

You might get out of sync with the time, since you use millis() twice.

Peter_n:
You might get out of sync with the time, since you use millis() twice.

Possibly, yes, but won’t that take quite a long time? If the application is that time sensitive perhaps the example should be more like this?

// Constants 
const byte MAX_STRING_LEN = 40;
const byte LED_PIN        = 13;
const int  BLINK_INTERVAL = 1000;

// Variables
char inputString[MAX_STRING_LEN];  // a string to hold incoming data
unsigned long previousMillis = 0;  // Last time we blinked
byte ledState = LOW;               // Current state of LED (HIGH=On)
byte strLen   = 0;                 // current length of rec'd string

void setup() {
  Serial.begin(19200);             // Change baud rate to suit
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  // Check the serial port for any pending data
  if (processSerial()) {
    // Received a complete string. For now, just echo it back
    Serial.println(inputString);

    // Finally setup for the next string
    inputString[0] = '\0';         // Make sure array is empty
    strLen         = 0;            // reset length to zero
  }   

  // Here is where you do the processing that needs to be done each
  // pass thru the loop (such as checking to see if it's time to blink)
  unsigned long now = millis();
  if(now - previousMillis > BLINK_INTERVAL) {
    // save the last time you blinked the LED 
    previousMillis = now;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable
    digitalWrite(LED_PIN, ledState);
  }  
}

// Check the Serial port and gather any pending data
boolean processSerial() {
  while (Serial.available()) {
    char inChar = (char)Serial.read(); 

    // We are done receiving the string if we received a return (or line feed)
    if ((inChar == '\n') || (inChar == '\r')) {
      return true;
    }

    // add it to the inputString if we have room
    if (strLen < (MAX_STRING_LEN - 1)) {
      inputString[strLen++] = inChar;
      inputString[strLen]   = '\0';
    }
  }

  return false;
}
  while (Serial.available())

Won’t this effectively act as blocking code, albeit for a very short time ? Whatever you are timing with millis() will have to wait until all available serial data has been processed. Might it not be better to read just one character from serial before returning to loop() so that the millis() timing can do its stuff between serial characters ?

Also, there is an argument for implementing the millis() timing differently. Instead of    previousMillis = now;  use    previousMillis = previousMillis + BLINK_INTERVAL;  This ensures that reacting to the interval ending remains constant even if time consuming events have occurred in the meantime.

UKHeliBob:   while (Serial.available())

Won't this effectively act as blocking code, albeit for a very short time ?

"Any" code is blocking while it runs. So it depends on how much "parsing" you do with the serial characters. Just stuffing them into a different buffer is not much fun, as they already lie in a buffer and memory is short enough as it is. (You can turn any parsing algorithm into a step wise parsing with a little state engine, so you do not need to have - f.ex - all digits of a number in a buffer before turing it into an int. Besides, if you do poll this code often enough, which you have to keep the LED blinking regularly, there will never accumulate more than one or maybe two characters in the Serial buffer.

And a note to the original poster Brad Burleson: Thanks for posting it. Whether the minor "tweaks" are needed or not, it is still good example for the number of programmers-to-be that struggle with the concept of writing non-blocking code, or have difficulty to come beyond the supplied example BlinkWithOutDelay sketch. Lets hope that enough persons find it with search.

Its great to see people providing demo code.

Might I suggest that you refactor the code so that loop() looks like this

void loop() {
   getSerialData();
   doOtherStuff();
}

This will make it easy for other users to amalgamate it with their own code as there is nothing specific to your system in loop() - apart from the call to get the serial data.

...R