Go Down

Topic: Swapping out delay for millis() problems (Read 668 times) previous topic - next topic

Basic

Hi Forum members
I have code I have been writing for a project which has been working OK but due to a delay of 2000 I have problems with a lag in activations that need to be almost instant.
The problem i am having is writing the correct code to swap the delay for millis() I just cant get it to work.
The current simplified code which works using delay(2000) is as below works but delay (2000) is what I need to swap with millis()

Rather than me muddying the water with what I have already tried any support would be a great help.

 /*
  AnalogReadSerial
  Reads an analog input on pin 0, prints the result to the serial monitor.
  Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

*/
  int ledPinl = 10;      // The LED is connected to digital pin 10 actually multimeter
  const int PIEZO_PINL= A3; // Piezo output

int valL=0;
int valR=0;

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
    // initialize digital pin 10 and 11 as an output.
  pinMode(10, OUTPUT);
  analogWrite (ledPinl, 127);
}

// the loop routine runs over and over again forever:
void loop() {

  // read the input on analog pin 3:
  int sensorValue00 = analogRead(A3);
  Serial.print(", Sensor Value 00: ");
  Serial.println(sensorValue00);
    delay(100);        // delay in between reads for stability
  // read the input on analog pin 4:
  int sensorValue01 = analogRead(A4);
  // if the analog value is high enough, turn on the LED:
  // print out the value you read:
  Serial.print(", Sensor Value 01: ");
  Serial.println(sensorValue01);
   delay(100);        // delay in between reads for stability
 
   int valL = analogRead(A3);
  if (valL < 10){
    if (sensorValue01 > valL) // if the current state is below 01 turns on Right LED
    analogWrite(ledPinl, 255);
      delay(2000);
      analogWrite(ledPinl, 127); 
  }

Koepel

Can you explain in words why you do those things for stability ? I don't understand why a dummy read makes it more stable. I also don't understand why a delay makes it more stable. Can you explain in words when to turn on the led for 2 seconds ? Should the led be turned off directly if the condition is no longer true ? Should the 2 seconds be lengthen if the conditions keeps on being true ?

DKWatson

#2
Feb 14, 2018, 01:02 am Last Edit: Feb 14, 2018, 01:02 am by DKWatson
Please read the instructions on how to use the forum and how to post code. If you ask for assistance, at least try to make easy for those who would help.

It's not exactly clear (to me) what you mean by 'swap with millis'.

Delay(2000) gives you a two second delay. Getting rid of delay (which you should NEVER use anyhow) and replacing it with:

   uint32_t _now = millis();
   while ((millis() - now) <= 2000)
   {
       // you can do something here;
   }

has the same effect. Is this what you mean by swap with millis?
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

Robin2

Have a look at how millis() is used to manage timing without blocking in Several things at a time.  Note how each function runs very briefly and returns to loop() so the next one can be called. Long running processes are achieved a tiny piece at a time. And there may be dozens of calls to some functions before it is actually time for anything to happen.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

larryd

Quote
Rather than me muddying the water with what I have already tried any support would be a great help.
We like muddy water, show us your attempt at incorporating millis()


No technical PMs.
The last thing you did is where you should start looking.

Basic

Can you explain in words why you do those things for stability ? I don't understand why a dummy read makes it more stable. I also don't understand why a delay makes it more stable. Can you explain in words when to turn on the led for 2 seconds ? Should the led be turned off directly if the condition is no longer true ? Should the 2 seconds be lengthen if the conditions keeps on being true ?
Hi Koepel
Thank you for looking into my issue.
Please see below for a description of the scenario.
Currently a Potentiometer is connected to the arduino;
& an LED is connected to the arduino;
The LED should not come on when the Potentiometer is turned from 0 upwards.
The LED should come on when the  Potentiometer is turned from a current reading (above 0) to a reading below its current read and stay on until it is turned to 0.
The LED should come on when the Potentiometer is turned fully to 0 (from a higher reading) the LED should then stay on for 2 seconds then turn off.

But whilst the input is at zero the Arduino must still be active ie. taking readings ever 10milli seconds.
With delay (as currently programmed) this does not happen every 10milli seconds but every 2 second, unless the Potentiometer is moved from 0.
This is not desirable.

I hope this helps
Thanks in advance
Richard

Basic

Please read the instructions on how to use the forum and how to post code. If you ask for assistance, at least try to make easy for those who would help.

It's not exactly clear (to me) what you mean by 'swap with millis'.

Delay(2000) gives you a two second delay. Getting rid of delay (which you should NEVER use anyhow) and replacing it with:

   uint32_t _now = millis();
   while ((millis() - now) <= 2000)
   {
       // you can do something here;
   }

has the same effect. Is this what you mean by swap with millis?
Hi DK Watson
Apologies for not being clear, I am new to the Forum and, new to Arduino probably not the best combination.
I have now realised by research and my small amount of experience that delay is not the best to use.

Your suggestion above seems to be in various instructions I have seen but what i struggling with is using it after an action has taken place
So in my piece of programming as below how would your suggestion fit in to replace the "delay(2000);" line of code.

int valL = analogRead(A3);
  if (valL < 10){
    if (sensorValue01 > valL) // if the current state is below 01 turns on Right LED
    analogWrite(ledPinl, 255);
      delay(2000);
      analogWrite(ledPinl, 127); 
  }

larryd

Is this line
delay(2000);
only to delay this line
analogWrite(ledPinl, 127); 

Or is it meant to delay everything afterwards?


.
No technical PMs.
The last thing you did is where you should start looking.

Koepel

#8
Feb 14, 2018, 10:16 pm Last Edit: Feb 14, 2018, 11:39 pm by Koepel
Create two global variables. Turn the software delay on by enabling the boolean variable and remember the millis(). At the end of the loop() check if the software delay is active. Turn the software delay off if millis() is two seconds further in time.

Code: [Select]

// two global variables
unsigned long previousMillis;
boolean active = false;

void setup()
{
  ...
}

void loop()
{
  if( ...
  {
    // Turn the software delay on
    active = true;    // make software delay active
    previousMillis = millis();   // remember this moment
    digitalWrite( pinLed, HIGH);   // turn on led
  }
  ...

  if( active)
  {
    if( millis() - previousMills > 2000)   // time has elapsed ?
    {
      active = false;                 // turn software delay off, it is no longer needed.
      digitalWrite( pinLed, LOW);   // turn off led.
    }
  }
}


Basic

Is this line
delay(2000);
only to delay this line
analogWrite(ledPinl, 127); 

Or is it meant to delay everything afterwards?


.
Hi larryd
I will add the previous lines of code in and add my understanding to the right of the code

 int valL = analogRead(A3);
  if (valL < 10){
    if (sensorValue01 > valL)       // if the current state is below 01 turns on Right LED
    analogWrite(ledPinl, 255);     //this turns on the Right LED (full power, 5 volts) (ON)
      delay(2000);                      //this makes the LED stay on at full power for 2 seconds (ON)
      analogWrite(ledPinl, 127);   //after 2 seconds has passed the LED goes back to half power (OFF)
  }

larryd

No technical PMs.
The last thing you did is where you should start looking.

larryd

Create two global variables. Turn the software delay on by enabling the boolean variable and remember the millis(). At the end of the loop() check if the software delay is active. Turn the software delay off if millis() is two seconds further in time.

Code: [Select]

// two global variables
unsigned long previousMillis;
boolean active;

void setup()
{
  ...
}

void loop()
{
  if( ...
  {
    // Turn the software delay on
    active = true;    // make software delay active
    previousMillis = millis();   // remember this moment
    digitalWrite( pinLed, HIGH);   // turn on led
  }
  ...

  if( active)
  {
    if( millis() - previousMills > 2000)   // time has elapsed ?
    {
      active = false;                 // turn software delay off, it is no longer needed.
      digitalWrite( pinLed, LOW);   // turn off led.
    }
  }
}



Maybe add:
active == false &&

if( active == false && ...


No technical PMs.
The last thing you did is where you should start looking.

Koepel

@larryd, I have changed my example. The global variable 'active' is now default set to false.
I prefer two seperate if-statements. That makes it clear what is going on in my opinion. That just my personal preference, I don't even understand why everyone uses the opening bracket '{' at the end of a line :smiley-confuse: Since the curley brackets provide a beautiful way to show the structure of a sketch.

I don't know the conditions when to start the software delay. I suppose that the software delay can be lengthened when it is already running. That means that the part to turn on the software delay can be executed over and over again regardless if it was turned off or not.

GreyArea

Hi larryd
I will add the previous lines of code in and add my understanding to the right of the code

 int valL = analogRead(A3);
  if (valL < 10){
    if (sensorValue01 > valL)       // if the current state is below 01 turns on Right LED
    analogWrite(ledPinl, 255);     //this turns on the Right LED (full power, 5 volts) (ON)
      delay(2000);                      //this makes the LED stay on at full power for 2 seconds (ON)
      analogWrite(ledPinl, 127);   //after 2 seconds has passed the LED goes back to half power (OFF)
  }

I am new too, so probably REALLY going to muddy the waters.

The delay(2000) is just to keep the LED on for two seconds, yes?

If so, consider setting a variable as follows at the point of your current delay statement.

Code: [Select]

Poweroff=millis();


Let the code continue on and at whatever critical program points it is necessary to check the LED, add the following

Code: [Select]

if (millis()-Poweroff>=2000){
 analogWrite(ledPinl, 127);
}


I used "Poweroff" not "LEDOn" because it seemed the important thing you were checking was the power dropping below one - the LED coming on is just the visualisation of that.

Sorry if I didn't help...and apologies to Mods for what are probably half-formed, badly written code snippets...

Basic

Hi Guys
Tried the previous suggestions but to no avail.
Did a little bit more digging and have written the code below, now I think i am very close to cracking this part of the programme, the LED comes on full power but stays on, there must be a slight error in turning it back down, please see below.

 /*
  AnalogReadSerial
  Reads an analog input on pin 0, prints the result to the serial monitor.
  Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

*/
  int ledPinl = 10;      // The LED is connected to digital pin 10 actually multimeter
  int ledPinr= 11;      // The LED is connected to digital pin 11 actually multimeter
  const int PIEZO_PINR = A2; // Piezo output
  const int PIEZO_PINL= A3; // Piezo output

  const int FLEX_PIN = A0; // Pin connected to voltage divider output
  int buttonState = 0;
  int lastButtonState = 1;
int valL=0;
int valR=0;

unsigned long elapsedTime;
unsigned long onTime;

 
// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
    // initialize digital pin 10 and 11 as an output.
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  analogWrite (ledPinl, 127);
  analogWrite (ledPinr, 127); 
 
  onTime = millis();
 onTime = elapsedTime;
 pinMode(12, OUTPUT);  //Initialize pin 12 as status LED
 pinMode(8, INPUT);    // Our button pin   
}

// the loop routine runs over and over again forever:
void loop() {
 
  // read the input on analog pin 3:
  int sensorValue00 = analogRead(A3);
  Serial.print(", Sensor Value 00: ");
  Serial.println(sensorValue00);
    delay(10);        // delay in between reads for stability
  // read the input on analog pin 4:
  int sensorValue01 = analogRead(A4);
  // if the analog value is high enough, turn on the LED:
  // print out the value you read:
  Serial.print(", Sensor Value 01: ");
  Serial.println(sensorValue01);
   delay(10);        // delay in between reads for stability
 
   int valL = analogRead(A3);
  if (valL < 10){

    if (sensorValue01 > valL) // if the current state is below 01 turns on Left LED
       analogWrite(ledPinl, 255);
       onTime = millis(); 
       }
    if(onTime > 0 && millis() - onTime > 2000)
       {       
       analogWrite(ledPinl, 127);  // LED goes off
       onTime=0;
       }
}

   
   

Go Up