[solved] Not working tone() inside function wakeup after sleep

Hello! I can’t understand one thing.
Please look at the code:

#include <avr/sleep.h>

void tosleep() {
 Serial.print("tosleep");
 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 sleep_enable();
 sleep_bod_disable();
 sleep_cpu();
}

void alarm() {
  tone(10, 100); //pin 10, 100 hz
  delay(1000);
  noTone(10); //pin 10
}

void setup () 
{
  attachInterrupt(1, wakeup, FALLING); // interrupt 1 (PIN3 for ProMini) => function wakeup
  Serial.begin(9600);
}

void wakeup () { // disable sleep
  sleep_disable();
  alarm ();
  Serial.print("Wakeup!");
}

void loop () {
 delay(3000);
 tosleep ();
}

When i click button (PIN 3) Arduino wakes up as it should and perform the function “wakeup” (i see in the Port Monitor “Wakeup”), but there is no sound from the piezo! I checked, alarm() function is in fact performed, but no sound.
If I move this:

alarm ();

from wakeup() to loop() there is sound.

In some sketches I’ve seen that in the waking function people perform only one thing: change some variable to true and then in the loop() they check this variable and perform the desired action. I can also do so, but I really want to understand the reason.

Hi,

Not certain, but it looks like there could be an issue with the ISR calling a function that contains a blocking delay of a full second. You also serial print from within the ISR. A google search on that subject will turn up many responses.

best,
Michael

Plain and simple. You are violating the conditions within an Interrupt Routine. Actually, I wonder why the Serial.print is firing at all.

Interrupt routines are, by nature, supposed to execute extremely fast because they are literally “interrupting” normal operations. You should not do lengthy processing within the Routine itself. Usually one sets a flag and does the execution once “normal” program execution has resumed (after the Interrupt Service Routine finishes!).

As you say that at least part of it works, I suspect the Compiler is trying to compensate. You really Need to Change the programming and remain within the design limitations of an interrupt service Routine for the program to work reliably.

Thank you! I understood.
Rewrote code:

#include <avr/sleep.h>

byte alarmstatus;

void tosleep() {
 Serial.print("tosleep");
 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 sleep_enable();
 sleep_bod_disable();
 sleep_cpu();
}

void alarm() {
  tone(10, 100);
  delay(1000);
  noTone(10);
}

void setup () 
{
  attachInterrupt(1, wakeup, FALLING);
  Serial.begin(9600);
}

void wakeup () {
alarmstatus = 1;
// now go to loop
}

void loop () {
if (alarmstatus) {
sleep_disable();
alarm ();
Serial.print("Wakeup!");
alarmstatus = 0;
} 
 delay(3000);
 tosleep ();
}

Works good :slight_smile: