Pin Change Interrupt - External Interrupt with Internal Interrupt
Here in the program, am cycling through LEDs using timer interrupt & if someone presses a switch, it should stop the first interrupt & trigger second one that should lit the led according to the switch pressed. Here, am a little confused which interrupt is being called. I referred some books for Pin Change Interrupt & wrote a few lines for setting PCMSK2. The output am getting is "initially all leds are cycling, when a switch is pressed...cycling of leds stops & starts over again (which means that program is reading input, just not triggering the second interrupt). It doesn't stop or pause & doesn't lit subsequent led." Could anyone help, please?
#include <avr/io.h>
#include <avr/interrupt.h>
#define PINK_MASK \
((1<<PINK0)|(1<<PINK1)|(1<<PINK2)|(1<<PINK3)|(1<<PINK4)|(1<<PINK5)|(1<<PINK6)|(1<<PINK7))
volatile unsigned int intrs, i=1;
void enable_ports(void);
void delay(void开发者_Go百科);
extern void __vector_23 (void) __attribute__ ((interrupt));
extern void __vector_25 (void) __attribute__ ((signal));
void enable_ports()
{
DDRB = 0xff; //PORTB as output for leds
PORTB = 0xff;
DDRK = 0x00; //PORTK as input from switches
PORTK |= PINK_MASK;
PCMSK2 = PINK_MASK; //ENABLE PCMSK2, Setting interrupts
PCICR = 0x04;
PCIFR = 0x04;
TCCR0B = 0x03; //Setting TIMER
TIMSK0 = 0x01;
TCNT0 = 0x00;
intrs = 0;
}
void __vector_23 (void)
{
intrs++;
if(intrs > 60)
{
intrs = 0;
PORTB = (0xff<<i);
i++ ;
if(i == 10 )
{
PORTB = 0xff;
i = 1 ;
}
}
}
void __vector_25 (void)
{
unsigned char switches;
switches = ((~PINK) & (PINK_MASK)); //Reading from switches
if(switches & (1<<PINK0))
PORTB = (PORTB<<PINK0);
else if (switches & (1<<PINK1))
PORTB = (PORTB<<PINK1);
else if (switches & (1<<PINK2))
PORTB = (PORTB<<PINK2);
else if (switches & (1<<PINK3))
PORTB = (PORTB<<PINK3);
else if (switches & (1<<PINK4))
PORTB = (PORTB<<PINK4);
else if (switches & (1<<PINK5))
PORTB = (PORTB<<PINK5);
else if (switches & (1<<PINK6))
PORTB = (PORTB<<PINK6);
else if (switches & (1<<PINK7))
PORTB = (PORTB<<PINK7);
}
int main(void)
{
enable_ports();
sei();
while(1)
{
}
}
Thanks for all your support.
External interrupts in the AVR architecture are confusing but not impossible. I found the best resource for me was the AVR libc page on interrupts. I think you've made the code too complicated for what you want it to do. Let's start from scratch:
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
void main() {
sei();
while(1) {};
}
AVR libc actually makes processing interrupts pretty painless. In the page I linked to above there's a list of all the supported interrupt vectors on each AVR chip. Let's assume you're using a Mega32 and you now want to have the LEDs blink using a timer interrupt. Let's add to the program:
uint8_t led_state;
ISR(TIMER0_COMP_vect) {
led_state = ~led_state;
PORTB = led_state;
}
void setup_timer_interrupt() {
TCCR0B = 0x03;
TIMSK0 = 0x01;
TCNT0 = 0x00;
}
This should blink the LEDs on PORTB
every time the timer interrupt occurs. Notice that the way it should be set up is by using the ISR(...)
macro; the __vector_...
calls you're using are deprecated and a bit more confusing.
Lastly you want to use a set of switches to hold the LED lit, if I understand your question correctly. I actually wouldn't use an external interrupt for this, just read the value of the switches using PINK
during ISR(TIMER0_COMP_vect)
, but we can use it if you'd like. We'll need to add the following code:
uint8_t switch_state;
void setup_switch_interrupt() {
// I'm assuming this code to enable external interrupts works.
DDRK = 0x00;
PORTK = 0xff;
PCMSK2 = 0xff; // set to all 1s
PCICR = 0x04;
PCIFR = 0x04;
}
ISR(INT0_vect) {
switch_state = PINK;
}
What does this do? We will keep the state of the switches in switch_state
, read every time the external interrupt fires (I'm guessing you have this set to happen on both 0->1 and 1->0 transitions). All that's left is to make the LED output dependent on the value of switch_state
. We'll do this in the timer interrupt since that's where we've been toggling the LEDs so far. The new version looks like:
ISR(TIMER0_COMP_vect) {
led_state = ~led_state | switch_state;
PORTB = led_state;
}
And that should do it!
Footnote: I said earlier that using the external interrupt for reading the switches isn't really necessary. This is because you can just read the switch values during the timer interrupt using PINK
. You can get rid of switch_state
, setup_switch_interrupt()
, and ISR(INT0_vect)
and just modify the timer interrupt to be this:
ISR(TIMER0_COMP_vect) {
led_state = ~led_state | PINK;
PORTB = led_state;
}
That should make the program a little simpler.
So no matter what, every time your __vector_23
executes you're cycling through the LEDs assigned to PORTB
by incrementing i
. If I understand what you're trying to do what you should be doing is incrementing i
only in __vector_25
, when the switch is pressed.
精彩评论