Unexpect results using tone()

I am trying to run a simple program that sends data to a 595 register and a buzzer. One of my loops runs without an issue, but the other refuses to run at all. It is caused by the buzzer bool, on the tone() line of the code. The declared variable and setup is the same for both programs:

const int latchPin = 8;
const int clockPin = 12;
const int dataPin = 10;
const int buzzerpin = 4;

int loopdelay = 50;
bool buzzer = 0;


void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(buzzerpin, OUTPUT);
}

This loop runs without a problem with the buzzer true or false:

  for (int numberToDisplay = 1; numberToDisplay < 128; numberToDisplay *= 2) {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, numberToDisplay);
    digitalWrite(latchPin, HIGH);
    delay(loopdelay);
  }
  
  tone(buzzerpin, 500 * buzzer, 40);   //This runs fine when buzzer is 0

  for (int numberToDisplay = 128; numberToDisplay > 1; numberToDisplay = numberToDisplay /= 2) {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, numberToDisplay);
    digitalWrite(latchPin, HIGH);
    delay(loopdelay);
  }

  tone(buzzerpin, 500 * buzzer, 40);  //This runs fine when buzzer is 0

But whenever I place this code in the loop, it refuses to run (when buzzer is set to false). If it's true it will run without any issues:

  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, random(256));
  digitalWrite(latchPin, HIGH);
  tone(buzzerpin, 500 * buzzer, 40);  //This does not work when buzzer is 0. Refuses to run, even the 3 lines of code before
  delay(loopdelay);

Use another pin (not 0 or 1).

If you take a look in Tone.cpp, you'll see the variations on this line of code all throughout the tone() function:

ocr = F_CPU / frequency / 2 - 1;

So with buzzer set to 0, you're trying to divide by 0. Unexpected results are to be expected in that situation.

I tried a couple different pins instead of 11, but no luck, still same behavior.

have you tried by honouring the truth type and not do math with it?

tone(buzzerpin, buzzer ? 500 : 0, 40);   

or better

if (buzzer) tone(buzzerpin, 500, 40);   

Here is a test in Wokwi

click to see the code
const uint8_t dataPin = 10;
const uint8_t clockPin = 12;
const uint8_t latchPin = 8;

const uint8_t buzzerPin = 4;

uint8_t counter = 0;

void setup() {
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
}

void loop() {
  digitalWrite(latchPin, HIGH);
  shiftOut(dataPin, clockPin, MSBFIRST, counter);
  digitalWrite(latchPin, LOW);
  tone(buzzerPin, 150+counter, 20);
  counter++;
  delay(80);
}

Why? The SPI library is not used.

Play the tone for a whole 40 ms? That is 1/25th of a second, a quick yip. 200 might be better.

Is pin 10 in a PORT that is used by a timer, and is the timer used by tone?

Touche.

I respect your knowledge in this forum (and many other, friend and foe), and I am okay with being corrected (after biscuits and tea). I thought I read pin 10 (Uno and Nano) shares something with ?tone? and/or ?millis?... and I routinely forget. I hope to keep learning... as I am a sieve of information.

Okay I'm a little confused now. I tried this suggestion by J-M-L:

tone(buzzerpin, buzzer ? 500 : 0, 40);

and that worked. I reverted back to what I originally had and now it has starting working (both loops run as intended with the original code), so I'm not sure if it was just a bug. I was just confused why it was working in one method but the other it didn't.

And I think you may be right if tone() changes the timer.
Good spot!

You know my code. I'd rather bit-bang than use PWM. I'm weird like that.

What does tone() do with frequency 0 again?

perhaps tone(buzzerpin, buzzer ? 500 : 1, 40);

And still, does a 40 ms 500Hz tone make a peep or a yip or do they come so fast it's more of a warble?

It was just to have a bool to quickly turn off the buzzer when I called that method. I found that when I told it to play a tone of 0hz nothing would actually be played, effectively disabling it. I guess an if statement outside of the tone call is probably better but I was just experimenting.

40ms just gives a short chirp.

As you found out it’s better to use Boolean anyway for what they are meant too : conditionals not maths :)

But turning values to T/F.... 0 is false and not 0 is true.

Suppose I use bits in a byte to store T/F. I can mask bits out and get a bool by (( expression != 0 ) ? true : false ), can't I?

Delta_G got a heart for saving me looking up noTone(). I wasn't sure.

This would be your bool

(A comparison leads to a truth value)

that's how I code but not everything I code is kosher

:wink:

better safe than sorry