timer issue after "while"

A variable A is set HIGH in a "while" loop.

Once out of the "while" loop I need to keep A HIGH during a fixed time T.

If I use the millis timer then this "if" loop is run once the first time, and then only again after "previousMillis >= currentMillis".

I am stuck for a solution that sets A low after time T after leaving the "while" loop.

Just a hint will be enough, thank you.

Just a hint will be enough, thank you.

HINT : Post an example program that exhibits the problem

You really should know better after 333 previous posts

By the way, there is no such thing as an if loop

UKHeliBob:
HINT : Post an example program that exhibits the problem

You really should know better after 333 previous posts

By the way, there is no such thing as an if loop

Right :grin:
This is Robin2's example 5 program from his Serial Tutorial that I am modifying to test HC12 modules.
I want to detect single string transmissions (and later also compare current and previous transmitted values).

A digital output has to go HIGH when a Receive is in Progress, and stay lit for say 1 second. Just single transmission bursts take place.

Here is void recWithStartEndMarkers(), I already included the DigitalWrite..

void recvWithStartEndMarkers() {

  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  unsigned long previousMillis = 0; // timer
  const int interval = 2000;
  boolean rxStatus = false;
  boolean ledState = false;
  digitalWrite (12, LOW);
  unsigned long currentMillis = millis();


  while (HC12.available() > 0 && newData == false) {
    rc = HC12.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;
      digitalWrite(12, HIGH);
      previousinteger1FromPC = integer1FromPC;
    }
  }

  if (digitalRead(12) == HIGH) {

  }
}

You did not use the millis() function correctly, but without any code I cannot help.

By the way, there is no such thing as an "if" loop. "if" does not loop. "if" is a statement.

I use the millis() function all of the time. The basic idea is to use millis() to note the time that something happened (like setting A to HIGH) and then checking each time through the loop() function to see if it is time to do something else (like setting A to LOW). All variables having to do with time should be unsigned long (or const unsigned long), the only arithmetic on the unsigned long variables should be subtraction, and the delay(...) function should not be used.

I cannot see how you have used/abused the loop() function so it is hard to help further. Nick Gammon has a web site with handy information on this topic but I do not currently have the URL.

vaj4088:
You did not use the millis() function correctly, but without any code I cannot help.

By the way, there is no such thing as an "if" loop. "if" does not loop. "if" is a statement.

I use the millis() function all of the time. The basic idea is to use millis() to note the time that something happened (like setting A to HIGH) and then checking each time through the loop() function to see if it is time to do something else (like setting A to LOW). All variables having to do with time should be unsigned long (or const unsigned long), the only arithmetic on the unsigned long variables should be subtraction, and the delay(...) function should not be used.

I cannot see how you have used/abused the loop() function so it is hard to help further. Nick Gammon has a web site with handy information on this topic but I do not currently have the URL.

I know the url of Nick Gammon's site; I will look at it more in depth.

The code I used is in my previous post.

I use the millis() as follows, please correct me if wrong:

//..
int interval = 1000; //1 second interval
unsigned long currentMillis = millis();
//..do something A..  

if (currentMillis - previousMillis >= interval) {
//..do something B..  This something B will always be executed the first time, and then only after interval
previousMillis = currentMillis();
}

The result of this code is that B will be exectued as soon as the if statement is reached, and then only again after interval.

My issue is that I need this statement B only executed after interval.

I.e.: a "while" loop is executed during which a digital output is set HIGH. After the while is done, then only after a fixed time does the digital output need to go LOW.

It would really help to see a complete sketch. Then it's much easier to understand the context, see how variables are declared / defined, etc.

gfvalvo:
It would really help to see a complete sketch. Then it's much easier to understand the context, see how variables are declared / defined, etc.

I am sorry, I misunderstood UKHeliBob too who asked the same; I thought it would be easier to read anything besides the actual void was not included.

Meanwhile I did write a millis() delay code for the digital output delayed off starting line 110. But it is not right.

// http://forum.arduino.cc/index.php?topic=499210.msg3407044#msg3407044
// http://forum.arduino.cc/index.php?topic=396450.0

// HC12 Communication between Arduinos

/*
  This program serves to send one integer (or byte) only from two different HC12
  transmitters at one sensor each (A and B)to one HC12 receiver at the central
  controller Arduino. The receiving HC12 has to know from which transmitter A or B
  the value comes.
  The data are sent with start- and endmarkers

  v5: two integers used, one for the sensor value (integer1FromPC) and one
  for the sensor identifier (integer2FromPC). At the transmitter the sensor A or B are
  identiefied by reading two digital inputs connected to a dipswitch with
  2 switches (max: 4 different sensor/transmitters).

  // RECEIVER PART
*/

#include <SoftwareSerial.h>
const byte HC12RxdPin = 4;                  // Recieve Pin on HC12
const byte HC12TxdPin = 5;                  // Transmit Pin on HC12
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin); // Create Software Serial Port
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integer1FromPC = 0;
int integer2FromPC = 0;
int previousinteger1FromPC = 0;
int previousinteger2FromPC = 0;
float floatFromPC = 0.0;

boolean newData = false;

//============

void setup()
{
  Serial.begin(9600);
  HC12.begin(9600);       // Open serial port to HC12

  // declare pin 11 & 12 as output
  pinMode (10, OUTPUT);
  pinMode (11, OUTPUT);
  pinMode (12, OUTPUT);
  delay(100);
}

void loop() {
  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    //   because strtok() used in parseData() replaces the commas with \0
    parseData();
    useParsedData();
    newData = false;


  }
}

//============

void recvWithStartEndMarkers() {

  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  unsigned long previousMillis = 0; // timer
  const int interval = 1000;
  boolean rxStatus = false;
  boolean ledState = false;
  digitalWrite (12, LOW);
  unsigned long currentMillis = millis();


  while (HC12.available() > 0 && newData == false) {
    rc = HC12.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;
      digitalWrite(12, HIGH);
      previousMillis = currentMillis;
      previousinteger1FromPC = integer1FromPC;
    }
  }

  if (digitalRead(12) == HIGH) {
    if (currentMillis - previousMillis >= interval) {
      digitalWrite(12, LOW);
      previousMillis = currentMillis;
    }
  }


}


//============

void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index. It creates the variable
  // strkIndx as a pointer to a variable of type char. It can hold the address of a
  // variable of type char.
  /*
    strtokIndx = strtok(tempChars, ",");     // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integer1FromPC = atoi(strtokIndx);     // convert this part to an integer
    /*
        strtokIndx = strtok(NULL, ",");
        floatFromPC = atof(strtokIndx);     // convert this part to a float
  */

  strtokIndx = strtok(tempChars, ",");     // get the first part - the string
  integer1FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC


}
//============

void useParsedData() {
  if (messageFromPC[0] == 'A') analogWrite (10, integer1FromPC);
  if (messageFromPC[0] == 'B') analogWrite (11, integer2FromPC);
}

Try making 'previousMillis' a 'static unsigned long'.

BTW, the are called functions, not 'voids'.

gfvalvo:
Try making 'previousMillis' a 'static unsigned long'.

BTW, the are called functions, not 'voids'.

Hi, I read up on "Static" (https://www.arduino.cc/en/Reference/Static but can you explain why it would be usefull in this case please?

gfvalvo:
Try making 'previousMillis' a 'static unsigned long'.

BTW, the are called functions, not 'voids'.

..changing to

static unsigned long previousMillis; // timer

made the difference!!

As it is now, previousMillis is an automatic variable local to recvWithStartEndMarkers(). Every time that function is entered previousMillis will be reset to 0. You don't want that. You want previousMillis to hold the millis() value from the instant you set output 12 to HIGH. Static will make that happen.

Said another way, static gives you the persistence of a global with the scope of a local.

In the setup() function, you need to initialize previousMillis. For example:

previousMillis = millis() ;

If you only provide snippets of code, then you cannot expect more than snippets of answers. We like to see complete programs including setup and loop. Otherwise, important pieces of information get left out. I see this post as an example because I cannot see how or even if this variable got initialized.

vaj4088:
In the setup() function, you need to initialize previousMillis. For example:

previousMillis = millis() ;

If you only provide snippets of code, then you cannot expect more than snippets of answers. We like to see complete programs including setup and loop. Otherwise, important pieces of information get left out. I see this post as an example because I cannot see how or even if this variable got initialized.

Agreed, but in post #6 you can find the complete code

Sorry, yes, thanks.

gfvalvo:
Said another way, static gives you the persistence of a global with the scope of a local.

So, if I understand correctly, if like in my case I have a program with 2 functions, and if I use a constant variable, then that constant variable does not keep its value?

So, if I understand correctly, if like in my case I have a program with 2 functions, and if I use a constant variable, then that constant variable does not keep its value?

I don't think you do understand correctly. You have variables declared locally within a function recvWithStartEndMarkers(). Without typing them as static, the local variables do not retain their value each time the function is called, but are reinitialized each time. Notice how Robin2 has declared some variables in the function as static.

Here's an examples of blinkWithoutDelay as it is normally shown with global variables, and a version with a function call. See how the previousMillis and ledState variables need to be static in order to keep their last value each time the function is called in loop().

void setup() {}
void loop()
{
  blinkWithOutDelay(1000);
}
void blinkWithOutDelay(const unsigned long interval)
{
  const byte ledPin =  LED_BUILTIN;// the number of the LED pin
  pinMode(ledPin, OUTPUT);
  static byte ledState = LOW;             // ledState used to set the LED
  //byte ledState = LOW;
  static unsigned long previousMillis = 0;
  //unsigned long previousMillis = 0;

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
  }
}
const byte ledPin =  LED_BUILTIN;// the number of the LED pin
byte ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;
const unsigned long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
  }
}

cattledog:
Here's an examples of blinkWithoutDelay as it is normally shown with global variables, and a version with a function call.

That makes it crystal clear. Thank you.

Pretty much what I told you in Reply #10.

gfvalvo:
Pretty much what I told you in Reply #10.

Right, and I gave you 2x karma; I am sorry if you are offended.