2

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.

Transistor
  • 629
  • 5
  • 16

1 Answers1

3

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:

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

  2. 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
Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81