Attiny85 sleep

Hi. I found a code that works great for sleeping and waking up attiny85.
However it wakes up attiny wether the switch is pressed or unpressed.
I want it to wake up only when pressed.

How can i do that?

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

const int switchPin = 3;
const int statusLED = 2;

void setup() {

pinMode(switchPin, INPUT);
digitalWrite(switchPin, HIGH);
pinMode(statusLED, OUTPUT);

// Flash quick sequence so we know setup has started
for (int k = 0; k < 10; k = k + 1) {
if (k % 2 == 0) {
digitalWrite(statusLED, HIGH);
}
else {
digitalWrite(statusLED, LOW);
}
delay(250);
} // for
} // setup

void sleep() {

GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts
PCMSK |= _BV(PCINT3); // Use PB3 as interrupt pin
ADCSRA &= ~_BV(ADEN); // ADC off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement

sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep

cli(); // Disable interrupts
PCMSK &= ~_BV(PCINT3); // Turn off PB3 as interrupt pin
sleep_disable(); // Clear SE bit
ADCSRA |= _BV(ADEN); // ADC on

sei(); // Enable interrupts
} // sleep

ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don’t need to do anything in it
}

void loop() {
sleep();
digitalWrite(statusLED, HIGH);
delay(1000);
digitalWrite(statusLED, LOW);
}

I'm not sure you can for a pin change interrupt. The INT0 supports edges.

Datasheet

9.2 External Interrupts

The External Interrupts are triggered by the INT0 pin or any of the PCINT[5:0] pins. Observe that, if enabled, the interrupts will trigger even if the INT0 or PCINT[5:0] pins are configured as outputs. This feature provides a way of generating a software interrupt. Pin change interrupts PCI will trigger if any enabled PCINT[5:0] pin toggles. The PCMSK Register control which pins contribute to the pin change interrupts. Pin change interrupts on PCINT[5:0]are detected asynchronously. This implies that these interrupts can be used for waking the part also from slee pmodes other than Idle mode.

The INT0 interrupts can be triggered by a falling or rising edge or a low level. This is set up as indicated in the specification for the MCU Control Register – MCUCR. When the INT0 interrupt is enabled and is configured as level triggered, the interrupt will trigger as long as the pin is held low. Note that recognition of falling or rising edge interrupts on INT0 requires the presence of an I/O clock, described in “Clock Systems and their Distribution” on page 23.

I could be wrong....

An easy solution is to check the state of the pin when you wake with digitalRead. If it's not the state you are expecting, immediately sleep again.

ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don't need to do anything in it
val = digitalRead(switchPin);
if(val==LOW)
{

sleep();

}
}

thats what you suggest?

You need to configure your wake up pin as INPUT_PULLUP. It's floating and triggering the wake up.

tf68:
You need to configure your wake up pin as INPUT_PULLUP. It's floating and triggering the wake up.

i made it pinMode(switchPin, INPUT_PULLUP); and i removed the sleep:
ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don't need to do anything in it
// val = digitalRead(switchPin);
// if(val==HIGH)
// {
// sleep();
// }
}

it still wakes up where i press or unpress the switch.

what am i doing wrong? thank you

chris700:
i made it pinMode(switchPin, INPUT_PULLUP); and i removed the sleep:
ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don't need to do anything in it
// val = digitalRead(switchPin);
// if(val==HIGH)
// {
// sleep();
// }
}

it still wakes up where i press or unpress the switch.

what am i doing wrong? thank you

No, you still need to sleep. When you wake up you need to check the pin state is LOW, if not sleep again:

while (digitalRead(switchPin) == HIGH)
{
   sleep();
}

Now the Arduino will sleep while the pin is HIGH.

pcbbc:
No, you still need to sleep. When you wake up you need to check the pin state is LOW, if not sleep again:

while (digitalRead(switchPin) == HIGH)

{
  sleep();
}



Now the Arduino will sleep while the pin is HIGH.

thanks.thats how it works my reed switch tho. i thought you meant before that if i change the INPUT to INPUT_PULLUP it would work without my code checking if its high or low. thanks :slight_smile:

I know it is already resolved, but I would recommend to do it this way:

Have a global variable on the sketch:

volatile bool pressed = False;

If you need to run your code at least 1 one time at the beginning then add to setup(){}:

pressed = True;

Your interrupt handler should be like:

ISR(PCINT0_vect) {
    if(digitalRead(switchPin)==HIGH){  
        pressed = True; //set flag
    }
}

Then, on your loop where all your code is you need to wrap it on a conditional:

void loop() {
    if (pressed){
        do_code_if_pressed();
        pressed = False; //reset flag
    }

    sleep();
}

What happens is that the pin change triggers the interrupt, then, only if it is high it sets our flag to true and loop runs the normal code only if the change was to high, if not, it sleeps again.

I removed the variable assignment on the interrupt because you need to keep interrupts as small as possible reducing cycles with that change. Also, the volatile flag tells the compiler to store the variable on RAM cause it is going to change asynchronously to main program, avoiding errors on stored value.

You read and save the state of the pin on interrupt because you don't know if 2 or 3 microseconds later, when MCU exits sleep, restarts loop and reads pin, the pin will be still on high, causing a lost interrupt. It could not be necessary now, but it will save you trouble later.

[Edit] I forgot to add the cli() and sei(). They are necessary on the loop if you want to turn off interrupts for the time you are not expecting to receive an interrupt. That turns off serial comm too I think. Useful when you are making time-critical communication like I2C. Because the trigger of an interrupt would affect the data sent.

Also, remember to use code tags please.