Avoiding Delay (blinkwithoutdelay) help

Hello!

I understand how to do the 'blinkwithoutdelay' using currentMillis to set the time, and compare to some interval, and run code. However, I'm stuck on how to do that twice in a row.

I am using Parola to send a string through the LEDs. I can get that working, no problemo. However, I am now trying to hook up a PING Ultrasonic Distance sensor, take a distance reading, and output that distance to the LEDs. The PING sensor will use delayMicroseconds() to send a ping, delay, receive the ping. Here's the original code:

void measureDistance()
{
  // set pin as output so we can send a pulse
  pinMode(signal, OUTPUT);
  digitalWrite(signal, LOW);
  delayMicroseconds(5);
  digitalWrite(signal, HIGH);
  delayMicroseconds(5);
  digitalWrite(signal, LOW);
  pinMode(signal, INPUT);
  pulseduration=pulseIn(signal, HIGH) / 2;
  // pulseduration=pulseduration/2; 
  distance = int(pulseduration/29);
  indistance = distance*.39;   //<<<<<<<<<<< changed 'indistance' to FLOAT 
}

See the 'delayMicroseconds'? How can I get rid of that? When I leave that in, the scrolling on the LEDs delays as well. I was able to get this far- but can't figure out how to do the second delay.

Here's what I have been able to get so far:

const int pingDelay = 5;
int previousMillis = 0;


void measureDistance()
{
   unsigned long currentMillis = millis();
  // set pin as output so we can send a pulse
  pinMode(signal, OUTPUT);
  digitalWrite(signal, LOW);
  if (currentMillis - previousMillis > pingDelay){
    previousMillis = currentMillis;
//  delayMicroseconds(5);
  digitalWrite(signal, HIGH);
  }                                                            ///  How do I do that again??
  delayMicroseconds(5);
  digitalWrite(signal, LOW);
  pinMode(signal, INPUT);
  pulseduration=pulseIn(signal, HIGH) / 2;
  // pulseduration=pulseduration/2; 
  distance = int(pulseduration/29);
  indistance = distance*.39;   
}

Do I need something like 'currentMillis2' or 'previousMillis2' ? Because I don't think I can just repeat the same code again, since I reset 'previousMillis = currentMillis' right?

I'm pretty sure the code I posted should get you to understand the issue - but if you would like the whole thing/more, just let me know!

Thanks for any ideas, it's a relatively easy idea I'm sure - I'm just having trouble getting my head wrapped around how to do it. :~

(I kind of wish we had something like spoiler tags, so you could provide hints/advice, I could work on it, then just click/hover over the spoiler tag to see the solution).

didn't we already fix this once?

How about if you don't reset previousMillis until after the the second interval and use: if (currentMillis - previousMillis > (pingDelay *2)){ for the second one (assuming the intervals are equal).

Henry_Best:
How about if you don't reset previousMillis until after the the second interval and use: if (currentMillis - previousMillis > (pingDelay *2)){ for the second one (assuming the intervals are equal).

Ah, good idea! I'll try that and report back.

And BulldogLowell, I don't think I have posted this issue - and if I have, I'm sorry :blush:
(PS: I bet you're even more so, but I am so excited for the vote results! Best of luck).

Getting rid of delay() is generally a good idea. But this cannot be equally applied to delayMicros(), especially not for very short delays since almost everything a arduino does repeatedly takes several microseconds.

Henry_Best:
How about if you don't reset previousMillis until after the the second interval and use: if (currentMillis - previousMillis > (pingDelay *2)){ for the second one (assuming the intervals are equal).

Hm, so I tried that and it kind of works, but not completely. Here's the code:

const int pingPin = A5;
long previousMillis = 0;
unsigned long pulseDuration = 0;
const int pingDelay = 5;
float indistance;
int distance;

void measureDistance()
{
  // set pin as output so we can send a pulse
  unsigned long currentMillis = millis();
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  if (currentMillis - previousMillis > pingDelay){
    digitalWrite(pingPin, HIGH);
    }
  if (currentMillis - previousMillis > (pingDelay * 2)){
    digitalWrite(pingPin, LOW);
    pinMode(pingPin, INPUT);
    previousMillis = currentMillis;
  }
  pulseDuration=pulseIn(pingPin, HIGH) / 2;
  // pulseduration=pulseduration/2; 
  distance = int(pulseDuration/29);
  indistance = distance*.39;   
  Serial.println(indistance);
}

What happens is that the PING sensor light stay lit up, but when I put my hand in front of it, and it reads a value, then the whole sketch starts to delay again...

For instance, if I don't have anything in front of the sensor, my text scrolls on the LED like usual (correctly). When I put my hand in front of the sensor, it does indeed detect the distance, BUT during the distance being read, the whole sketch delays (and the text scrolling across pauses for the [I assume] pingDelay time).

Does how I described that make sense?

did you try the NewPing library?

BulldogLowell:
did you try the NewPing library?

I'm looking at it - I still can't figure out how to do it twice. Note the PING sensor I have only has one PIN for the echo/trig (that doesn't change the code too much, I don't think).

Sorry about my lack of understanding, but I'll get there eventually. :blush:

Some time ago someone posted a sketch to get several delays out of a function similar to the blink without delay, each working independently. Would this be something useful?

I cant recall the original link, perhaps someone with better memory than mine can post a link.

Regards

casemod:
Some time ago someone posted a sketch to get several delays out of a function similar to the blink without delay,

I think this is what you mean. It has now been elevated to the status of a sticky

...R

make your function more of a function...

pss th spin number(s) into the function and return a float.

something like this untested bit... modifying your function, which I am unsure if it does what you want.

in loop():

float distance1 = measureDistance(pulsePin1);
float distance2 = measureDistance(pulsePin2);
float measureDistance(int signal)
{
  unsigned long currentMillis = millis();
  // set pin as output so we can send a pulse
  pinMode(signal, OUTPUT);
  digitalWrite(signal, LOW);
  if (currentMillis - previousMillis > pingDelay){
    previousMillis = currentMillis;
    //  delayMicroseconds(5);
    digitalWrite(signal, HIGH);
  }           
  delayMicroseconds(5);
  digitalWrite(signal, LOW);
  pinMode(signal, INPUT);
  pulseduration=pulseIn(signal, HIGH) / 2;
  // pulseduration=pulseduration/2; 
  distance = int(pulseduration/29);
  indistance = distance*.39;
  return indistance; 
}

Found it:

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

boolean delay_without_delaying(unsigned long time) {
  // return false if we're still "delaying", true if time ms has passed.
  // this should look a lot like "blink without delay"
  static unsigned long previousmillis = 0;
  unsigned long currentmillis = millis();
  if (currentmillis - previousmillis >= time) {
    previousmillis = currentmillis;
    return true;
  }
  return false;
}

boolean delay_without_delaying(unsigned long &since, unsigned long time) {
  // return false if we're still "delaying", true if time ms has passed.
  // this should look a lot like "blink without delay"
  unsigned long currentmillis = millis();
  if (currentmillis - since >= time) {
    since = currentmillis;
    return true;
  }
  return false;
}

unsigned long ledtime = 0;
unsigned long atime, btime, ctime, nltime;

void loop() {
  static int ledstate = false;
  if (delay_without_delaying(ledtime, 500)) {
    ledstate = !ledstate;
    digitalWrite(13, ledstate);
  }
  if (delay_without_delaying(atime, 100)) {
    Serial.print("A");
  }
  if (delay_without_delaying(btime, 200)) {
    Serial.print("B");
  }
  if (delay_without_delaying(ctime, 30)) {
    Serial.print("C");
  }
  if (delay_without_delaying(nltime, 1000)) {
    Serial.print("\n");
  }
}

Thanks for the ideas BulldogLowell and Casemod.

I will try both of them - but briefly, BulldogLowell, wouldn't the 'delaymicroSeconds()' still delay the whole thing? I just want to get the ping sensor to give me a distance, then output that to my LED display - so any delay makes the LED scrolling slow down. But thanks, I agree I need to 'tighten up' my functions, so that helps. :slight_smile:

You must have a precise delay for the echo to be measured

A few microseconds won't affect your lcd display

so any delay makes the LED scrolling slow down.

You start generating a pulse. You wait a few microseconds. You stop sending the pulse. Then, you wait a long time (in the pulseIn() function) for the echo.

Removing the delayMicroseconds() call, and keeping the pulseIn() call, is pointless. The delay of a few microseconds is NOT what is affecting the display scrolling.

What you are attempting to do is like trying to loose weight by substituting a Pepsi Zero for the Diet Pepsi that you are drinking with your bacon double 1/2 pound burger with 3 kinds of cheese.

Piethon:
How about if you don't reset previousMillis until after the the second interval and use: if (currentMillis - previousMillis > (pingDelay *2)){ for the second one (assuming the intervals are equal).

if (currentMillis - previousMillis > (interval)){

Thats the same issue as described here: Demonstration code for several things at the same time - Project Guidance - Arduino Forum

In short, the interval may return a higher value, due to the execution times. So you need to check what time the event is due, not if the given time has elapsed, as this adds to any execution times. Not sure if I am clear enough.

Anyway, if I wanted very accurate delays I would not use such a thing. I would set a timer to overflow every x period and would add an ISR to execute whatever you are executing with that function now. Is this not technically possible or you just didn't knew?

You can add a function that starts the timer manually and returns an interrupt at overflow (Stop the timer again on the ISR).

One can also count timer 0 overflows (490 per second) to get accurate delays, assuming your loop is not stuck with delays, but this method is a bit more complicated and adds a bit more overhead.

I may be wrong, but I seem to remember reading that the microseconds counter is only updated every 4 micros. How then, can there be a measured 5 microsecond delay?

Henry_Best:
I may be wrong, but I seem to remember reading that the microseconds counter is only updated every 4 micros. How then, can there be a measured 5 microsecond delay?

Good point, he can't :wink:
Its probably going to return either 4 or 8 depending on the system overhead.

I cant stress enough, that for something on this order of magnitude an interrupt would be better suited.

casemod:

Henry_Best:
I may be wrong, but I seem to remember reading that the microseconds counter is only updated every 4 micros. How then, can there be a measured 5 microsecond delay?

Good point, he can't :wink:
Its probably going to return either 4 or 8 depending on the system overhead.

I can't see it returning 4 if he's asking for a 5 micros delay.

I cant stress enough, that for something on this order of magnitude an interrupt would be better suited.

One of the rare cases where an interrupt is required.

I've not used an interrupt before, but will look in to it. I'm getting closer to it working, so I'll keep updating as I get there. Thanks again everyone for your advice and tips!