delay inside blink without delay

I’m having problems figuring out this delay within the blink without delay. Two Maxbotix LV EZ 1 ultrasonic sensors are chained together so that one doesn’t interfere with the other. As the code is written, the sensors take turns reading the distance just as expected. I have attached the code, a wiring image, and a screenshot (PW result) of the results.

/*
  Two Maxbotix sensors chained together. Sensor 1 is triggered by the code to read distance. Then sensor 1
  triggers sensor 2. This prevents cross sensor interference of the ultrasonic waves.
  Sensors being used for this code are the LV EZ-1 MaxSonar Sensors from MaxBotix
*/
const int pwPin1 = 9;    //sensor 1
const int pwPin2 = 10;   //sensor 2 - triggered by sensor 1
int triggerPin1 = 13;  //triggers sensor 1
long sensor1, sensor2, distance1, distance2;
unsigned long triggerPause = 1;
unsigned long loopPause = 300; //stops sensors from ranging too frequently - better for stability
unsigned long PreviousMillis1 = 0;
unsigned long PreviousMillis = 0;

void setup () {
  Serial.begin(9600);
  pinMode(pwPin1, INPUT);
  pinMode(pwPin2, INPUT);
  pinMode(triggerPin1, OUTPUT);
}

void read_sensor() {
  sensor1 = pulseIn(pwPin1, HIGH);
  distance1 = sensor1 / 58; //makes the reported range the distance in centimeters

  sensor2 = pulseIn(pwPin2, HIGH);
  distance2 = sensor2 / 58;
  printall();
}

void start_sensor() {

  digitalWrite(triggerPin1, HIGH);
  delayMicroseconds(25);   //necessary for sensor to trigger
  digitalWrite(triggerPin1, LOW);

  read_sensor();

}


void printall() {
  Serial.print("S1");
  Serial.print("-");
  Serial.print(distance1);
  Serial.print(" ");
  Serial.print("S2");
  Serial.print("-");
  Serial.print(distance2);
  Serial.println();
}

//loops every 300 milliseconds to read sensors and print results
void loop () {
  unsigned long CurrentMillis = millis();
  if (CurrentMillis - PreviousMillis1 >= loopPause) {
    start_sensor();
    PreviousMillis1 = CurrentMillis;
  }

}

I would like to get rid of the delayMicroseconds = 25; that you see in the start_sensor function and replace it with non blocking code. The following code is my attempt to do that. I have also attached a screenshot (PW result 2) of the results of this code. Obviously the non blocking delays are interfering with each other.

/*
  Two Maxbotix sensors chained together. Sensor 1 is triggered by the code to read distance. Then sensor 1
  triggers sensor 2. This prevents cross sensor interference of the ultrasonic waves.
  Sensors being used for this code are the LV EZ-1 MaxSonar Sensors from MaxBotix
*/
const int pwPin1 = 9;    //sensor 1
const int pwPin2 = 10;   //sensor 2 - triggered by sensor 1
int triggerPin1 = 13;  //triggers left sensor
long sensor1, sensor2, distance1, distance2;
unsigned long triggerPause = 1;
unsigned long loopPause = 300; //stops sensors from ranging too frequently - better for stability
unsigned long PreviousMillis1 = 0;
unsigned long PreviousMillis2 = 0;


void setup () {
  Serial.begin(9600);
  pinMode(pwPin1, INPUT);
  pinMode(pwPin2, INPUT);
  pinMode(triggerPin1, OUTPUT);
}

void read_sensor() {
  sensor1 = pulseIn(pwPin1, HIGH);
  distance1 = sensor1 / 58; //makes the reported range the distance in centimeters

  sensor2 = pulseIn(pwPin2, HIGH);
  distance2 = sensor2 / 58;
  printall();
}

void start_sensor() {

  digitalWrite(triggerPin1, HIGH);
  //delayMicroseconds(25);   //necessary for sensor to trigger. must be greater than 20 microseconds
  unsigned long CurrentMillis2 = millis();
  if (CurrentMillis2 - PreviousMillis2 >= triggerPause) {  //This is supposed to replace delayMicroseconds
  digitalWrite(triggerPin1, LOW);
  PreviousMillis2 = CurrentMillis2;
  }
  read_sensor();

}


void printall() {
  Serial.print("S1");
  Serial.print("-");
  Serial.print(distance1);
  Serial.print(" ");
  Serial.print("S2");
  Serial.print("-");
  Serial.print(distance2);
  Serial.println();
}

//loops every 300 milliseconds to read sensors and print results
void loop () {
  unsigned long CurrentMillis = millis();
  if (CurrentMillis - PreviousMillis1 >= loopPause) {
    start_sensor();
    PreviousMillis1 = CurrentMillis;
  }

}

Does anybody have any suggestions how I can improve this code to make the non blocking delay in the start_sensor function work with the non blocking delay in the loop function?

TeslaIaint: Does anybody have any suggestions how I can improve this code to make the non blocking delay in the start_sensor function work with the non blocking delay in the loop function?

Don't. Sometimes the best thing to do is to leave it alone.

Non-blocking code is only necessary if you need to go off and do something else during the waiting period. There is a cost for this though. Non-blocking code has extra overhead associated with storing the start time and continually checking the interval. Because of this, you need the interval to be a certain length before it becomes worth doing a non-blocking delay. I probably wouldn't consider non-blocking code until the intervals got over a millisecond.

25 microseconds is like 400 instruction cycles. That might sound like a lot, but it's not. You're running the sensor every 300 milliseconds, so you've got 4.8 million instructions cycles in between those runs. You can afford to throw away 400 of those.

The non-blocking delays are not "obviously" interfering with each other. The code is malfunctioning not because of any mythical "interference" but because you did not implement the non-blocking interval the correct way. When you implement an interval like this, you need to check on it as often as you can afford, and that should be at least several times per interval period. There is no point making a 1 ms interval when you only check it every 300 ms. Of course it won't work properly.

When all you have is a hammer, everything looks like a nail. This is not a nail, so you don't need a hammer. All tools have an appropriate use, included non-blocking delays.

I think Jiggy-Ninja has a valid point. Unless you need something close to real-time, those 25 microseconds are not going to kill your application.

If you insist on changing it, you need to implement something that will prevent both sensors from being triggered at the same time. A small statemachine comes to mind.

And you need to use micros() instead of millis() ;)

This made me smile because it reminded me of my Army days. We had the Expression "hurry up and wait". You had to get somewhere really fast so you could wait until it started. Everyone yelled "faster, faster" and when you got there, you waited two hours before anything happened.

In this example, an attempt is made to save 25 milliseconds so that the following wait is 250 milliseconds instead of 225...

I agree with Jiggy-Ninja: "All tools have an appropriate use, included non-blocking delays." but would go further and say "as well as blocking delays".

Other than that, what I often do in situations like when I activate the device - which often times includes a delay because they don't want you to attempt to read the device before it is ready - I ensure within my code that I DONT try to read it until it has time to fully come up to Speed. Instead of just waiting, I do other things, like activate other devices that I will also Need to read, do calculations which Need to be done anyway, etc. After doing a few things like that, the time for the sensor to come up to Speed has elapsed and I can safely start reading them.

Unless you need something close to real-time, those 25 microseconds are not going to kill your application.

The application then calls pulseIn() which twiddles it's thumbs waiting for the echo to return, anyway, so removing the 25 microsecond delay will, overall, do nothing to improve the performance of the application.

OP: Take a look at the NewPing library, where interrupts are used to perform the work, with NO delay()s anywhere, IF you really need better performance.

PaulS: The application then calls pulseIn() which twiddles it's thumbs waiting for the echo to return, anyway, so removing the 25 microsecond delay will, overall, do nothing to improve the performance of the application.

OP: Take a look at the NewPing library, where interrupts are used to perform the work, with NO delay()s anywhere, IF you really need better performance.

PulseIn is the bigger bad guy. 25 microseconds isn't a long block unless you run it 20+ times/second and then it starts to be a drag in the total (not yet a total drag at least).

Where you want to watch out is if you add code that does need to be fast response.

IMO for some addons like GSM and ultrasonic sensors, having a dedicated controller makes sense.

JaBa: In this example, an attempt is made to save 25 milliseconds so that the following wait is 250 milliseconds instead of 225...

If it was a 25 millisecond delay, I'd say go ahead, non-block that any day of the week.

This guy's trying to fancy up a 25 microsecond delay. There's no point, especially when OP's still blocking for far longer with 2 pulseIn() functions on the same pathway.

I agree with Jiggy-Ninja: "All tools have an appropriate use, included non-blocking delays." but would go further and say "as well as blocking delays".

Obviously OP knows that blocking delays have a purpose, otherwise this thread wouldn't exist. The mistake here was not fully understanding their tradeoffs, and so not being able to recognize when it would not be appropriate.

I know that it's pounded into people's heads here to not use blocking delays, but the common situation on this forum is someone who has their loop peppered with delay(1000), delay(5000), delay(2000) all over the place to blink their LEDs in a set pattern and then wants to add 4 buttons and 2 rotary encoders to control a servo that they want to dance the Macarana. It's impossible to do that when the controller's constantly comatose.

So it's not a surprise that situations like this happen, where a delay is so short and infrequent that it's not worth bothering trying to refactor around it, but someone has the thought "delays are always bad" and tries to do it anyway. This is when they can learn how to balance things, and consider "is the delay long enough that it's worth going off and doing other things during the interval?" "Does anything even need to be done during this time?" If this answer to either of those questions is no, it's fine to use a blocking delay like this. If the answer is yes, you non-block.

Other than that, what I often do in situations like when I activate the device - which often times includes a delay because they don't want you to attempt to read the device before it is ready - I ensure within my code that I DONT try to read it until it has time to fully come up to Speed. Instead of just waiting, I do other things, like activate other devices that I will also Need to read, do calculations which Need to be done anyway, etc. After doing a few things like that, the time for the sensor to come up to Speed has elapsed and I can safely start reading them.

This is not a function to setup the sensor at the start of the program. It's an ultrasound sensor, so I assume the trigger pin enables the buzzer. I'm guessing the 25 microsecond delay is to keep it active long enough to get a decent pulse before shutting it off. This is something that's run repeatedly in loop(). I've never used one before so I'm not familiar with the details though.

Actually I have a rule of thumb for non-blocking tasking code. Try to keep any step from using over 200 usecs max and under 100 usecs if possible (10-bit analog read takes 105 plus settle period). add: looping through a large array that doesn't have to be done this pass through loop() is also blocking. Maintaining indexes and processing 1 element per pass is good practice at breaking up the steps.

A step is an execution from loop(), all the code until it is done and loop() can run the next thing. Maybe there's a case in there that 1 time a minute has to take a whole milli, then don't have other tasks that will die because of it! At least be fault tolerant, LOL!

I run IPO loop at over 50KHz in simple examples. I put a delay(1) in and got 980 Hz.

When you learn something new or been away, good practice makes you better. Zero delays approach generally makes good practice.

I appreciate the replies and the advice. And I should have been clearer on my future intentions. In the future there will be motors with PWM, etc. If the 25 microsecond delay won't affect them or affect them very little, I'm happy to leave the delayMicroseconds as is.

If you ever get to that point then you might add an AVR chip if not a small board.

With robots I would want to distribute the intelligence, 328P is $2 ea when you buy 100. Can use excess stock on products at startup.

This is all you need to load/bootload 328P or 1284P on breadboard.

I will solder to sockets, here is Arduino-on-a-chip!

Have to admit, it's small.

GoForSmoke: Actually I have a rule of thumb for non-blocking tasking code. Try to keep any step from using over 200 usecs max and under 100 usecs if possible (10-bit analog read takes 105 plus settle period). add: looping through a large array that doesn't have to be done this pass through loop() is also blocking. Maintaining indexes and processing 1 element per pass is good practice at breaking up the steps.

A step is an execution from loop(), all the code until it is done and loop() can run the next thing. Maybe there's a case in there that 1 time a minute has to take a whole milli, then don't have other tasks that will die because of it! At least be fault tolerant, LOL!

I run IPO loop at over 50KHz in simple examples. I put a delay(1) in and got 980 Hz.

When you learn something new or been away, good practice makes you better. Zero delays approach generally makes good practice.

All good points, especially fault tolerance. It depends on your requirements. Some things might be able to cope with having the processor go off into lala land for 5 ms, others will need tighter timings. The balance will shift depending on the exact circumstances of what you're doing.

1/50kHz = 20 us + 1,000 us = 1,020 us, 1/1,020 us = 980.4 Hz.

I can do math, you know. It's not exactly a mystery that when things take longer to do, you can't do them as frequently.

What is IPO? The only time I've seen that acronym used is in finance, and the first few pages of google results didn't have anything I saw related to electronics.

GoForSmoke: If you ever get to that point then you might add an AVR chip if not a small board.

With robots I would want to distribute the intelligence, 328P is $2 ea when you buy 100. Can use excess stock on products at startup.

This is all you need to load/bootload 328P or 1284P on breadboard.

I will solder to sockets, here is Arduino-on-a-chip!

Have to admit, it's small.

I just bought an Ardueeny last week. That thing in your second link is so much cooler.

Check out the first link especially if you have an Uno with socketed chip. It gives you the chance to bootload replacement chips to program via serial (USB).

Halfway down that link the example chip changes to the "Mighty" 1284P with 40 pins and 16K RAM. I bought a board with one that runs 24MHz because I couldn't not. It runs the debounce tuner loop() at 127KHz. But my Teensy 3.1 can chew that up and 2 more.... so many Duinos, so few years left.

IPO is separation of tasks but not rigid. Note that Serial is 2-way IO.

Input

Process

Output

Make tasks to be virtual machines, have them interact through data (flags, finite states, time, pins) as well as on it. These machines are very good for streaming data, SD adapters to IoT.

Jiggy-Ninja: 1/50kHz = 20 us + 1,000 us = 1,020 us, 1/1,020 us = 980.4 Hz.

I can do math, you know. It's not exactly a mystery that when things take longer to do, you can't do them as frequently.

That example was my answer to members who thought delay(1) is nothing, to show that watching 4 buttons, blinking a led and printing constant status is nothing compared to a delay(1).