Ash
Ash

Reputation: 9351

Creating an oscillating tone using Arduino, ATTiny85 and a simple buzzer

First a bit of background. I am attempting to make an LED glow and a buzzer produce a tone that sweeps smoothly up and down in frequency, like an air raid siren. I am using an Arduino Uno, connected to an ATTiny85 chip operating at 8hz clock speed. An SPDN contact switch is used to provide input on 4, while 0 and 1 go out to the positive legs of the buzzer and LED respectively. Suitable resistors are being used to limit current, which is 5v from the Arduino board.

Now, my problem. I can produce a constant tone at any frequency I like. I can produce a tone that goes back and forth between two tones like a UK police siren (Dee-Daa-Dee-Daa etc) but I am unable to generate a smooth transition between two tones. The LED works as expected.

What I actually observe is a single tone that does not vary. Once or twice I've managed to produce a tone that varies, but randomly within the given range rather than smoothly.

I am not using the tone() Arduino command and would prefer not to, as it is not best suited for what I am trying to accomplish.

Here is my code:

const float pi2 = 6.28318530717;
const int buzzer = 0;
const int light = 1;
const int button = 4;

// Set up the pins as input and output
void setup() {
  pinMode(buzzer, OUTPUT);
  pinMode(light, OUTPUT);
  pinMode(button, INPUT);
}

bool buzzerState = LOW;
float nextFlip = 0;

// Generates a sine wave for the given uptime, with a period and offset (in milliseconds).
float sineWave(float uptime, float period, float offset, float minimum, float maximum) {
  float s = sin(((uptime + offset) * pi2) / period);
  // Normalise the result between minimum and maximum
  return (s + 1) / 2 * (maximum - minimum) + minimum;
}

// Returns the time between buzzer inversions based on a given system uptime.
float frequency(float uptime) {
  return sineWave(uptime, 5000, 0, 1, 10);
}

// Main loop
void loop() {

  // Check button state and turn the light on or off
  bool buttonDown = digitalRead(button);
  digitalWrite(light, buttonDown);

  // Check to see if it's time for the next buzzer inversion
  float m = micros();
  if (!buttonDown || m < nextFlip) return;

  // Get the inverse of the current buzzer state
  if (buzzerState == HIGH) {
    buzzerState = LOW;
  } else {
    buzzerState = HIGH;
  }

  // Write the new buzzer state
  digitalWrite(buzzer, buzzerState);

  // Decide when the next inversion will occur
  nextFlip = m + frequency(m);
}

Upvotes: 1

Views: 1672

Answers (1)

Ash
Ash

Reputation: 9351

Silly mistake! I finally noticed: I'm reading micros() where I meant to read millis() - in other words, it was oscillating, just a thousand times faster than I intended it to! Multiplying all values up by a factor of 1000 in the sine wave function produced a lovely oscillation.

Upvotes: 3

Related Questions