简体   繁体   中英

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);

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM