Why does my ultrasound range-finder stop loop() working?

I am using an Arduino Uno, and have wired up a ping rangefinder (with 4 pins).
I have written the following script for it:

const int inping = 6;
const int outping = 7;


void setup() {
  pinMode(11,OUTPUT);
  pinMode(3,OUTPUT);
  Serial.begin(9600);
  pinMode(inping,INPUT);
  pinMode(outping,OUTPUT);
}

void loop() {
  long duration, inches, cm;

  digitalWrite(outping, LOW);
  delayMicroseconds(2);
  digitalWrite(outping, HIGH);
  delayMicroseconds(5);
  digitalWrite(outping, LOW);
  
  duration = pulseIn(inping, HIGH);

  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);

  /*if (cm < 60) {
    alarm(); 
  }*/
  Serial.print(cm);
  Serial.print(" ");
  delay(10);
}

long microsecondsToInches(long microseconds) {
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds) {
  return microseconds / 29 / 2;
}

void alarm() {
  tone(11,291,1000);
  for (int i = 0; i < 1000; i++) {
    digitalWrite(3,HIGH);
    delay(1);
    digitalWrite(3,LOW);
  }
}

The problem is only if the rangefinder doesn't recieve an echo (say it's out of range) and it returns 0. However after this point, in the Serial Monitor, it won't emmit any more pulses, and loop runs incredibly slowly, and you just get a series of 0s with very long pauses in between. The only way to get it to run normally again is to re-upload the code, which is very annoying (pressing the reset button doesn't work, neither does disconnecting and reconnecting it to the power).

Why does this happen?

PulseIn blocks and waits until it sees the pulse. If the pulse isn't coming then it will wait for some time before it times out and returns zero. So when nothing is there you're spending most of your time in the pulseIn function waiting for a pulse that isn't coming. If you want it to remain responsive to other thing then ditch the pulseIn and watch for the pulse in the loop code and use millis between when you send the ping and receive the pulse to get your time.

Makes sense :slight_smile:

but the range finder just returns 0 if it doesn't get a pulse, so why does it stop the whole thing from working unless I re-upload the script?

Also, if it just times out if it doesn't get the pulse in, why does it never emmit a pulse the next time it runs loop()?

Okay, so it's pulse in that returns 0 if it recieves no pulse :slight_smile:

But if pulse-in times out, why does that stop it from working next time loop() is called? it will keep on returning 0 from that point even if there is something right in front of it

The pulseIn function will accept a third parameter for timeout. Try adding a 20000 microsecond timeout to your pulseIn.

duration = pulseIn(inping, HIGH, 20000);

I connected a HCSR04 rangefinder to my Uno as in your code and ran your code as posted. I get a constant stream of ranges with no lock ups. 0 for out of range and good numbers when something (my hand) is in range. So I don't think it is your code. I don't know what would cause your problem, but I would suspect the rangefinder itself. I have had bad units before.

Did you use the third ardument for pulseIn() like you just said? or did you run the code as it was?

I ran the code as it was posted without the timeout parameter.

const int inping = 6;
const int outping = 7;


void setup() {
  pinMode(11,OUTPUT);
  pinMode(3,OUTPUT);
  Serial.begin(9600);
  pinMode(inping,INPUT);
  pinMode(outping,OUTPUT);
}

void loop() {
  long duration, inches, cm;

  digitalWrite(outping, LOW);
  delayMicroseconds(2);
  digitalWrite(outping, HIGH);
  delayMicroseconds(5);
  digitalWrite(outping, LOW);
 
  duration = pulseIn(inping, HIGH, 20000);

  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);

  /*if (cm < 60) {
    alarm();
  }*/
  Serial.print(cm);
  Serial.print(" ");
  delay(10);
}

long microsecondsToInches(long microseconds) {
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds) {
  return microseconds / 29 / 2;
}

void alarm() {
  tone(11,291,1000);
  for (int i = 0; i < 1000; i++) {
    digitalWrite(3,HIGH);
    delay(1);
    digitalWrite(3,LOW);
  }
}