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();
}
asked Aug 28, 2020 at 0:10
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. 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. 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!? Commented Aug 28, 2020 at 2:19
  • Go read the documentation on delayMicroseconds. It clearly states that the resolution of that function is 4us. 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.

answered Aug 28, 2020 at 8:53
4
  • Dear @Edger Bonet and other Engineeries please concentrate with me little bit.. 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 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

answered Aug 28, 2020 at 5:50

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.