Go Down

Topic: timer issue after "while" (Read 281 times) previous topic - next topic

brice3010

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.

UKHeliBob

Quote
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
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

brice3010

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  :smiley-mr-green:
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..

Code: [Select]

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) {

  }
}

 

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.

brice3010

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:

Code: [Select]

//..
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.




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.

brice3010

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.

Code: [Select]

// 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);
}


gfvalvo

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

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

brice3010

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?



brice3010

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

BTW, the are called functions, not 'voids'.
..changing to
Code: [Select]

static unsigned long previousMillis; // timer

made the difference!!

gfvalvo

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.

gfvalvo

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

vaj4088

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

Code: [Select]

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.


brice3010

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

Code: [Select]

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

vaj4088


Go Up