AVR C won't run interrupt

736 views Asked by At

I'm fiddling with my MEGA-1284p kit and avr studio and I'm in need of some help solving a problem. I need it to toggle LED3 on button press SW0.

Here is the AVR C code:

#define F_CPU 11059200UL // The Xplained kit runs at 11.0592 MHz

#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int ex37() {

    DDRB = 0x04;// LED3 as output
    PORTB = 0x04; //LED3 off    

    EIMSK |= (1<<INT0) | (0<<INT1) | (0<<INT2); // Enable external interrupt 0 (SW0)
    MCUCR |= (1<<ISC01) | (1<<ISC00); // INT0 on rising edge.

    sei(); // Start interrupts

    _delay_ms(1000); //wait 1000 ms = 1 sec
    PORTB = 0x00; //LED3 on
    _delay_ms(1000); //wait 1000 ms = 1 sec
    PORTB = 0x04; //LED3 off

    while(1) {  
    };
    return 0;
}
ISR(INT0_vect) {
    _delay_ms(1000); //wait 1000 ms = 1 sec
    if (PORTB == 0x04){
        PORTB = 0x00;
    } else {
        PORTB = 0x04;
    }
}

But the function to change the LED3 never gets called for as far as I can tell.

4

There are 4 answers

0
UncleO On BEST ANSWER

SW0 is connected to PB0, which is not the pin that any of the external interrupts are active on.

Instead, you need to use a pin change interrupt, PCIE1 and configure it properly. See datasheet for the register descriptions.

1
Dark Falcon On

You need to disable the watchdog timer or regularly execute the watchdog timer reset (WDR) instruction. If you don't, the controller will reset when it expires. The data sheet gives code like this for disabling it:

void WDT_off(void)
{
    __disable_interrupt();
    __watchdog_reset();
    /* Clear WDRF in MCUSR */
    MCUSR &= ~(1<<WDRF);
    /* Write logical one to WDCE and WDE */
    /* Keep old prescaler setting to prevent unintentional
    time-out */
    WDTCSR |= (1<<WDCE) | (1<<WDE);
    /* Turn off WDT */
    WDTCSR = 0x00;
    __enable_interrupt();
}
0
zviad On

Instead of:

if (PORTB == 0x04){
    PORTB = 0x00;
} else {
    PORTB = 0x04;
}

you can write only: PORTB ^= 0x04;

0
Daniel On

It may not be the primary issue in your code, but the first thing that jumps out at me is the massive delay you have inside your interrupt service routine:

ISR(INT0_vect) {
_delay_ms(1000); //wait 1000 ms = 1 sec
if (PORTB == 0x04){
    PORTB = 0x00;
} else {
    PORTB = 0x04;
}
}

One full second is a very, very long time for a microcontroller to be waiting. As someone mentioned, it's likely that your watchdog timer is timing out. Instead of fiddling with the watchdog enable/disable, consider rewriting your ISR first, and see if that solves your problem.

It is generally good practice to write code with the shortest ISR's possible. I would recommend using your ISR to instead create a flag, and respond to it in your while(1) loop. Having a 1 second delay in your ISR may not cause problems now, but it could really bog down your MCU once things start adding up.

I hope this helps.