user13749: My ATtiny 85 won't wake up!
The purpose of the device is to monitor a reed switch and give a 20 ms output pulse on every alternate positive-going transition of the reed switch input. The device should go to sleep after 30 s of inactivity. It should wake up on reed switch activity (rising or falling edge).
/*
          ATMEL ATTINY 85
              +-\/-+
        PB5  1|    |8  Vcc
        PB3  2|    |7  PB2 (INT0) reed switch input (1 MΩ ext. pull-up)
        PB4  3|    |6  PB1        output
        GND  4|    |5  PB0 
              +----+
*/
#include <avr/sleep.h>
#include <avr/power.h>
#include <elapsedMillis.h>

const int hallPin = 2;            // Reed switch in this case.
const int magnetPin =  1;         // Output.
const long debouncing_time = 15;  // Debouncing time in milliseconds.

volatile int hallState = 0;       // variable for storing the hall counter
volatile bool hallMem = 0;        // One-shot memory.
volatile unsigned long last_micros;

elapsedMillis timer;

void setup(){
  pinMode(magnetPin, OUTPUT);
  pinMode(hallPin, INPUT);
  // Attach an interrupt to the ISR vector. DO I NEED THIS?
//  attachInterrupt(0, pin_ISR, RISING); //default interupt pin is always 0 on ATtiny85 (physical pin 7).
  timer = 0;                             //Reset the timer
}

void loop(){
  if(digitalRead(hallPin) && !hallMem){
    hallMem = true;               // One-shot memory.
    hallState++;
    delay(debouncing_time);       // Keep it simple.
    timer = 0;
  }
  if(!digitalRead(hallPin)){
    hallMem = false;              // Allow re-trigger.
  }
  if(hallState > 1) {
      digitalWrite(magnetPin, HIGH);        // Send 20 ms pulse to sensor activation coil.
      delay(20);
      digitalWrite(magnetPin, LOW);
      hallState = 0;                        // Reset the trigger.
  }
  if(timer >= 30000) {                      // No activity.
    system_sleep();
  }
}

// From http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void system_sleep() {
  GIMSK |= _BV(PCIE);                     // Enable Pin Change Interrupts
  PCMSK |= _BV(INT0);                     // Use INT0 (PB2) 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(INT0);                  // Turn off INT0 (PB2) as interrupt pin
  sleep_disable();                        // Clear SE bit
  ADCSRA |= _BV(ADEN);                    // ADC on

  sei();                                  // Enable interrupts  
  
  timer = 0;          // Reset the sleep timer on wake-up.
}

ISR(PCINT0_vect) {
}

Can anyone spot my error that is preventing a wake-up?
What is the ADC enabling instruction doing? Do I need it?
Many thanks.

user7508: I believe your problem lies here:
PCMSK |= _BV(INT0);  // Use INT0 (PB2) as interrupt pin

You seem to have mixed up two sorts of interrupts:

INT0 (External Interrupt), which only works on pin INT0 (i.e. PB2)
and can sense low-level, rising edge, falling edge, or any change.

PCINT0 (Pin Change Interrupt), which works on any IO pin, but can
only sense “any change”.


Since you are sleeping in PWR_DOWN mode, pin change interrupt is the
appropriate choice. All your program is consistent with this choice but
for the line above.
The INT0 macro has the value 6. It represents bit 6 of GIMSK, which
is used to enable the INT0 interrupt. Not what you want. Bit 6 of
PCMSK is reserved, so you are not supposed to touch it. If you want
the pin change interrupt to sense changes in pin PB2 (aka PCINT2), you
instead have to:
PCMSK |= _BV(PCINT2);  // sense changes in PCINT2 = PB2


13749: <p>My ATtiny 85 won't wake up!</p>
<p>The purpose of the device is to monitor a reed switch and give a 20 ms output pulse on every alternate positive-going transition of the reed switch input. The device should go to sleep after 30 s of inactivity. It should wake up on reed switch activity (rising or falling edge).</p>
<pre><code>/*
          ATMEL ATTINY 85
              +-\/-+
        PB5  1|    |8  Vcc
        PB3  2|    |7  PB2 (INT0) reed switch input (1 MΩ ext. pull-up)
        PB4  3|    |6  PB1        output
        GND  4|    |5  PB0 
              +----+
*/
#include &lt;avr/sleep.h&gt;
#include &lt;avr/power.h&gt;
#include &lt;elapsedMillis.h&gt;

const int hallPin = 2;            // Reed switch in this case.
const int magnetPin =  1;         // Output.
const long debouncing_time = 15;  // Debouncing time in milliseconds.

volatile int hallState = 0;       // variable for storing the hall counter
volatile bool hallMem = 0;        // One-shot memory.
volatile unsigned long last_micros;

elapsedMillis timer;

void setup(){
  pinMode(magnetPin, OUTPUT);
  pinMode(hallPin, INPUT);
  // Attach an interrupt to the ISR vector. DO I NEED THIS?
//  attachInterrupt(0, pin_ISR, RISING); //default interupt pin is always 0 on ATtiny85 (physical pin 7).
  timer = 0;                             //Reset the timer
}

void loop(){
  if(digitalRead(hallPin) &amp;&amp; !hallMem){
    hallMem = true;               // One-shot memory.
    hallState++;
    delay(debouncing_time);       // Keep it simple.
    timer = 0;
  }
  if(!digitalRead(hallPin)){
    hallMem = false;              // Allow re-trigger.
  }
  if(hallState &gt; 1) {
      digitalWrite(magnetPin, HIGH);        // Send 20 ms pulse to sensor activation coil.
      delay(20);
      digitalWrite(magnetPin, LOW);
      hallState = 0;                        // Reset the trigger.
  }
  if(timer &gt;= 30000) {                      // No activity.
    system_sleep();
  }
}

// From http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void system_sleep() {
  GIMSK |= _BV(PCIE);                     // Enable Pin Change Interrupts
  PCMSK |= _BV(INT0);                     // Use INT0 (PB2) as interrupt pin
  ADCSRA &amp;= ~_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 &amp;= ~_BV(INT0);                  // Turn off INT0 (PB2) as interrupt pin
  sleep_disable();                        // Clear SE bit
  ADCSRA |= _BV(ADEN);                    // ADC on

  sei();                                  // Enable interrupts  
  
  timer = 0;          // Reset the sleep timer on wake-up.
}

ISR(PCINT0_vect) {
}
</code></pre>
<p>Can anyone spot my error that is preventing a wake-up?</p>
<p>What is the ADC enabling instruction doing? Do I need it?</p>
<p>Many thanks.</p>
 7508: <p>I believe your problem lies here:</p>
<pre class="lang-c prettyprint-override"><code>PCMSK |= _BV(INT0);  // Use INT0 (PB2) as interrupt pin
</code></pre>
<p>You seem to have mixed up two sorts of interrupts:</p>
<ol>
<li><p>INT0 (External Interrupt), which only works on pin INT0 (i.e. PB2)
and can sense low-level, rising edge, falling edge, or any change.</p>
</li>
<li><p>PCINT0 (Pin Change Interrupt), which works on any IO pin, but can
only sense “any change”.</p>
</li>
</ol>
<p>Since you are sleeping in PWR_DOWN mode, pin change interrupt is the
appropriate choice. All your program is consistent with this choice but
for the line above.</p>
<p>The <code>INT0</code> macro has the value 6. It represents bit 6 of <code>GIMSK</code>, which
is used to enable the INT0 interrupt. Not what you want. Bit 6 of
<code>PCMSK</code> is reserved, so you are not supposed to touch it. If you want
the pin change interrupt to sense changes in pin PB2 (aka PCINT2), you
instead have to:</p>
<pre class="lang-c prettyprint-override"><code>PCMSK |= _BV(PCINT2);  // sense changes in PCINT2 = PB2
</code></pre>
