Using OneButton Library with Sleep Mode on ATtiny85

Hi everyone,

I'm working on a project with an ATtiny85 where I want to use the OneButton library to handle button presses and implement a sleep mode for power saving. The basic functionality I want is:

  • A single click turns the LED on.
  • A double click turns the LED off and puts the ATtiny85 to sleep after 3 seconds.
  • While in sleep mode, a single click should wake the ATtiny85 and turn the LED on.

Here's the code I have so far:

#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <OneButton.h>

#define LED_PIN PB2           // PB2 (Pin 7)
#define INTERRUPT_BUTTON PB1  // PB1 (Pin 6)

OneButton button(INTERRUPT_BUTTON, true, true);

volatile bool ledState = LOW;

void setup() {
  // Set up the LED pin
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  // Set up the button with the OneButton library
  button.attachClick(singleClick);
  button.attachDoubleClick(doubleClick);

  // Enable pin change interrupt for INTERRUPT_BUTTON (PB1)
  GIMSK |= (1 << PCIE);    // Enable Pin Change Interrupts
  PCMSK |= (1 << PCINT1);  // Enable Pin Change Interrupt for PB1

  // Enable global interrupts
  sei();

  // Enable sleep mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}

void loop() {
  button.tick();  // Check the status of the button

  if (ledState == LOW) {
    delay(3000);  // Wait for 3 seconds
    if (ledState == LOW) {
      enterSleep();
    }
  }
}

ISR(PCINT0_vect) {
  // Wake up from sleep
  // Do nothing here, just wake up
}

void singleClick() {
  // Handle single click - turn LED on and stay awake
  ledState = HIGH;
  digitalWrite(LED_PIN, HIGH);
}

void doubleClick() {
  // Handle double click - turn LED off and go to sleep
  ledState = LOW;
  digitalWrite(LED_PIN, LOW);
}

void enterSleep() {
  // Disable ADC and other modules to save power
  ADCSRA &= ~(1 << ADEN);

  // Sleep until an interrupt occurs
  sleep_enable();
  sei();
  sleep_cpu();
  sleep_disable();

  // Re-enable ADC
  ADCSRA |= (1 << ADEN);
}

The Issue: The button functions (single click to turn on the LED, double click to turn off the LED) work perfectly without the sleep mode. However, when I include the sleep mode, the button press does not always wake up the ATtiny85 as expected.

Question: How can I correctly implement the OneButton library with the sleep mode on the ATtiny85 to achieve the desired functionality? Any help or pointers would be greatly appreciated!

Thank you!

During that wait you don't check the button's activity... so if ledState was LOW before you can be sure it's still LOW after the delay...

I don't use the OneButton library, but it looks like it is not intended to work with sleep modes. I suspect that you need to get wakeup interrupt working separately from the button library. Keep in mind that in sleep mode, the button library timing won't work.

From the library docs:

Troubleshooting

If your buttons aren't acting they way they should, check these items:

  1. Check your wiring and pin numbers.
  2. Did you call tick() on each button instance in your loop?
  3. Did you alter your clock timers in any way without adjusting ticks?

Yes, you're right.
I just wanted to make sure the status didn't change...but you're right. I'll have to use
millis()
to manually stagger the time.
thx

Yes, obviously that doesn't work.

I have no idea how to recognize a double click or a single click and wake up at the same time.

Maybe something with:

But how can I handle it?

Maybe one is a solution, maybe a workaround because it's not particularly elegant.
But you gave me the idea.

...
..
void loop() {
  button.tick();  // Check the status of the button

  if (ledState == LOW) {
    //delay(3000);  // Wait for 3 seconds
    if (!anyButtonClick) {
      enterSleep();
    }
  }
}

ISR(PCINT0_vect) {
  // Wake up from sleep
  // Do nothing here, just wake up
  anyButtonClick = 1;
  button.tick(); 
  delay (20);
}

void singleClick() {
  // Handle single click - turn LED on and stay awake
  ledState = HIGH;
  digitalWrite(LED_PIN, HIGH);
  anyButtonClick =0;
}

void doubleClick() {
  // Handle double click - turn LED off and go to sleep
  ledState = LOW;
  digitalWrite(LED_PIN, LOW);
  anyButtonClick =0;
}
..
...

Do not use delay() within an ISR.

On some Arduinos it is ignored, or on others, it will cause a system crash, because delay depends on interrupts and those are turned off.

Alright!
is removed :wink: Thx a lot!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.