开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜