0

I'm curently playing with sleep modes. When I push the button, melody starts, push again go to deep down sleep and save 3v battery, push again wake up and melody starts again. But seems like it doesn't completely goes to sleep and can't wake up.

#include <OneButton.h>
#include <avr/sleep.h>
#include <avr/power.h>

#define cs6 1109 #define fs5 740 #define d6 1175 #define c6 1047 #define f5 698 #define b5 988 #define e5 659 #define bf5 932 #define ef5 622 #define b4 494 #define g5 784 #define led1 8 #define led2 7

const uint16_t halloween[] PROGMEM = { cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4 };

typedef enum { ACTION_OFF, ACTION_ON } MyActions;

const int buzzer = PA1; unsigned long previousMillis = 0; unsigned long pauseBetweenNotes = 218; int noteDurations = 6; int thisNote=0; int ledState = LOW;

OneButton button(10, true, true);

MyActions nextAction = ACTION_OFF; // no action when starting

void setup() { pinMode(buzzer, OUTPUT); pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); attachInterrupt(digitalPinToInterrupt(10), wakeUpFromSleep, FALLING); button.attachClick(myClickFunction);

}

void melody () {

unsigned long currentMillis = millis();

if (thisNote <= 290 && currentMillis - previousMillis >= pauseBetweenNotes) { previousMillis = currentMillis;

if (ledState == LOW) {

  ledState = HIGH;

  tone(buzzer, pgm_read_word(&amp;halloween[thisNote]), 168);
  pauseBetweenNotes = 167 * 0.65;
  thisNote++;
}

else {

  ledState = LOW;
}
digitalWrite(led1, ledState);
digitalWrite(led2, ledState);

} }

void wakeUpFromSleep() { // Rimuovi l'attivazione dell'interrupt per il pulsante detachInterrupt(digitalPinToInterrupt(10)); sleep_disable(); power_all_enable(); }

void myClickFunction() {

if (nextAction == ACTION_OFF) { nextAction = ACTION_ON; thisNote = 0; pauseBetweenNotes = 0; previousMillis = 0; }

else { nextAction = ACTION_OFF; digitalWrite(led1, LOW); // spegni i led digitalWrite(led2, LOW); noTone(buzzer); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_cpu(); } }

void loop() {

button.tick();

if (nextAction == ACTION_OFF) { wakeUpFromSleep(); }

else if (nextAction == ACTION_ON) { melody(); } }

tommy
  • 29
  • 6
  • When you press the button , the chances are high that, the interrupt is deactivated. You attach the interupt in the setup routine but then detach it with the first "loop" run. Without an active interrupt and after the first button press the MCU sleeps and pressing the button again does nothing. – Peter Paul Kiefer Mar 12 '23 at 21:21
  • So you think I should attach interrupt somewhere else ? – tommy Mar 12 '23 at 22:11
  • attachInterrupt(digitalPinToInterrupt(10), cannot be fully understood without knowing which configuration of which board core you are using. – timemage Mar 12 '23 at 22:27
  • I'm using attiny44a mcu and button pin is attached to PB0 pin – tommy Mar 12 '23 at 23:07
  • That isn't exactly what I asked, but it is relevant information to a correct answer which you should edit into your question. – timemage Mar 14 '23 at 00:35
  • I wrote Attiny44 in my thread title, I should also insert in the text of question? – tommy Mar 16 '23 at 12:46
  • "attiny44" is not "which configuration of which board core you are using". You can at least include "PB0" in your question so someone (not me) can explain to you why attachInterrupt simply won't work with that pin. And why it won't wake with that pin. – timemage Mar 17 '23 at 23:39
  • 1
    According to the datasheet external interrupt are triggered by any pin PCINT[11:0] so i think PB0 is ok for attachInterrupt – tommy Mar 18 '23 at 08:58
  • 1
    I understand your confusion. But, that is not the case. attachInterrupt works with INT# not PCINT#. These are different things. Importantly none of the PCINT will wake your chip from powerdown. – timemage Mar 19 '23 at 20:22
  • ok so the new code will never work, I have to redesign completely..... – tommy Mar 20 '23 at 08:21
  • And for the button pin i have to use PB2 that according datasheet have INT0 – tommy Mar 20 '23 at 08:28
  • 1
    Alright, so I've found another datasheet and this one did mark PCINT as a wake-up source in the table, not just in the statement elsewhere in the sheet. To confirm this isn't just an error, I set up a T44A with CKOUT fuse enabled, verified that stops outputting clock in powerdown mode sleep. Configured PCINT and triggered it with a button and it did wake and resume CKOUT production. So at least with at T44A it's verified to wake with PCINT. The part regarding PCINT and attachInterrupt stands; so you'd need to integrate NicoHood's library for that part. – timemage Mar 27 '23 at 23:50
  • Yes I've used his library and with PB0 seems working for power down – tommy Mar 28 '23 at 06:28

1 Answers1

2

EDIT I've written the following programm. It should provide the requested features.

But for the time being I don't have access to an ATtiny44a so I used a Arduino UNO. I read both data sheets and did not find anything that prevents the program from running on a ATtiny44. So please try it and if it runs you can read the comments in the program to understand what I did to get it running.

I have a very "chirpy" button, so some times the program can not differ whether I clicked twice or the button bounces. I've used long debouncing periods to get rid of that. I've commented it in the code, please check what value works best for you.

Ah, And I've accellerated the the melody a little bit ;-). I like Heavy Metal more than Walzing Matilda style ;-). And I change the programm so that it runs the mellody again and again until you pressed the button again. Your Program stopped ofter playing the melody once.

// This Code is intended to run on an ordinary Arduino Uno
// The original request was to implement it for an ATtiny44a.
// I will document if there are difference to take 
// into consideration. Most of the code should run on a 
// attiny44 as well.

// The purpose of this program is to let the MCU play a melody // started and stopped by clicking a button. The mcu should enter // a enerngy saving sleep mode when the melody stops. // When in sleep mode, pressing a button should wake up the MCU // which then should continue playing the melody.

#include <avr/sleep.h> #include <avr/power.h>

// The button pin must be pin two for Arduino Uno // for a tiny any pin can be used so pin 2 is fine. const int buttonPin = 2; const int buzzerPin = 10; const int led1 = 8; const int led2 = 7;

// Attention!!!!: I use a pull up and a push button // connected to GND. // With this setup pressing the button will pull the pin to GND. // Therefore we read LOW while the button is pressed.
// If the button is HIGH active - that means the button // is connected to VCC - the LOW of the following constant must // be changed to HIGH and the RISING must be changed to FALLEN. #define BUTTON_PRESSED LOW #define INTERRUPT_TRIGGER_METHOD RISING

// I decided to use a very long debounce delay, because I // featured a very "chirpy" button. Feel free to experiment // with this delay. const long debounceDelay = 150L;

// setup for the melody

// define the note pitch values #define cs6 1109 #define fs5 740 #define d6 1175 #define c6 1047 #define f5 698 #define b5 988 #define e5 659 #define bf5 932 #define ef5 622 #define b4 494 #define g5 784

// provide a melody as an array. const uint16_t halloween[] PROGMEM = { cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, cs6, fs5, fs5, cs6, fs5, fs5, cs6, fs5, d6, fs5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, c6, f5, f5, c6, f5, f5, c6, f5, cs6, f5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, b5, e5, e5, b5, e5, e5, b5, e5, c6, e5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, bf5, ef5, ef5, bf5, ef5, ef5, bf5, ef5, b5, ef5, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4, fs5, b4, b4, fs5, b4, b4, fs5, b4, g5, b4 };

//define processing variables for the play functionallity unsigned long previousMillis = 0; unsigned long pauseBetweenNotes = 300; unsigned long lengthOfActiveNote = 300; int noteCounter = 0; boolean toneOn = false;

// handling the play mode // after inserting the battery the melody does not play. // After the user will have pushed and released // the push button, we will start with the melody. volatile boolean playMelody = false; volatile bool playModeChangeRequested = false;

// reading and debouncing the button volatile unsigned long lastDebouncingMillis = 0;

void stopTheMelody() { noTone(buzzerPin); toneOn = false; digitalWrite(led1, toneOn); digitalWrite(led2, toneOn);
}

void startTheMelody() { previousMillis = 0; pauseBetweenNotes = 0; noteCounter = 0; toneOn = false; digitalWrite(led1, toneOn); digitalWrite(led2, toneOn);
}

void melody () { unsigned long currentMillis = millis(); if (! toneOn && (currentMillis - previousMillis) > pauseBetweenNotes) { pauseBetweenNotes = 167 * 0.2; tone(buzzerPin, pgm_read_word(&halloween[noteCounter])); noteCounter++;
if (noteCounter > 290) { // the old program plays the melody only once // with resetting the note counter to 0 // the melody start again and again. noteCounter = 0; } toneOn = true; digitalWrite(led1, toneOn); digitalWrite(led2, toneOn);
previousMillis = currentMillis; } else if(toneOn && (currentMillis - previousMillis) > lengthOfActiveNote) { lengthOfActiveNote = 58; noTone(buzzerPin); toneOn = false; digitalWrite(led1, toneOn); digitalWrite(led2, toneOn);
previousMillis = currentMillis; } }

// This is the interrupt service routine. // It is called every time the button will have been released. void ISR_buttonReleased() { // Here, we know that this ISR is called because, // the button was released.
lastDebouncingMillis = 0L; playModeChangeRequested = true;

if (!playMelody) { // if the interrupt was triggered while the MCU was sleeping // we need to switch off the sleep mode to resume // normal activity. Otherwise the debouncing method does not // work, as it is done by code outside of the ISR. sleep_disable(); power_all_enable(); } }

void setup() { pinMode(buttonPin, INPUT_PULLUP); pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(buzzerPin, OUTPUT);

// paranoia setup playMelody = false; playModeChangeRequested = false; lastDebouncingMillis = 0;

// the interrupt is triggered on rising edge, i.e. // when the button will be released
attachInterrupt( digitalPinToInterrupt(buttonPin), ISR_buttonReleased, INTERRUPT_TRIGGER_METHOD);

// stop melody and sleep stopTheMelody(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_cpu(); }

void loop() { // lastDebouncingMillis will be set to 0 1st) in the // setup routine and 2nd) in the ISR. if (lastDebouncingMillis==0 || digitalRead(buttonPin)==BUTTON_PRESSED) { // Here lies the magic! // We synchronize the ISR, the sleep mode, a long button // press without release and the // button bouncing with this single if statement. lastDebouncingMillis = millis(); }

if (playModeChangeRequested) { unsigned long tempMillis = millis(); if((tempMillis - lastDebouncingMillis) > debounceDelay) {
playModeChangeRequested = false; playMelody = !playMelody; if (!playMelody) { // stop melody and sleep stopTheMelody(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_cpu(); } else { startTheMelody(); } } }

if(playMelody) { melody(); }
}

Old Answer removed

The old answer was not clear enough for this complicated topic.

Peter Paul Kiefer
  • 1,883
  • 8
  • 10
  • Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on [meta], or in [chat]. Comments continuing discussion may be removed. – Juraj Mar 20 '23 at 13:45