Attiny84 external interrupt not working

I wrote a program to test the external interrupt on an Attiny84 that is supposed to blink an LED when a button is pressed. It's not working correctly and the LED blinks when I power up the circuit, but doesn't do anything when I press the button. Can you see what I'm doing wrong? I'm new to this and I would really appreciate any help.

//Attiny84 interrupt test
//LED is on PA7 
//Pushbutton is on PA0 (using external INT0 interrupt)

#include <Interrupt.h> 

int led = 7;
int button = 0;
//for setting register bits with AVR code
//cbi and sbi are standard (AVR) methods for setting, or clearing, bits in PORT (and other) variables. 
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif 



void setup(void)
{
  cli(); //disable global interrupts
  pinMode(led, OUTPUT);
  pinMode(button,INPUT_PULLUP); 
  
  // Set ISC01= 1 and ISC00 = 0 to generate an external interrupt request on the falling edge of INT0
  sbi(MCUCR,ISC01);
  cbi(MCUCR,ISC00); 
  
  //enable external interrupt request 0
  sbi(GIMSK,INT0);
  
  sei(); //enable global interrupts
  
}

void loop(void)
{
 //nothing right now
  
}


//external interrupt ISR (for INT0 pin)
ISR(INT0_vect)
{
  blink_led();
}

void blink_led(void)
{
  digitalWrite(led,HIGH);
  delay(1000);  //delay one second
  digitalWrite(led,LOW); 
}

Don't do delays in an ISR. Moving it to a separate function doesn't take the curse off it.

Better would be:

volatile bool wantBlink;

void loop(void)
{
  if (wantBlink)
    {
    blink ();
    wantBlink = false;
    }
 }


//external interrupt ISR (for INT0 pin)
ISR(INT0_vect)
{
  wantBlink = true;
}

(Not tested).

It turns out I had used the wrong external interrupt pin in my code and circuit--the pin is called "INT0" and there is another pin called "PCINT0" (go figure) and so I confused them. Now that I am using the right pin, it works! Thank you for the advice about not calling a function with a delay from an ISR! That made it work even better...

One is an external interrupt, the other is a pin-change interrupt.

Thanks, got it...if you use pin change interrupts on multiple pins that share the same interrupt vector, what is the best way for determining which pin caused the interrupt? I know I could use If statements in the main loop to determine the state of the pins, but I was wondering if there's a way to latch the pin values once the interrupt occurs without using If statements.

Thank you!

If you are using the IDE then using attachInterrupt() is better than using ISR() as it allows you to select rising/falling etc.

There is a pin change lib which works well. However it you do use ISR() then you need to compare the current state of the port with the old state. There are masks for each of the pin change int's which allow to get pin change int's but only when certain pins on the port change (see the datasheet).

Mark

whatever9:
but I was wondering if there's a way to latch the pin values once the interrupt occurs without using If statements.

Thank you!

What I would do is save the pin states first thing in the ISR. This is as close as you will get to latching them. Then you can check that saved state in the main loop.

Ok, is there any issue with using a few If statements within the ISR to check?

I got the interrupts to work, but the sleep function isn't working as expected. The chip draws about 7 mA and the interrupts don't work as they should when I put the chip to sleep. This is the function I'm using:

void sleep_function(void)
{
  cbi(ADCSRA,ADEN); //disable ADC
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); //set deep sleep mode
  sleep_mode(); /put chip to sleep
  //program starts here after waking from sleep
  sbi(ADCSRA,ADEN); //enable ADC
 
  
}

I used sleep_enable() and sleep_disable() and it didn't make a difference. Is the Arduino sleep library compatible with Attiny84? It's hard for me to tell from the datasheet what's going on...

I think I'm also a little confused about when the program wakes from sleep. When an interrupt is triggered, does the program really start at the last line of the function above, and then go to the ISR?

I'm using pin change interrupts and an analog comparator interrupt. Does the ADC need to be turned on for the analog comparator interrupt to work?

:o
Thank you.

I think I'm also a little confused about when the program wakes from sleep. When an interrupt is triggered, does the program really start at the last line of the function above, and then go to the ISR?

When it wakes it executes the ISR. After leaving the ISR it would execute the line after sleep_mode().

The chip draws about 7 mA and the interrupts don't work as they should when I put the chip to sleep.

Can you describe your hardware? If it asleep it should use less than that, but if you have voltage regulators and so on, it would probably use that much.

I'm using an Attiny84 (datasheet http://www.atmel.com/images/doc8183.pdf) and an LD1117 3.3V regulator. I hope that's enough info...

I found out that the analog comparator interrupt doesn't work in deep sleep mode and it has to be in Idle mode. The current is about 7 mA so I'm trying to figure out how to reduce it. I'm only using buttons/switches and LEDs. This is my test program to better explain what I'm doing:

//interrupt test program for Attiny84A (LEDs turn on in response to interrupts)
//Yellow LED for button interrupt is on PB2
//Green LED for PB0 switch interrupt is on PA0
//Red LED for PB1 switch interrupt is on PA3
//Little Red LED for analog comparator interrupt is on PA5
//Pushbutton is on PB2 (using external INT0 interrupt)
//switch pins go to PB0 and PB1 

#include <Interrupt.h> 
#include <TinyWireM.h>
#include <Adafruit_MCP4725.h>
#include <avr/sleep.h>

Adafruit_MCP4725 dac;

int ledyellow = 8;
int ledgreen = 0;
int ledred = 3;
int ledredlittle = 5;
int button = 7;
int switch1 = 10;
int switch2 = 9;
int dac_in = 2;
int analog_in = 1;
//for setting register bits with AVR code
//cbi and sbi are standard (AVR) methods for setting, or clearing, bits in PORT (and other) variables. 
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif 

volatile bool buttonpress, switchpress1,switchpress2,switchpress3, switch1_on, switch2_on, analogcomp;




void setup(void)
{
  cli(); //disable global interrupts
  dac.begin(0x62); //set DAC address
  
  //set LEDs as outputs
  pinMode(ledyellow, OUTPUT);
  pinMode(ledgreen, OUTPUT);
  pinMode(ledred, OUTPUT);
  pinMode(ledredlittle, OUTPUT);
  
  //set button and switches as inputs with pull-up resistors on
  pinMode(button,INPUT_PULLUP); 
  pinMode(switch1,INPUT_PULLUP); 
  pinMode(switch2,INPUT_PULLUP); 
  
  //set analog comparator pins as inputs
  pinMode(dac_in,INPUT);
  pinMode(analog_in,INPUT);
  
  //enable pin change interrupt 1 (for PCINT[11:8])
  sbi(GIMSK,PCIE1);
  sbi(PCMSK1,PCINT8); //enable PCINT8 pin change interrupt (for SP3T switch)
  sbi(PCMSK1,PCINT9); //enable PCINT9 pin change interrupt (for SP3T switch)

  //enable pin change interrupt 0 (for PCINT[7:0])
  sbi(GIMSK,PCIE0);
  sbi(PCMSK0,PCINT7); //enable PCINT7 pin change interrupt (for button)
  
  //temporarily disable analog comparator interrupt (before configuring)
  cbi(ACSR,ACIE);
  //set comparator interrupt on rising output edge
  sbi(ACSR,ACIS1); 
  sbi(ACSR,ACIS0);
  
  //enable analog comparator interrupt
  sbi(ACSR,ACIE);
  
  dac.setVoltage(2048, false); //initialize DAC output to half VCC
  
  sei(); //enable global interrupts
  
}

void loop(void)
{
 
  if (analogcomp)
  {
     digitalWrite(ledyellow, HIGH);
     digitalWrite(ledgreen, HIGH);
     digitalWrite(ledred, HIGH);
     delay(500);
     digitalWrite(ledyellow, LOW);
     digitalWrite(ledgreen, LOW);
     digitalWrite(ledred, LOW);
     analogcomp = false;
   sleep_function(); //go to sleep
  }
  
  else if (buttonpress)
  {
    digitalWrite(ledyellow, HIGH);
    delay(500);
    digitalWrite(ledyellow, LOW);
    buttonpress = false;
    sleep_function(); //go to sleep
  }
  
  else if(switchpress1)
  {
    digitalWrite(ledgreen, HIGH);
    delay(500);
    digitalWrite(ledgreen, LOW);
    switchpress1 = false;
    sleep_function(); //go to sleep
  }
  
  else if (switchpress2)
  {
    digitalWrite(ledred, HIGH);
    delay(500);
    digitalWrite(ledred, LOW);
    switchpress2 = false;
    sleep_function(); //go to sleep
  }
  
  else if (switchpress3)
  {
    digitalWrite(ledredlittle, HIGH);
    delay(500);
    digitalWrite(ledredlittle, LOW);
    switchpress3 = false;
    sleep_function(); //go to sleep
  }
      
}

//analog comparator interrupt
ISR(ANA_COMP_vect)
{
  analogcomp= true;
}

//for switches
ISR(PCINT1_vect)
{
    //read switch values
     switch1_on = digitalRead(switch1);
     switch2_on = digitalRead(switch2);
     
     if (switch1_on == 0) //switch 1 is on
     {
       switchpress1 = true; 
     }
     
     else if (switch2_on == 0) //switch 2 is on
     {
      switchpress2 = true;
     }
     
     else //neither switch is on
     {
      switchpress3 = true;
     }

}

//for button
ISR(PCINT0_vect)
{
    buttonpress = true;
}

void sleep_function(void)
{
  cbi(ADCSRA,ADEN); //disable ADC
  set_sleep_mode(SLEEP_MODE_IDLE); //sleep mode idle 
  sleep_mode(); //implement sleep
  //PROGRAM STARTS HERE AFTER WAKING FROM SLEEP 
  sbi(ADCSRA,ADEN); //enable ADC
}