Trouble Making a Variable for Delay Time

Hello, I'm looking to see if I can get any help or guidance on where I'm going wrong in my code. I'm trying to create a variable for the delay time to blink an LED but I'm not having much luck.

Here is my code so far:

// Much of the code is from Robin2's receiving several characters with start and end markers...

const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
int blink_delay;



void setup() {
  Serial.begin(9600);
  pinMode(8, OUTPUT);
}



void loop() 
{
  recvWithStartEndMarkers();
  showNewData();

  if (Serial.available())
  {
    blink_delay = Serial.read();
    digitalWrite(8, HIGH);
    delay(blink_delay);
    digitalWrite(8, LOW);
    delay(blink_delay);    
  }
}



void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  
  // if (Serial.available() > 0) {
        while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}



void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;
  }
}

Thanks!

What do you mean by "not much luck"? Doesn't compile? Delays too short? Too long?

blink_delay = Serial.read();Why are you ignoring the value that recvWithStartEndMarkers() gives you ? Serial.read() will give you a single byte at most.

It complies and flashes okay, but when I enter <1000> into the serial monitor (with 'no line editing' and '9600' baud), I'll get a single quick flash of the LED and then nothing. Each time I enter that value, the serial monitor will output...

This just in ... 100
This just in ... 100

or

This just in ... 000
This just in ... 000

Sometimes the serial monitor won't output anything.

UKHeliBob:

blink_delay = Serial.read();

Why are you ignoring the value that recvWithStartEndMarkers() gives you ? Serial.read() will give you a single byte at most.

Sorry, I don't understand.

The recvWithStartEndMarkers() function collects characters in receivedChars, and sets the newData flag to true, when the end of record marker (>) arrives.

 recvWithStartEndMarkers();

should be followed by:

 if(newData)
  {
     // Do something with it...
  }

Inside the block, you could call atoi(receivedChars), and assign the result to blink_delay, and actually blink the LED.

Sorry, I don't understand.

Look at how the program is structured
You call recvWithStartEndMarkers() and it puts the input between < and > into the receivedChars array, terminating it with a 0 to turn the array of chars into a C style string. Then you call showNewData() which prints a message and the string from recvWithStartEndMarkers().

Then you do

  if (Serial.available())
  {
    blink_delay = Serial.read();
    digitalWrite(8, HIGH);
    delay(blink_delay);
    digitalWrite(8, LOW);
    delay(blink_delay);    
  }

Which totally ignores the string in the receivedChars array. What you need to do is to use the receivedChars array and turn it into an integer using the atoi() function and use that as the parameter for your delay()s

At its crudest try (untested)

  if(newData)
  {
    blink_delay = atoi(receivedChars);
    digitalWrite(8, HIGH);
    delay(blink_delay);
    digitalWrite(8, LOW);
    delay(blink_delay);    
  }
}

after showNewData() in loop()

UKHeliBob:
after showNewData() in loop()

Appreciate all of the info PaulS and UKHeliBob, that solved it.

However, when I open the serial monitor, the variable setup seems to only accept the initial value sent out, anything else I type in for a different value goes ignored. I have to close the serial monitor and reopen it again if I wish to change the delay value again. Is there a way to change it in the code so I can keep the same serial window open and continue to send out different delay values?

You changed your code. We can't guess how you changed it. Post the new code if you want help with it.

Sorry. Here is the code...

I added the suggested changes into the void loop. The only other thing I changed beyond that was to remark out the "showNewData();" as leaving it in only allows the loop and blink to complete once.

// Much of the code is from Robin2's receiving several characters with start and end markers...
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
int blink_delay;


void setup() {
  Serial.begin(9600);
  pinMode(8, OUTPUT);
}



void loop() 
{
  recvWithStartEndMarkers();
  //showNewData();

  if(newData)
  {
    blink_delay = atoi(receivedChars);
    digitalWrite(8, HIGH);
    delay(blink_delay);
    digitalWrite(8, LOW);
    delay(blink_delay);   
  }
}



void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  
  // if (Serial.available() > 0) {
        while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}



void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;
  }  
}

The only other thing I changed beyond that was to remark out the "showNewData();

Which means that the newData variable is never set to false. As a result the code that depends on
        while (Serial.available() > 0 && newData == false) {will never be executed.

Could that be a problem, I wonder ?

That was it!

Here is what was changed to allow it...

while (Serial.available() > 0)

Thank you very much again!

jon5221:
That was it!
Here is what was changed to allow it...

while (Serial.available() > 0)

Thank you very much again!

That does not make any sense to me. That is the standard code.

As @UKHeliBob said the key thing is to set newData = false when you want to receive more data.

...R

Robin2:
That does not make any sense to me. That is the standard code.

As @UKHeliBob said the key thing is to set newData = false when you want to receive more data.

...R

Not sure, when I leave that alone,

while (Serial.available() > 0 && newData == false)

I have the issue of only being able to enter one piece of information into the serial monitor, everything else I entered goes ignored.

When I changed it, to this:

while (Serial.available() > 0)

I can enter different values over and over in the same serial monitor window allowing it to work as I needed it to. But now that you bring it up, it has me a little worried that changing it in the way I have done may have some unintended consequences down the road...

  if(newData)
  {
    blink_delay = atoi(receivedChars);
    digitalWrite(8, HIGH);
    delay(blink_delay);
    digitalWrite(8, LOW);
    delay(blink_delay);

    newData = false; // Add this line. Put the while loop back the way it was
  }

Did that, and back to the same issue where the LED illuminates for the set time and then goes dark, but does not blink -- doesn't appear to be looping.

// Much of the code is from Robin2's receiving several characters with start and end markers...
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
int blink_delay;


void setup() {
  Serial.begin(9600);
  pinMode(8, OUTPUT);
}



void loop()
{
  recvWithStartEndMarkers();
  //showNewData();

  if(newData)
  {
    blink_delay = atoi(receivedChars);
    digitalWrite(8, HIGH);
    delay(blink_delay);
    digitalWrite(8, LOW);
    delay(blink_delay);   

    newData = false; // Added
  }
}



void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
 
  // if (Serial.available() > 0) {
        while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}



void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;
  } 
}

doesn't appear to be looping.

Add some Serial.print() statements in recvWithStartEndMarkers():

    rc = Serial.read();
    Serial.print("I got: ");
    Serial.println(rc);

What does the function print?

jon5221:
Not sure, when I leave that alone,

while (Serial.available() > 0 && newData == false)

I have the issue of only being able to enter one piece of information into the serial monitor, everything else I entered goes ignored.

Then you have not understood how the code is intended to work.

The idea is

  • if the newData variable is false
  • it ignores incoming bytes until it sees the start marker.
  • it collects and saves incoming bytes to the receivedChars[] array until it sees the end marker.
  • it sets the variable newData to true so you know the data has all arrived.
  • it does NOT check any more incoming data until your code has set the variable newData back to false

The reason your code has to set the variable back to false is to give it time to use the recieved data, or to move it somehwere safe before the receivedChars[] array is used for the next data that arrives.

If you deal with the received data as soon as the newData variable becomes true and then set that variable to false it will reliably receive all the data you can send to it.

If you edit the code to remove the check for newData == false you completely negate the whole purpose of the code.

...R