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


9

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


1
自从我使用AVR已经有一段时间了,但是我确定必须有一个为正确的引脚触发的标志。中断发生后,该标志应清除,因此您无需存储状态。设置标记的事实应该足够了
Gustavo Litovsky

@ gl3829,如果我正确理解,则标志是每组针脚
Tom Davies

Answers:


11

我认为向量和图钉的命名重叠令人困惑

它是!

中断向量有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 */
    }
}

兆位具有三个引脚改变中断,其向量为PCINT [0-2],但每个中断都由一组引脚触发。我的问题是关于如何区分该组中的哪个引脚引起了中断。
Tom Davies

@TomDavies您是正确的,谢谢,我更改了答案,但这正是您的想法。我通读了数据手册,没有标志来指示更改了哪个引脚。
Garrett Fogerlie

@ Garret:您是否知道在您的原始示例中,可以轻松确定触发中断的是下降沿还是上升沿?(好吧,除非两个引脚都在同一时刻发生变化……但是在这种情况下,只有黑魔法才有帮助)(previous_pins>引脚):下降沿(先前的引脚<引脚):上升沿也许值得在上面提到。

@TomDavies PINB涵盖PCINT0-7,PINC涵盖PCINT8-15等
EkriirkE 2015年

0

在较新的ATTINY系列INTFLAGS寄存器上,将告诉您是哪个端口位引起了中断。

这是数据表的摘录:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.