【问题标题】:Pin Change Interrupt - External Interrupt with Internal Interrupt引脚变化中断 - 带内部中断的外部中断
【发布时间】:2010-11-09 19:43:26
【问题描述】:

在程序中,我正在使用定时器中断循环 LED,如果有人按下开关,它应该停止第一个中断并触发第二个中断,该中断应该根据按下的开关点亮 LED。在这里,我有点困惑正在调用哪个中断。我参考了一些关于 Pin Change Interrupt 的书,并写了几行来设置 PCMSK2。得到的输出是“最初所有的 LED 都在循环,当按下开关时...... LED 的循环停止并重新开始(这意味着程序正在读取输入,只是没有触发第二个中断)。它不会停止或暂停 & 不点亮后续的 LED。”有人可以帮忙吗?

#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)
    {

    }
}

感谢大家的支持。

【问题讨论】:

  • 抱歉,我不使用 Atmel µC。但也许你可以问embdev.net
  • 您的目标设备是什么?

标签: c avr interrupt-handling


【解决方案1】:

AVR 架构中的外部中断令人困惑,但并非不可能。我发现对我来说最好的资源是AVR libc page on interrupts。我认为您使代码变得过于复杂,无法满足您的要求。让我们从头开始:

#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

void main() {
    sei();
    while(1) {};
}

AVR libc 实际上使处理中断非常轻松。在我上面链接的页面中,有一个列表,列出了每个 AVR 芯片上所有支持的中断向量。假设您使用的是 Mega32,您现在希望使用定时器中断让 LED 闪烁。让我们添加到程序中:

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

每次发生定时器中断时,PORTB 上的 LED 应该会闪烁。请注意,它的设置方式是使用ISR(...) 宏;您正在使用的 __vector_... 调用已被弃用并且更加混乱。

最后,如果我正确理解您的问题,您想使用一组开关来保持 LED 亮起。我实际上不会为此使用外部中断,只需在ISR(TIMER0_COMP_vect) 期间使用PINK 读取开关的值,但如果您愿意,我们可以使用它。我们需要添加以下代码:

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

这是做什么的?我们将在switch_state 中保持开关的状态,每次外部中断触发时读取(我猜你有这个设置发生在 0->1 和 1->0 转换上)。剩下的就是使 LED 输出依赖于switch_state 的值。我们将在定时器中断中执行此操作,因为到目前为止我们一直在切换 LED。新版本长这样:

ISR(TIMER0_COMP_vect) {
    led_state = ~led_state | switch_state;
    PORTB = led_state;
}

应该这样做!

脚注:我之前说过,使用外部中断来读取开关并不是真正必要的。这是因为您可以在定时器中断期间使用PINK 读取开关值。您可以去掉switch_statesetup_switch_interrupt()ISR(INT0_vect),只需将定时器中断修改为:

ISR(TIMER0_COMP_vect) {
    led_state = ~led_state | PINK;
    PORTB = led_state;
}

这应该会使程序更简单一些。

【讨论】:

    【解决方案2】:

    所以无论如何,每次__vector_23 执行时,您都会通过递增i 来循环分配给PORTB 的LED。如果我了解您正在尝试做的事情,那么您应该做的是仅在__vector_25 中增加i,当按下开关时。

    【讨论】:

    • @sneezy,我认为我第一次回答时弄错了,请查看我的编辑并提供一些更好的说明。
    • 我没有看到 __vector_25 被调用。
    猜你喜欢
    • 2021-09-12
    • 2018-03-30
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-24
    • 1970-01-01
    • 2020-05-14
    相关资源
    最近更新 更多