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();
}
-
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– Delta_G08/28/2020 01:47:50Commented 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– Delta_G08/28/2020 01:48:57Commented 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– absi08/28/2020 02:19:49Commented 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– Delta_G08/28/2020 03:41:35Commented 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 timeDaniel Melendrez– Daniel Melendrez09/19/2021 02:02:34Commented Sep 19, 2021 at 2:02
2 Answers 2
I see at least three reasons for the behavior you notice:
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 thenmicros()
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.- 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. 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.
-
Dear @Edger Bonet and other Engineeries please concentrate with me little bit..absi– absi08/28/2020 20:13:54Commented Aug 28, 2020 at 20:13
-
@absi: What do you mean?Edgar Bonet– Edgar Bonet08/28/2020 20:18:05Commented 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 explainabsi– absi08/28/2020 20:38:12Commented Aug 28, 2020 at 20:38
-
@absi: Oh, I missed that. See amended answer.Edgar Bonet– Edgar Bonet08/28/2020 21:08:37Commented Aug 28, 2020 at 21:08
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:
- 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.
- 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
Explore related questions
See similar questions with these tags.