1

dears Engineers.. i got stuck with this issue couldn't understand.. please help with explanations.

first i was upset of my ultrasonic sensor reading deviations, that is i examine my sensor indoor and at quite environment,, so what makes this noisy output readings??!!!

so i tried to dig into the pulseIn function and tracking the timing of each instruction in the code.. after reading the library.., i decided to use pulseInLong function. following is a result of some iterations timing in microseconds:

Ultrasonic Sensor HC-SR04 Test
with Arduino UNO R3
Start ~ trig LOW  ~ 10us delay ~ trig High ~ 10us delay~ trig High ~   pulseIn    ~   Duration
0           8           12          8           12          4           7352            137976
4           4           12          8           12          8           7336            137960
4           8           12          8           12          8           7352            137976
4           8           12          8           12          8           7356            137980
4           8           12          8           12          8           7352            137976
4           8           12          8           12          8           7356            137980
4           8           12          8           12          8           7360            137984
4           8           12          8           12          8           7364            137996
0           8           12          8           12          8           7364            137992
4           8           12          8           12          8           7372            137996
4           8           12          4           12          8           7380            138004
0           4           12          8           12          8           7372            137996
0           4           12          8           12          8           7348            137968
4           8           12          4           12          8           7372            137996
4           8           12          8           12          4           7376            138004
4           8           12          8           12          8           7380            138008
0           8           12          8           8           8           7352            137980
4           8           12          4           12          8           7352            137976
4           8           12          4           12          8           7368            137992
4           8           12          8           12          8           7340            137964
4           8           12          4           12          8           7352            137980
4           8           12          4           12          8           7360            137984
12          8           12          8           12          8           7368            137996
4           8           12          8           12          8           7348            137972
4           8           12          8           12          12          7360            137984
0           8           12          8           12          8           7344            137968
4           8           12          8           12          8           7352            137976
4           8           12          8           12          8           7364            137988
4           8           12          4           12          8           7360            137984
4           8           12          8           12          4           7372            138000

first i wondered why there are different execution time for the same instruction??! for example digitalWrite(trig_pin,LOW or High) varies in range 4 ~ 12 microseconds!!????

more strange when i found elapsed time after delay 10us, micros() function shows only 8 us??!!!

all these in range of 16 us,, so i expected maybe due to some instruction cycles or unprecise clock...etc.

but the BigBang i shocked when read this huuuuuge difference in pulseIn timing measurment; i reset the timer befor the function and just after it, so i got an elapsed time in range of 7350 us. in the same time the resultant measured time from the function in range of the 138000 us?????!!!!!!

put in mind that pulseInLong is a blocking function..as you will see below, it loops in a while loop until timeout (so return 0) or pulse generated and measured before timeout then return pulse elapsed time.

first i suspected in this number maybe not microseconds. inspected the function deeply, ??!!! i found it using the exact micros() function such i do in the code?

 * this function relies on micros() so cannot be used in noInterrupt() context
 */
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
{
    // cache the port and bit of the pin in order to speed up the
    // pulse width measuring loop and achieve finer resolution.  calling
    // digitalRead() instead yields much coarser resolution.
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    uint8_t stateMask = (state ? bit : 0);

    unsigned long startMicros = micros();

    // wait for any previous pulse to end
    while ((*portInputRegister(port) & bit) == stateMask) {
        if (micros() - startMicros > timeout)
            return 0;
    }

    // wait for the pulse to start
    while ((*portInputRegister(port) & bit) != stateMask) {
        if (micros() - startMicros > timeout)
            return 0;
    }

    unsigned long start = micros();
    // wait for the pulse to stop
    while ((*portInputRegister(port) & bit) == stateMask) {
        if (micros() - startMicros > timeout)
            return 0;
    }
    return micros() - start;
}

anyway..i dont want to make this story long.. can someone explain what is going on to me please?!

thanx

here is arduino code i used

#define trigPin 3 //attach pin D3 Arduino to pin Trig of HC-SR04


// defines variables
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement

void setup() {
  // put your setup code here, to run once:

  pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
  pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
  Serial.begin(9600); // // Serial Communication is starting with 9600 of baudrate speed

  Serial.println("Ultrasonic Sensor HC-SR04 Test"); // print some text in Serial Monitor
  Serial.println("with Arduino UNO R3");
  Serial.println("Start ~ trig LOW   ~   10us delay   ~   trig High   ~   10us delay   ~   trig High    ~    pulseIn    ~   Duration");

}

void loop() {
  // put your main code here, to run repeatedly:
  // Clears the trigPin condition
  int indx = 0;
  int arr[7] = {0};
  double last = micros();

  arr[indx] = micros() - last;
  indx++;
  last = micros();

  digitalWrite(trigPin, LOW);

  arr[indx] = micros() - last;
  indx++;
  last = micros();

  delayMicroseconds(10);

  arr[indx] = micros() - last;
  indx++;
  last = micros();
  // Sets the trigPin HIGH (ACTIVE) for 10 microseconds

  digitalWrite(trigPin, HIGH);
  arr[indx] = micros() - last;
  indx++;
  last = micros();

  delayMicroseconds(10);
  arr[indx] = micros() - last;
  indx++;
  last = micros();

  digitalWrite(trigPin, LOW);
  arr[indx] = micros() - last;
  indx++;
  last = micros();

  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseInLong(echoPin, HIGH);
  arr[indx] = micros() - last;

  // Calculating the distance
  distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
  // Displays the distance on the Serial Monitor

  for (int i = 0; i <= indx; i++)
  {
    Serial.print(arr[i]);
    Serial.print("     \t    ");
  }
  Serial.print(duration);
  Serial.println();

}
5
  • Look at the source code, you have it. digitalWrite is a function that has several lines in it. There are interrupts running on the chip. If one of those interrupts fires during the execution of the digitalWrite function then it will take longer to execute that time.
    – Delta_G
    Commented Aug 28, 2020 at 1:47
  • This method of reading an ultrasonic sensor is a great way to introduce someone to how those types of sensors work, because it is really easy to follow code, but there are much better ways to handle reading an ultrasonic sensor in a much more accurate manner.
    – Delta_G
    Commented Aug 28, 2020 at 1:48
  • thanx Delta_G for responding here, but unfortunately, i still can't get the point!!! first: why sometimes i measure an elapsed time 8us, while i used a delay of 10us?! second: why do i receive big difference in time measurement between elapsed time while execution the pulseInLong function and its return duration measurement!?
    – absi
    Commented Aug 28, 2020 at 2:19
  • Go read the documentation on delayMicroseconds. It clearly states that the resolution of that function is 4us.
    – Delta_G
    Commented Aug 28, 2020 at 3:41
  • Just to add my two cents. Perhaps the digitalWriteFast library might come handy for this time-critical application. I normally use it instead of the default function and it certainly saves a bit of time Commented Sep 19, 2021 at 2:02

2 Answers 2

1

I see at least three reasons for the behavior you notice:

  1. micros() has a resolution of 4 µs. If you could call it at a period fixed to exactly 10 µs, you would see the time deltas alternate between 8 and 12 µs. But then micros() takes some time to execute, so if you use it to time a function that takes 10 µs to execute, you will read 12 µs more often than 8.
  2. There is a timer interrupt firing every 1024 µs. Any process that gets interrupted will show an execution time longer than normal. This is the likely cause of digitalWrite() taking occasionally a lot longer than usual.
  3. pulseIn() waits for the start of the pulse before it starts to measure its duration. Its execution time can then be significantly longer than the pulse duration it reports.

i expected maybe due to some instruction cycles or unprecise clock.

The same clock is used for sequencing the CPU instructions and for timing them. So the clock precision has no effect on the timings you measure.

Edit: There is an extra issue here, which is the overflow of arr[6]. The execution time of pulseInLong() may be something like 138,424 µs. Since an int on the Uno is 16 bits, this value wraps modulo 216 to 7,352, which is the value shown in the first line of the output.

4
  • Dear @Edger Bonet and other Engineeries please concentrate with me little bit..
    – absi
    Commented Aug 28, 2020 at 20:13
  • @absi: What do you mean? Commented Aug 28, 2020 at 20:18
  • #3) The point number 3: regarding pulseInLong returned time and execution time: the time returned by the function is what i listed in the timing table under duration, where the execution time is listed under pulseIn at the timing table. as you can see the execution time is much less than the returned measured time for the pulse, and that is very strange??!! so please someone try to explain
    – absi
    Commented Aug 28, 2020 at 20:38
  • @absi: Oh, I missed that. See amended answer. Commented Aug 28, 2020 at 21:08
0

Why do I receive the big difference in time measurement between elapsed time while execution the pulseInLong function and its return duration measurement?

The answer lies in the choice of the way it is implemented. The delay function itself is helpful but the accuracy is not great when precision is needed. Here is the official note from the site:

  1. This function works very accurately in the range of 3 microseconds and up. We cannot assure that delayMicroseconds will perform precisely for smaller delay-times.
  2. As of Arduino 0018, delayMicroseconds() no longer disables interrupts

If you want to really be precise, I recommend to use hardware timers. I believe it will suffice. to know more about using hardware timers you can refer to

https://learn.adafruit.com/multi-tasking-the-arduino-part-2/timers

https://maker.pro/arduino/projects/timer-interrupts-improve-your-arduino-programming-skills

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.