NewPing / Tone conflict

I'm new to arduino, so be kind in the response.

I have a SainSmart HC-SR04 that I have successfully implemented with the NewPing library. The next step is to use the distance to generate a tone based on distance. When I compile the following code, I get a "Fail to Compile" error. If I comment out everything but the tone command, it works (with a value in the tone variable). Conversely, if I comment out everything but the ping code, it works. The final straw was to comment out everything and bring in one line of code at a time. With the tone and the #include <newping.g>, I got a fail to compile, when either of those commands in place and the other commented out works. Is there some kind of conflict between the tone() routine and the newping library?

#include <NewPing.h>
NewPing sonar(2,3,300);
unsigned int pingage;
unsigned int toneage;
void setup() {
Serial.begin(9600);
pingage = 500;
}
void loop()
{
** pingage = sonar.ping() / US_ROUNDTRIP_CM;**
** Serial.print("Ping: ");**
** Serial.print(pingage);**
** Serial.println("cm");**
__ toneage = pingage * 10;__
** tone(10,toneage);**
** delay(100);**
}

Looks like both libraries define an ISR for "__vector_7".

Vector 7 seems to be the Watchdog Timer vector?

NewPing uses the Timer 2 Compare A interrupt on an UNO. That is "Vector 8" but vectors are numbered from 1 instead of 0 so "__vector_7" might mean "the vector at offset 7" which is the 8th vector.

Tone.cpp (in hardware/arduino/cores/arduino) also uses the Timer 2 Compare A interrupt on an UNO.

If you had a Leonardo you'd be OK: NewPing uses Timer 4 and Tone uses Timer 3.

Since Tone is built-in and NewPing is third-party you could change NewPing to use another timer. Or you could abandon NewPing and get the pulse length with pulseIn():

const int TriggerPin = 2;
const int EchoPin = 3;

void setup() {
   pinMode(TriggerPin, OUTPUT);
   pinMode(EchoPin, INPUT);
}

void loop() {
   unsigned long duration;
   int distance;

  digitalWrite(TriggerPin, HIGH);
  delay(1);
  digitalWrite(TriggerPin, LOW);

  duration = pulseIn(EchoPin, HIGH, 5700);  // Timeout if distance > 100 cm

  distance = duration / 57;  // Divide by round-trip microseconds per cm to get cm

  if (distance >= 200 || distance <= 0) {
    Serial.println("Out of range");
  }
}

I made a small tone library that doesn't use interrupts:

Thanks, John. I'll try that. I thought the conflict was in the libraries, but didn't know how to go about debugging. Now I have a little better understanding (I think).

Nick, it looks like your library wants to go to a Mac; it didn't want to copy to my library.

Let me give this a roll and see what happens. Thanks!

What do you mean "it didn't want to copy"? What it wants doesn't enter into it! Make it copy.

Anyway, the library is so small I reproduce it below.

TonePlayer.h :

/*
 
 Play tones with hardware timers
 Author: Nick Gammon
 Date:   1 April 2013
 
  */

#include <Arduino.h>

class TonePlayer
  {
  // addresses of output ports - NULL if not applicable
  volatile byte * const timerRegA_;
  volatile byte * const timerRegB_;
  volatile byte * const timerOCRH_;
  volatile byte * const timerOCRL_;
  volatile byte * const timerTCNTH_;
  volatile byte * const timerTCNTL_;
  
  public:
    // constructor
    TonePlayer (
          // ports
          volatile byte & timerRegA, 
          volatile byte & timerRegB, 
          volatile byte & timerOCRH,
          volatile byte & timerOCRL, 
          volatile byte & timerTCNTH, 
          volatile byte & timerTCNTL)
       : 
         timerRegA_  (&timerRegA), 
         timerRegB_  (&timerRegB),
         timerOCRH_  (&timerOCRH), 
         timerOCRL_  (&timerOCRL), 
         timerTCNTH_ (&timerTCNTH), 
         timerTCNTL_ (&timerTCNTH)
  { }
    
    void tone (const unsigned int Hz);
    void noTone ();
    
  };  // end of TonePlayer

TonePlayer.cpp :

/*
 
 Play tones with hardware timers
 Author: Nick Gammon
 Date:   1 April 2013
 
 Example of use:
 
 #include <TonePlayer.h>

 ...
 
 TonePlayer tone1 (TCCR1A, TCCR1B, OCR1AH, OCR1AL, TCNT1H, TCNT1L);  // pin D9 (Uno), D11 (Mega)

 or, on the Mega 2560:

 TonePlayer tone3 (TCCR3A, TCCR3B, OCR3AH, OCR3AL, TCNT3H, TCNT3L);  // pin D5
 TonePlayer tone4 (TCCR4A, TCCR4B, OCR4AH, OCR4AL, TCNT4H, TCNT4L);  // pin D6
 TonePlayer tone5 (TCCR5A, TCCR5B, OCR5AH, OCR5AL, TCNT5H, TCNT5L);  // pin D46

 ...
 
 pinMode (9, OUTPUT);  // D9 on Uno, D11 on Mega 2560
 tone1.tone (440);     // play 440 Hz
 delay (500);          // wait half a second
 tone1.noTone ();      // stop playing

 or, on the Mega 2560:
 
 pinMode (46, OUTPUT);  
 tone5.tone (440);

*/

#include <TonePlayer.h>


void TonePlayer::tone (const unsigned int Hz)
{
  // it takes two toggles for one "cycle"
  unsigned long ocr = F_CPU / Hz / 2;
  byte prescaler = _BV (CS10);  // start with prescaler of 1  (bits are the same for all timers)
  
  // too large? prescale it
  if (ocr > 0xFFFF)
    {
    prescaler |= _BV (CS11);    // now prescaler of 64
    ocr /= 64;
    }
  
  // stop timer
  *timerRegA_ = 0;
  *timerRegB_ = 0;
  
  // reset counter
  *timerTCNTH_ = 0;
  *timerTCNTL_ = 0;
  
  // what to count up to
  *timerOCRH_ = highByte (ocr);
  *timerOCRL_ = lowByte (ocr);
  
  *timerRegA_ = _BV (COM1A0);             // toggle output pin
  *timerRegB_ = _BV (WGM12) | prescaler;  // CTC
  }  // end of TonePlayer::tone

void TonePlayer::noTone ()
  {
  // stop timer
  *timerRegA_ = 0;
  *timerRegB_ = 0;  
  } // end of TonePlayer::noTone

Make a folder inside "libraries" called TonePlayer. Put both files inside it. Restart the IDE.


License removed for brevity. See original download for the license details (basically you can use it however you want).