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.
Edit: more about being non-blocking.
There is normally no reason for you to use delay() at all in your
program. The only reason for this function to exist is to help complete
beginners write their first blink-the-LED program. As soon as you start
writing anything non trivial, you should ban it from your vocabulary.
The Blink Without Delay tutorial is here precisely to teach you how to
get rid of delay() by using millis().
In this particular case, however, the drawback of delay() may not be
too severe: if the alarm is sounding and you delay a tone change, you
may hear it as a glitch that breaks the rhythm of the sound. If the
delay is short enough, maybe up to 10 ms or so, you are unlikely to
notice it. Longer delays will be noticeable, and it's up to you to
decide whether you find them annoying or not.
It is possible to ensure a very steady rhythm despite the delays by
using interrupts, but this will cost you your 16-bit timer. Or you could
write your own implementation of tone() that does both the pin
toggling and the tone changes using a single timer. Any such option will
require you to learn about low-level timer
programming, which is significantly
more demanding than learning to use millis().
while (alarmOn)loop that can unsetalarmOn: ifalarmOnis initiallytrueyou have an infinite loop.