How to properly control pitch of buzzer with potentiometer?

I wish to control the pitch of a buzzer with a potentiometer.
In order to accomplish that, is it sufficient to simply map the digital potentiometer values (0-4095) to the desired frequency range (for instance 4 -16 kHz). Using a formula such as:
return int(MIN_FREQUENCY + (pot_value / 4095) * (MAX_FREQUENCY - MIN_FREQUENCY)). I would then set the frequency of my buzzer: buzzer.setFrequency()

Apart from setting the calculated frequency dynamically, would I also have to change the duty cycle dynamically in some way? Is the duty cycle connected to the human hearing curve (frequencies) in some way?

Thanks

Why don't you just try it and see?

The tone() function is a square wav (50% duty cycle). To change that, you'd have to use a variation of the blink example or the blink without delay example. And whatever processor cycles used to read the pot, or do other things, will interfere with the timing to some extent.

50% duty cycle gives the highest volume and the least harmonics (for a square wave or pulse). As the pulse gets wider or narrower (at the same frequency) it gets quieter and the harmonics become relatively stronger so the character of the tone changes.

Ensure the "buzzer" is passive. If 5vdc and GND are applied, and only a "click" is made, your buzzer is passive. If you have a tone, your buzzer is active, and will not work for this project.

The passive buzzer only needs a value, ranging from 31 to 1024. You could do "math" to give the buzzer a value, or read and "map()" a potentiometer value... or create a moving value... this simulation oscillates between 700 and 800 Hz.

sketch.ino for wokwi.com
unsigned long ledTimer, ledInterval = 250; // led interval - 250 = fast wigwag
unsigned long sirenTimer, sirenInterval = 50; // siren interval, 50 = fast warble

byte Led1Pin = 2, Led2Pin = 3, BuzzerPin = 4; // pins for LEDs and buzzer

int count = 1; // siren cycle counter

// int sirenCycles = 10; // larger numbers for testing siren
int sirenCycles = 20; // one full cycle (2 directions)
int sirenTone = 700, sirenDirection = 10; //

bool state = 0, led = 1, siren = 1; // enter sketch led/siren ON

void setup() {
  Serial.begin(115200);
  pinMode(Led1Pin, OUTPUT);
  pinMode(Led2Pin, OUTPUT);
  pinMode(BuzzerPin, OUTPUT);
}

void loop() {
  if (led) // if the "led" flag is set
    ledOn(); // call the LED function
  if (siren) // if the "led" flag is set
    sirenOn(); // call the siren function
}

void ledOn() {
  if (millis() - ledTimer > ledInterval) { // time difference = ledInterval?
    ledTimer = millis(); // reset ledTimer
    state = !state; // on/off/on/off...

    if (state) { // when state is HIGH
      Serial.print("Siren cycle ");
      Serial.print(count);
      Serial.print(" RED ");
    }
    if (!state) { // when state is LOW
      Serial.println("BLU ");
    }

    // alternate on/off state of LEDs
    digitalWrite(Led1Pin, !digitalRead(Led1Pin)); // state
    digitalWrite(Led2Pin, !digitalRead(Led1Pin)); // opposite state
  }
}

void sirenOn() {
  if (millis() - sirenTimer > sirenInterval) { // time difference > interval?
    sirenTimer = millis(); // reset timer

    sirenTone += sirenDirection; // change frequency up/down
    tone(BuzzerPin, sirenTone); // make the tone

    if (sirenTone < 700 || sirenTone > 800) { // frequency range
      sirenDirection = -sirenDirection; // change frequency direction
      if (count == sirenCycles) { // make two cycles (1) up (2) down
        sirenOff(); // turn off siren
      }
      count++;
    }
  }
}

void sirenOff() {
  Serial.println("\nSiren OFF");
  digitalWrite(Led1Pin, LOW); // turn off red LED
  digitalWrite(Led2Pin, LOW); // turn off blu LED
  noTone(BuzzerPin); // turn off siren
  siren = 0; // flag to stop going to siren function
  led = 0; // flag to stop going to led function
}

diagram.json for wokwi.com
{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "nano", "top": -4.8, "left": -0.5, "attrs": {} },
    {
      "type": "wokwi-buzzer",
      "id": "bz1",
      "top": -98.7,
      "left": 138.9,
      "rotate": 90,
      "attrs": { "volume": "0.1" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -49.2,
      "left": 131.4,
      "rotate": 90,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": -49.2,
      "left": 59,
      "rotate": 270,
      "attrs": { "color": "blue", "flip": "1" }
    }
  ],
  "connections": [
    [ "nano:GND.2", "led1:C", "black", [ "v0" ] ],
    [ "nano:2", "led1:A", "green", [ "v0" ] ],
    [ "nano:3", "led2:A", "green", [ "v0" ] ],
    [ "nano:GND.2", "led2:C", "black", [ "v0" ] ],
    [ "nano:GND.2", "bz1:1", "black", [ "v0" ] ],
    [ "nano:4", "bz1:2", "green", [ "v0" ] ]
  ],
  "dependencies": {}
}

I changed this

    if (sirenTone < 100 || sirenTone > 3600) { // frequency range

and got a wider range of frequencies. Then I looked, an upper limit is implied here, the last of a list giving frequencies corresponding to notes:

NOTE_DS8	4978

a7

I should have noticed I was looking at the wrong ADC (10 bit) of the Nano/Uno... and OP mentioned 4096.

The simulation was "US cop" style.

1 Like

I assume the buzzer I have is active (When connecting it to voltage and ground, it produces a sound).

Are active buzzers even capable of specific frequencies? When using freq() and duty() function of PWM() object (esp32), even frequencies of 20000 hz will produce an audible sound (which doesn't align with how human hearing should work).

So is there any workaround I can output specific frequencies by using an active buzzer?

Been answered already.