Buzzer interfering with Ultrasonic proximity sensor

I’m making a device that shows on an LCD screen the distance measured by a proximity sensor, and added a buzzer to beep faster and faster based on the distance. Just making the proof of concept i seem to have inhibited the work of the sensor.

I tried eliminating the timing aspect altogether and just beeping at different tones, but still the problem persists: that is that sometimes the readings become wildly inaccurate for a fraction of a second, or they refuse to update for a second or so.

My code:

#include <LiquidCrystal.h>
#include "pitches.h"

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// The pin number of the sensor's output:
const int pingPin = 10;

// Define the pin the Speaker is hooked up to
const int SPK_PIN = 8;

long duration, inches, cm;

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
}

void loop() {
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH pulse
  // whose duration is the time (in microseconds) from the sending of the ping
  // to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);
  
  tone(SPK_PIN, getTone((int)(cm*(89.0/500.0))));

  lcd.setCursor(0, 0);
  
  if (cm >= 500){
    lcd.print("Out of range");
    lcd.setCursor(0, 1);
    lcd.print("Out of range");
    Serial.println("Out of range");
  } else {
    Serial.print(inches);
    lcd.print(inches);
  
    Serial.print(" in,");
    lcd.print(" in,       ");

    lcd.setCursor(0, 1);
  
    Serial.print(cm);
    lcd.print(cm);
  
    Serial.print(" cm");
    lcd.print(" cm        ");
  
    Serial.println();
  }

  //delay(cm);
  delay(100);
}

long microsecondsToInches(long microseconds) {
  // According to Parallax's datasheet for the PING))), there are 73.746
  // microseconds per inch (i.e. sound travels at 1130 feet per second).
  // This gives the distance travelled by the ping, outbound and return,
  // so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the object we
  // take half of the distance travelled.
  return microseconds / 29 / 2;
}

pitches.h is just a long list of defenitions for notes, and this function:

float getTone(int index){
  int i = index % 89;
  if (i == 0) i = 89;
  if (i == 1) return 31;
  return 29.171 * exp(0.0577*i);
}

The problem goes away when i remove all the sound making code. Any reason for this? Workarounds?

I'd first restructure the code to avoid the 100 mS delay:

static unsigned long lastLoopAtMs = 0 ;
unsigned long mS = millis() ;
if (mS - lastLoopAtMs > 100 ) {
   lastLoopAtMs = mS ;

   // your code here
}

If that doesnt help, try putting

tone( SPK_PIN, 262 ) ;  // middle C

in setup() and commenting out the tone() statement in the loop() to see if there is an incompatibility between tone(), pulseIn() etc.

You could also try optimising your getTone() function which looks quite heavy.

Do you really need distance in both centimeters and inches? Pulling one of those out would give a small optimization on time.

Thanks for the replies: the loop optimization didn't change the problem, and neither did outsourcing the tone to void setup().

I tried playing a constant C4 tone (called in setup) and then physically unplugging the buzzer and plugging it back in. i found that even though the tone was still being played by the Arduino, unplugging the buzzer fixed the issue, and i thought that it may be the actual sound that's playing that's interfering with the Ultrasonic (key word "sonic"; i only just realized that) sensor.

I'm planning to use this in a project where the sensor will be far away from the buzzer, so this might not be an issue for this particular project if that is the case.

To experiment further, i used a second arduino to play a middle C at 2 second intervals, and put it right next to the sensor. turns out, that doesn't interfere with the sensor at all! So its the buzzer playing on the same arduino that causes the issue somehow.

I don't know where to go from here, has anyone else dealt with square wave issues on and arduino before?

Just kidding! i slapped an LED on the device and integrated the example code for fading an LED in and out at regular intervals using analogWrite(). No buzzer at all, and the issue repeated itself! The sensor is totally out of whack when the LED is not a full brightness, so it looks like PWM of any kind running somewhere else on the arduino totally interferes with pulsein().

I guess i just wont have a buzzer on this project? ¯_(ツ)_/¯

It shouldn’t. Post a circuit schematic. Please not fritzing, just draw one and take a picture.

The NewPing library doesn't use pulseIn - give that try?

Soounds like it could be a psu problem - try adding some decoupling capacitors, or ( just maybe ) the buzzer harmonics are reaching up into the ultrasonic region. Connect it all up and put your fingere over the buzzer - does it work then?

Allan