1
votes

I have made this code on Arduino where the objective is to have the user type in a delay time into the serial monitor, and then the LED should be blink with that delay time. For example if I type in 1000 the LED should be turned on for 1 second then off for 1 second, then repeat.

My problem is that when the code has finished running once, it waits for a new user input, instead of continuing to blink. I think i have to take the Serial.parseInt out of the loop but i'm not sure how as every time I have tried to put it somewhere else the LED just lights up constantly.

Here is the code:

int ledPin = 13;


void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);

  Serial.print(" Enter delay time: ");
  while (!Serial.available());

}

void loop() {
  // put your main code here, to run repeatedly
  int delayTime = Serial.parseInt();
  digitalWrite(ledPin, HIGH);
  delay(delayTime);
  digitalWrite(ledPin, LOW);
  delay(delayTime);

}
3

3 Answers

2
votes

Serial.parseInt is a blocking function. That means it waits for valid serial input until it times out. Because of this, any other action in loop has to wait too. Reading user input in setup works only once though, so it never asks the user for input again.

To avoid this, you'll have to check the serial buffer, and then read each byte individually, while also doing the LED blinking in the main loop.

Another thing to avoid now, is the use of the delay function, because it also hangs the entire main loop (including the serial readings) for the given parameter time. You can still blink the LED by using timestamp intervals.

For a nice example of a non-blocking serial read, we can use this sample from the Arduino docs. Additionally, for another nice example of an LED-blinking sketch without using delay, we can use the BlinkWithoutDelay sample from the Arduino docs too.

String inString = "";
unsigned long previousMillis = 0;
int delayTime = 0;
int ledState = LOW;
int ledPin = 13;

void nonBlockingSerialReadDelayTime() {
  while (Serial.available() > 0) {
    int inChar = Serial.read();
    if (isDigit(inChar)) {
      // convert the incoming byte to a char and add it to the string
      inString += (char)inChar;
    }
    // if you get a newline (user pressed ENTER on the serial console)
    if (inChar == '\n') {
      // set our new delay time
      delayTime = inString.toInt();

      // clear the string for new input
      inString = "";

      // ask user again
      Serial.print(" Enter delay time: ");
    }
  }
}

void blinkLED() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= delayTime) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // 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(ledPin, ledState);
  }
}

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  while (!Serial.available());
  Serial.print(" Enter delay time: ");
}

void loop() {
  nonBlockingSerialReadDelayTime();
  blinkLED();
}
0
votes

Simply read the delay time in your setup befor you enter loop

int ledPin = 13;
int delayTime = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);

  Serial.print(" Enter delay time: ");
  while (!Serial.available());
  delayTime = Serial.parseInt();

}

void loop() {
  // put your main code here, to run repeatedly

  digitalWrite(ledPin, HIGH);
  delay(delayTime);
  digitalWrite(ledPin, LOW);
  delay(delayTime);

}
0
votes

Sure Serial.parseInt() is blocking, but you can combine it with Serial.available()

const int ledPin = 13;
int delayTime = 1000;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.print(" Enter delay time: ");
}

void loop() {
  digitalWrite(ledPin, HIGH);
  delay(delayTime);
  digitalWrite(ledPin, LOW);
  delay(delayTime);

  if (Serial.available()) { 
     int temp = Serial.parseInt();
     if (temp  > 0) delayTime = temp;
     Serial.print(" Enter delay time: ");
  }  
}

Of course this approach does not allow to break into a very slow blink cycle immediately, but that's a different issue.