Skip to main content
3 of 4
+ non-blocking implementation.
Edgar Bonet
  • 45.2k
  • 4
  • 42
  • 81

You can just have a variable that remembers whether the alarm is supposed to be on or off. Let's call it alarm_on. Then:

bool alarm_on;
static void start_alarm() { alarm_on = true; }
static void  stop_alarm() { noTone(); alarm_on = false; }

void loop()
{
    if (alarm_on) alarm();
    if (some_condition()) start_alarm();
    if (some_other_condition()) stop_alarm();
}

For a better approach that allows you to sound the alarm without blocking the whole program, see the Blink Without Delay Arduino tutorial.

Edit: I just wrote (but did not test) a non-blocking version of this alarm, based on a state machine and the timing technique from the Blink Without Delay tutorial. Here it is, as a class:

class TwoToneAlarm {
public:
    static const uint16_t HIGH_FREQ = 3300;
    static const uint16_t LOW_FREQ  = 3000;
    static const uint16_t TONE_DURATION = 200;

    TwoToneAlarm(uint8_t output_pin)
    : state(OFF), pin(output_pin) {}

    // Start the alarm.
    void start()
    {
        tone(pin, HIGH_FREQ);
        state = HIGH_TONE;
        last_tone_change = millis();
    }

    // Stop the alarm.
    void stop()
    {
        noTone(pin);
        state = OFF;
    }

    // Call this periodically to handle the tone changes.
    void update()
    {
        if (state == OFF) return;
        if (millis() - last_tone_change >= TONE_DURATION) {
            switch (state) {
                case HIGH_TONE:
                    tone(pin, LOW_FREQ);
                    state = LOW_TONE;
                    break;
                case LOW_TONE:
                    tone(pin, HIGH_FREQ);
                    state = HIGH_TONE;
                    break;
                default:
                    break;
            }
            last_tone_change += TONE_DURATION;
        }
    }

private:
    enum { OFF, HIGH_TONE, LOW_TONE } state;
    uint16_t last_tone_change;
    uint8_t pin;
};

It could be used like this:

TwoToneAlarm alarm(8);

void loop()
{
    if (some_scary_condition()) alarm.start();
    if (some_other_condition()) alarm.stop();
    alarm.update();
}

Note that the whole program must be non-blocking (delay()-free), otherwise the tone changes will not be done on time.

Edgar Bonet
  • 45.2k
  • 4
  • 42
  • 81