Reputation: 47
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.
Upvotes: 0
Views: 784
Reputation: 648
Instead of:
if (PORTB == 0x04){
PORTB = 0x00;
} else {
PORTB = 0x04;
}
you can write only: PORTB ^= 0x04;
Upvotes: 0
Reputation: 235
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.
Upvotes: 0
Reputation: 8449
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.
Upvotes: 2
Reputation: 44181
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();
}
Upvotes: 0