确定哪个引脚触发了 PCINTn 中断?

电器工程 avr 中断 爱特梅尔
2022-01-13 07:53:26

我是否正确地认为如果您有两个引脚导致相同的 AVR PCINT 中断(例如由 PCINT0 或 PCINT1 引脚引起的PCINT0向量——我认为向量和引脚的命名重叠令人困惑)确定哪个引脚的唯一方法(s) 造成中断是在每次中断后记录它们的状态,并比较 PCMSKn 中启用的所有引脚的先前值和当前值?

2个回答

我认为向量和引脚的命名重叠令人困惑

它是!

一个中断向量有 8 个不同的外部引脚的原因是为了更容易布局 PCB 或在与另一个引脚功能发生冲突时使用不同的引脚。

我的想法是否正确......确定哪些引脚导致中断的唯一方法是在每次中断后记录它们的状态并比较在 PCMSKn 中启用的所有引脚的先前值和当前值?

差不多吧,假设你只关心 PB0 (PCINT0) 和 PB1 (PCINT1)。因此引脚更改使能掩码 PCMSK0 将设置为 0x03。

// External Interrupt Setup
...

volatile u_int8 previousPins = 0; 
volatile u_int8 pins = 0; 

ISR(SIG_PIN_CHANGE0)
{
    previousPins = pins; // Save the previous state so you can tell what changed
    pins = (PINB & 0x03); // set pins to the value of PB0 and PB1
    ...
}

因此,如果pins是 0x01,您就知道它是 PB0 ... 如果您需要知道发生了什么变化,您需要将其与 进行比较,这与previousPins您的想法几乎完全相同。

请记住,在某些情况下,pins如果引脚在中断之后但之前的状态发生变化,则可能不准确pins = (PINB & 0x03)

另一种选择是使用单独的中断向量,每个向量都有一个引脚,这样你就知道哪个被改变了。同样,这也有一些问题,例如中断优先级,一旦 CPU 进入 ISR,全局中断使能位I-bitSREG被清除,以便禁用所有其他中断,尽管您可以根据需要在中断中设置它,那将是一个嵌套中断。

有关更多信息,请查看 Atmel 的应用笔记为 megaAVR 设备使用外部中断。

更新

这是我刚刚在这里找到的完整代码示例

#include <avr/io.h>
#include <stdint.h>            // has to be added to use uint8_t
#include <avr/interrupt.h>    // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF;     // default is high because the pull-up

int main(void)
{
    DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
    // PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs

    PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
    // PB0, PB1 and PB2 are now inputs with pull-up enabled

    PCICR |= (1 << PCIE0);     // set PCIE0 to enable PCMSK0 scan
    PCMSK0 |= (1 << PCINT0);   // set PCINT0 to trigger an interrupt on state change 

    sei();                     // turn on interrupts

    while(1)
    {
    /*main program loop here */
    }
}

ISR (PCINT0_vect)
{
    uint8_t changedbits;

    changedbits = PINB ^ portbhistory;
    portbhistory = PINB;

    if(changedbits & (1 << PB0))
    {
    /* PCINT0 changed */
    }

    if(changedbits & (1 << PB1))
    {
    /* PCINT1 changed */
    }

    if(changedbits & (1 << PB2))
    {
    /* PCINT2 changed */
    }
}

在较新的 ATTINY 系列INTFLAGS寄存器上,会告诉您哪个端口位导致了中断。

以下是数据表的摘录:

位 7:0 – INT[7:0]:中断引脚标志当引脚变化/状态与引脚的输入检测配置匹配时,INT 标志置位。将“1”写入标志位位置将清除该标志。