I'm trying to use pin change interrupts to detect pressed buttons. Until now I have never worked with these kind of interrupts and there are some problems, so I want to make sure if this is the correct usage.
If I got the datasheet right the following things must be done to use a pin change interrupt:
- Set which PINs you want to control in the PCMSK register
- Enable the PINs register for pin change interrupt control (PCICR)
- Enable interrupts
- Use the corresponding interrupt vector
Project: Simple Moodlamp, Colors controlled via 4 Buttons.
Setup:
- Atmega168A-PU
- 4 mini push button switches
- MOSFETS to control my 3 Watt RGB LED
Here is the code I'm using which is not working as expected:
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define BUTTON1 (1<<PC5)
#define BUTTON2 (1<<PC4)
#define BUTTON3 (1<<PC3)
#define BUTTON4 (1<<PC2)
#define GREEN (1<<PB1)
#define BLUE (1<<PB2)
#define RED (1<<PB3)
void init() {
// enable LED
DDRB |= GREEN;
DDRB |= BLUE;
DDRB |= RED;
// button pullups
PORTC |= BUTTON1;
PORTC |= BUTTON2;
PORTC |= BUTTON3;
PORTC |= BUTTON4;
// pin change interrupts for buttons
PCMSK1 |= PCINT13;
PCMSK1 |= PCINT12;
PCMSK1 |= PCINT11;
PCMSK1 |= PCINT10;
// enable pin change for buttons
PCICR |= PCIE2;
sei();
}
ISR(PCINT2_vect) {
PORTB = BLUE;
}
void ledTest() {
PORTB ^= RED;
_delay_ms(250);
PORTB ^= RED;
_delay_ms(250);
PORTB ^= RED;
_delay_ms(250);
PORTB ^= RED;
PORTB ^= BLUE;
_delay_ms(250);
PORTB ^= BLUE;
_delay_ms(250);
PORTB ^= BLUE;
_delay_ms(250);
PORTB ^= BLUE;
PORTB ^= GREEN;
_delay_ms(250);
PORTB ^= GREEN;
_delay_ms(250);
PORTB ^= GREEN;
_delay_ms(250);
PORTB ^= GREEN;
}
int main() {
init();
ledTest();
_delay_ms(500);
PORTB |= GREEN;
while(1) {
_delay_ms(100);
}
}
Note: The buttons should be debounced. Since I'm trying to this step by step and it shouldn't mater for turning on the LED, I ignored it here.
Question: Is the way I'm trying to use the interrupts correct?
Problems with my setup:
- Buttons1-3 are totally ignored.
- Button4 is triggering a reset of the atmega
Things I checked:
- Buttons are in no way connected to the reset PIN
- Buttons are properly connected to GND if pressed
- Buttons are not connected to GND if not pressed
Buttons work nicely if I utilize them without an interrupt, e.g.:
if(!(PINC & BUTTON4)) { PORTB ^= BLUE; }
- 16MHZ external crystal / internal crystal
- Any errors in the routing
- I'm using a 100nF capacitator between PWR and GND on the atmega
- VCC(7), GND(8), GND(22), AVCC(20) are connected (since I don't need AREF, its not connected)