Дополнительные внешние прерывания

step962
Offline
Зарегистрирован: 23.05.2011

 Не касаясь других вопросов, по поводу "а на какие ноги можно навесить прерывание" замечу, что схема распиновки Arduino содержит весь список функций, доступных на той или иной ноге:

Пользоваться схемой просто: стоит у ноги в скобочках функция PCINTx, значит можно, не стоит - низззя.

UPD: ATMega328 по-большому отличается от ATMega168 лишь размером памяти.

Monster
Offline
Зарегистрирован: 18.06.2012

Итого, более 5 (2+3) прерываний без анализа инициатора на Нано иметь невозможно?

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

1) ...или данное прерывание относится только к ногам этого порта и не более?

Именно так. PCINT0 - порт B, PCINT1 - порт С, PCINT2 - порт D.

2) В чем отличие PCINTx от INTx ?

Прерывание INTx можно настроить по: переднему фронту импульса, заднему фронту импульса, по переднему и заднему одновременно (любое изменение уровня) и на низкий уровень, это когда на ноге низкий уровень все время будет выполняться обработчик INTx. А прерывание PCINTx срабатывает только на любое изменение уровня и изменить это никак нельзя.

3) ...будет ли пропуск этого события?

Если во время выполнения обработчика какого-либо прерывания сгенерилось какоенить другое прерывание, то после выполнения текущего обработчика, это другое прерывание, будет выполнено, но только один раз, вне зависимости от того сколько раз оно сгенерилось. Никакого буфера для отслеживания нет. Есть флаг готовности этого прерывания (а он только один), который показывает что оно произошло и что надо надо срочно прыгнуть на обработчик этого прерывания. Более подробно как это работает тут, раздел прерывания easyelectronics.ru/avr-uchebnyj-kurs-podprogrammy-i-preryvaniya.html

4) ...Будет ли корректно так раскидать ноги..

Да так можно сделать, но, что-бы INT0/INT1 не накладывались на PCINT2, надо в регистре PCMSK2 назначить только одну ногу (PCINT23 - PD7 на МК) которая будет вызывать обработчик прерывания ISR(PCINT2_vect){}. Это можно сделать вот так PCMSK2 = 128.

>> Или можно вообще использовать все ноги порта D...

Нет, нельзя.

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

Monster пишет:

Итого, более 5 (2+3) прерываний без анализа инициатора на Нано иметь невозможно?

В яблочко!

Monster
Offline
Зарегистрирован: 18.06.2012

Настройка всех 4 прерываний на любое изменение логического уровня (чтобы условия для входов были одинаковы):

 

01void setup()
02{       
03  // разрешение прерываний INT0 и INT1
04  EIMSK  =  (1<<INT0)  | (1<<INT1);
05  // настройка срабатывания прерываний на любому изменению
06  EICRA  =  (0<<ISC11) | (1<<ISC10) | (0<<ISC01) | (1<<ISC00);
07  // разрешение прерываний с портов B (PCINT[7:0]) и D (PCINT[23:16]), и запрет с порта C (PCINT[14:8])
08  PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (1<<PCIE0);
09  // маскирование всех ног, кроме PB0 и PD7 - по одной на PCINT0 и PCINT2
10  PCMSK0 |= (0<<PCINT7)  | (0<<PCINT6)  | (0<<PCINT5)  | (0<<PCINT4)  | (0<<PCINT3)  | (0<<PCINT2)  | (0<<PCINT1)  | (1<<PCINT0);
11  PCMSK1 |=                (0<<PCINT14) | (0<<PCINT13) | (0<<PCINT12) | (0<<PCINT11) | (0<<PCINT10) | (0<<PCINT9)  | (0<<PCINT8);
12  PCMSK2 |= (1<<PCINT23) | (0<<PCINT22) | (0<<PCINT21) | (0<<PCINT20) | (0<<PCINT19) | (0<<PCINT18) | (0<<PCINT17) | (0<<PCINT16);
13}

Ну и сами обработчики:

01// обработчик прерывания INT0
02ISR(INT0_vect)
03
04  PassiveLeftIntFlag = !PassiveLeftIntFlag;
05}
06 
07// обработчик прерывания INT1
08ISR(INT1_vect)
09
10  PassiveRightIntFlag = !PassiveRightIntFlag;
11}
12 
13// обработчик прерывания PCINT2
14ISR(PCINT2_vect)
15
16  ActiveLeftIntFlag = !ActiveLeftIntFlag;
17}
18 
19// обработчик прерывания PCINT0
20ISR(PCINT0_vect)
21
22  ActiveRightIntFlag = !ActiveRightIntFlag;
23}

Теперь всё верно? :)

П.С. Избыточность в масках - для наглядности.

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

>> Теперь всё верно? :)

Да, все так.

Одинадцатую строчку (в сетапе) можно было вообще не писать. Т.к. прерывание PCINT1 не разрешено не важно как настроен регистр PCMSK1, выполяться оно не будет. Но на правильность выполнения это, конечно, не повлияет.

Monster
Offline
Зарегистрирован: 18.06.2012

Вроде работает все как надо, НО при подаче сигнала на ноги ардуина д2/д3/д7/д8 статус флагов в переменных обработчиков меняется на 1 моментально, а вот при отключении сигнала флаг становится нулевым довольно долго. 

Каковы могут быть причины?  Возможно надо принудительно внутри обработчиков опускать флаги прерываний, но они и сами через время должны обнуляться... :(

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

>> а вот при отключении сигнала...

Это что значит? Переход с высокого уровня на низкий?

>> Возможно надо принудительно внутри обработчиков опускать флаги прерываний...

Флаг прерывания автоматически сбрасывантся в 0 как только начинает выполняться обработчик этого прерывания.

Monster
Offline
Зарегистрирован: 18.06.2012

Evgen пишет:
Это что значит? Переход с высокого уровня на низкий?
Да.
Evgen пишет:
Флаг прерывания автоматически сбрасывантся в 0 как только начинает выполняться обработчик этого прерывания
Тогда почему же тогда флаг обнуляется так долго?

Весь скетч:

01// флаги прерываний
02volatile int PassiveLeftIntFlag = LOW;
03volatile int PassiveRightIntFlag = LOW;
04volatile int ActiveLeftIntFlag = LOW;
05volatile int ActiveRightIntFlag = LOW;
06 
07volatile boolean x=false;
08 
09// инициализация
10void setup()
11
12  // разрешение прерываний INT0 и INT1
13  EIMSK  =  (1<<INT0)  | (1<<INT1);
14  // настройка срабатывания прерываний на любому изменению
15  EICRA  =  (0<<ISC11) | (1<<ISC10) | (0<<ISC01) | (1<<ISC00);
16  // разрешение прерываний с портов B (PCINT[7:0]) и D (PCINT[23:16]), и запрет с порта C (PCINT[14:8])
17  PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (1<<PCIE0);
18  // маскирование всех ног, кроме PB0 и PD7 - по одной на PCINT0 и PCINT2
19  PCMSK0 |= (0<<PCINT7)  | (0<<PCINT6)  | (0<<PCINT5)  | (0<<PCINT4)  | (0<<PCINT3)  | (0<<PCINT2)  | (0<<PCINT1)  | (1<<PCINT0);
20  PCMSK1 |=                (0<<PCINT14) | (0<<PCINT13) | (0<<PCINT12) | (0<<PCINT11) | (0<<PCINT10) | (0<<PCINT9)  | (0<<PCINT8);
21  PCMSK2 |= (1<<PCINT23) | (0<<PCINT22) | (0<<PCINT21) | (0<<PCINT20) | (0<<PCINT19) | (0<<PCINT18) | (0<<PCINT17) | (0<<PCINT16);
22  
23  // настройка таймера на период = 1с
24  TIMSK1=0x01;   // enabled global and timer overflow interrupt
25  TCCR1A = 0x00; // normal operation page 148 (mode0)
26  TCNT1=0x0BDC;  // 16bit counter register
27  TCCR1B = 0x04; // start timer / set clock
28   
29  pinMode(13, OUTPUT);
30  digitalWrite(13,LOW);
31}
32 
33// обработчик прерывания INT0
34ISR(INT0_vect)
35
36  PassiveLeftIntFlag = !PassiveLeftIntFlag;
37}
38 
39// обработчик прерывания INT1
40ISR(INT1_vect)
41
42  PassiveRightIntFlag = !PassiveRightIntFlag;
43}
44 
45// обработчик прерывания PCINT2
46ISR(PCINT2_vect)
47
48  ActiveLeftIntFlag = !ActiveLeftIntFlag;
49}
50 
51// обработчик прерывания PCINT0
52ISR(PCINT0_vect)
53
54  ActiveRightIntFlag = !ActiveRightIntFlag;
55}
56 
57ISR (TIMER1_OVF_vect)
58{
59  TCNT1=0x0BDC; // set initial value to remove time error (16bit counter register)
60  x=true
61}
62 
63void loop()
64{
65  if (x==true)
66  {
67    digitalWrite(13,PassiveLeftIntFlag | PassiveRightIntFlag | ActiveLeftIntFlag | ActiveRightIntFlag);
68    x=false;
69  }
70}

 

Monster
Offline
Зарегистрирован: 18.06.2012

Нужно ли еще в регистре SREG взвести I-бит чтобы разрешить прерывания глобально, или этого не надо и он по дефолту = 1?

step962
Offline
Зарегистрирован: 23.05.2011

 Эту (и ей подобные) инструкцию:

PCMSK2 |= (1<<PCINT23) | (0<<PCINT22) | (0<<PCINT21) | (0<<PCINT20) | (0<<PCINT19) | (0<<PCINT18) | (0<<PCINT17) | (0<<PCINT16);

без ущерба для конечного результата можно сократить до

PCMSK2 |= (1<<PCINT23);

ибо, во-первых, выражение вида (0<<PCINT16) это то же самое, что просто 0, и, во-вторых, в выражениях побитового ИЛИ (|) 0 никак на результат не влияет.

Цитата:

Нужно ли еще в регистре SREG взвести I-бит чтобы разрешить прерывания глобально, или этого не надо и он по дефолту = 1?

"Нужно/не нужно" где, в какой момент? Однозначного ответа на этот вопрос дать нельзя - на то этот флаг и доступен, чтобы в критических секциях программы сбрасывать его, а затем снова устанавливать.

Ну а по дефолту он = 0. Если можно верить дейташитам от Атмеля.

Monster
Offline
Зарегистрирован: 18.06.2012

По дефолту он скорее = 1, т.к. в коде он нигде не включается, а прерывания работают.

Проблема оказалась несколько иной природы: судя по этой статье проблема связана с "дребезгом контактов".

И действительно, при замыкании входов на +5В даже пальцами (токи достаточно малы, но достаточны) диод на 13 ноге загорается, но гаснет весьма лениво.  А если же ногу закоротить на землю (или между собой) пальцем, то диод отрабатывает довольно адекватно в обе стороны.

Возможно изменение триггера с любого изменения логического уровня на стабильный лоу уровень решит эту проблему, а может и нет.

Правда в этом случае придется уже анализировать внутри PCINTх-обработчиков состояние ноги, но все же задержки... :(

По поводу сокращений я специально указал на то, что это для наглядности изложения проблемы. :)

step962
Offline
Зарегистрирован: 23.05.2011

Monster пишет:

По дефолту он скорее = 1, т.к. в коде он нигде не включается, а прерывания работают.

"-Видишь суслика?
-Нет.
-И я не вижу. А он там есть...
"

По умолчанию таки 0:

Просто скрытая от глаз простого пользователя Arduino обертка функции setup устанавливает этот флаг, а также делает некоторые другие необходимые подготовительные операции.

Monster пишет:

По поводу сокращений я специально указал на то, что это для наглядности изложения проблемы. :)

В полном соответствии с афоризмом "Язык дан человеку для того, чтобы скрывать свои мысли" ;)

Monster
Offline
Зарегистрирован: 18.06.2012

Это все хорошо, но как решить задачу исключив дребезг?

Емкость на вход или есть еще варианты?

Li2n
Offline
Зарегистрирован: 03.02.2013

Прошу помощи по прерыванию.

Пытаюсь INT0 активировать при переходе с 0 на 1. Пин2.

Но при отсоединении пина от земли прерывание всеравно вызывается. Не понимаю.

01#define LEDPIN 13        // Вывод светодиода
02#define BTNPIN 2         // Вывод кнопки
03 
04volatile word count = 0, voda = 0; 
05                        
06//boolean clapan = 0;
07//int count_vody=0, obor_in_litr=100;
08//float litry=0;
09 
10ISR(INT0_vect)
11{
12    count = 1000;           // Инициализировать счётчик
13}
14 
15void setup(){
16   
17    pinMode(LEDPIN, OUTPUT);                      // Вывод светодиода в режим вывода
18    pinMode(2, INPUT);                       // Вывод кнопки в режим ввода
19    EIMSK  =  (0<<INT0);
20    EICRA  =  (0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (1<<ISC00);
21    EIMSK  =  (1<<INT0);
22    
23    interrupts();                                 // Разрешить прерывания глобально
24    Serial.begin (9600);
25}
26 
27void loop(){
28   
29if (count>0) {
30  digitalWrite(LEDPIN, HIGH);
31  count=count-1;
32  }
33  else {
34  digitalWrite(LEDPIN, LOW);
35  }
36Serial.println (count);
37delay (5);
38}

 

step962
Offline
Зарегистрирован: 23.05.2011

Li2n пишет:

Прошу помощи по прерыванию.

Пытаюсь INT0 активировать при переходе с 0 на 1. Пин2.

Как вы думаете - для чего служит строка 20 вашего скетча? Правильно - для выбора режима работы прерывания INT0 (кстати и INT1 тоже). После этого я открываю даташит на ATMega328 (у вас этот микроконтроллер?), нахожу в нем главу 12 (External Interrupts), нахожу там табличку 12-2 (Interrupt 0 Sense Control). Ну и выясняю, что комбинация ICS01=0 & ICS00=1 задает режим "Any logical change on INT0 generates an interrupt request.", то бишь - "прерывание при любом изменении логического уровня"

Цитата:

Но при отсоединении пина от земли прерывание всеравно вызывается. Не понимаю.

1EICRA  =  (0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (1<<ISC00);

Вам по-прежнему непонятно? ;)

 

PS: "переход с 0 на 1" это "The rising edge of INT0 generates an interrupt request.". Режим задаваемый комбинацией ICS01=1 & ICS00=1. Все та же таблица 12-2. Все того же даташита.

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

Во первых вы не правильно включаете прерывания. В 20 строке вы настроили прерывание INT0 на ЛЮБОЕ изменение уровня.  Вот так надо:

120 EICRA=(1<<ISC01); // настроили прерывание INT0 по переднему фронту

19 строку изменяем на:

119 digitalWrite(2, HIGH); // подтягиваем пин 2 к +5в на всякий случай

И во вторых, в обработчике прерывания, в 12 строке, желательно добавить паузу, чтобы исключить дребезг контактов.

112 count=1000; delay(50);

 

 

maksim
Offline
Зарегистрирован: 12.02.2012

В обработчике прерывания задержку?
Крайне не рекомендую этого делать и работать она корректно все равно не будет.

Evgen
Evgen аватар
Offline
Зарегистрирован: 10.06.2011

maksim пишет:

В обработчике прерывания задержку?
Крайне не рекомендую этого делать и работать она корректно все равно не будет.

Кстати да, не надо. с IAR-ом перепутал, там __delay_cycles в прерываниях нормально работает.

Li2n
Offline
Зарегистрирован: 03.02.2013

Спасибо. Буду пробовать.

Даташит пока не скачивал.

Второй день только ковыряюсь с ардуинкой.

Нужно контроллировать датчик холла+ сигналы с купюроприемника принимать+монетоприемник.

Еще нужно одно прерывание, блин. И как то все это дело считывать.

С помехами вообще засада.

maksim
Offline
Зарегистрирован: 12.02.2012

Тогда можно было прерывания 0 и 1 настроить дуиновскими функциями.

Zahar
Zahar аватар
Offline
Зарегистрирован: 16.11.2013

Evgen пишет:

Написал библиотеку которая добавляет Ардуине три дополнительных внешних прерывания, может кому пригодится.

Огромное спасибо за библиотеку.

7up
Offline
Зарегистрирован: 27.12.2016

Всем привет. Можно понтять темку? я пока только учусь :) потому не все из данной темы осилил.

прошу подсказать туда я или не туда :)

сейчас использую ардуину нано и ее одно прерывание для фиксации срабатывания кнопки (например концевик двери). Считать внутри loop() не подходит, та как раз в 5мин я отправляю результаты счетчика на сервер, в это время отследить нажатие в loop() не реально, только использовать прерывание, сейчас использую его в режиме FALLING. Так вот задача инкрементить(считать) одной ардуинкой около 5-10 счетчиков(нажатий кнопок),частота нажатий каждой не чаще чем 1 в 5с.

Так как в одном корпусе находится и GSM модуль для GPRS соединения, а плодить в этом корпусе по ардуине на 2 счетчика(по 2 прерывания) не совсем красивый вариант. Использовать arduino zero или mega где больше прерываний казалось бы решит мою задачу, но они дороже и больше по размеру. Возможно есть более грамотное решение?

заранее спасибо.

7up
Offline
Зарегистрирован: 27.12.2016
1ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
2 {   
3     digitalWrite(13,digitalRead(8) and digitalRead(9));
4 }

 

верно ли я понимаю из данного мануала (http://playground.arduino.cc/Main/PinChangeInterrupt) что когда на одном из цифровых пинов от 8го до13го появиться логическая единица, то сработает прерывание и код остановиться? Далее мне нужно пройтись по этим пинам и проверить у кого еденица, в моем случае - это какой счетчик инкрементить.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Не совсем. Когда на одном из ваших пинов появится изменение состояния код не остановится, а произойдет передача управления на обработчик прерывания PCINT0. Далее, какая из ног "сработала" можно решить чтением всего порта сразу и операцией XOR с сохраненным предыдущим значением. В 1 остануться только те биты, которые изменились. Пробегая их в цикле (сдвигая например вправо делением на 2) и проверяя исходный бит можно получить ответ "куда сработало" в ноль или 1.

Примерно так сделано у меня в "общем обработчике" PCINTx:

Смотрите строки 250..271. Генератор процедуры ISR() собственно обработчик прерывания. В нем выделяется какая нога сработала и вызывается та подпрограмма, которая привязана к этой ноге с передачей её текущего значения ноги прерывания. Она уже внутри себя может посмотреть какое изменение (0->1 или 1->0) и что-то сделать по этому поводу.

Вот, как-то так. Тут файл-темплейт для генерации функций по мере надобности для разных случаев и плат.

7up
Offline
Зарегистрирован: 27.12.2016

Понял Вас, спасибо за код. 

Но по факту лучше использовать 2 External + 3 PinChange прерывания, как описано выше в теме, что бы не тратить ресурс на определение ноги инициатора, верно? Или данный вариант необходим только при высоких частотах, что бы не пропустить срабатывания? Если в моем случае частота срабатывания по каждому прерыванию будет не чаще чем 1с то можно смело использовать вариант с определением ног?

А возможно же еще использовать и вот эту библиотеку http://playground.arduino.cc/Main/PinChangeInt верно?

Попробую реализовать это в живую, что бы задавать меньше глупых вопросов :) и ужесли не получиться приду запомощью. 

Интересно ж не только реализовать, а и понять логику процесса.

Tohin
Offline
Зарегистрирован: 01.02.2016

Помогите разобратся с PCINT2

01#define set_bit(reg,value) reg |= (_BV(value))
02#define unset_bit(reg,value) reg &= ~(_BV(value))
03volatile uint8_t ReadPortD;  //тут храним состояние порта D Пины с 0-7 на ардуино UNO
04 
05 
06ISR(PCINT2_vect){      // сработало прерывание
07  unset_bit (PCICR,PCIE2);  //отключаем прерывание до отработки прерывания, во избежании повторных срабатываний
08  ReadPortD=PIND;   //записываем состояние порта D
09}
10 
11void setup() 
12{
13  pinMode(5,INPUT_PULLUP); // Clock Подключаем к INT1, нельзя переназначать
14  pinMode(6, INPUT_PULLUP); // второй вывод энкодера
15  pinMode(7, INPUT_PULLUP); // кнопка энкодера
16 
17  Serial.begin(9600);
18  while (!Serial);
19  set_bit (PCICR,PCIE2);//Включаем прерывание PCINT16-23 (PortD) PCIE2, регистр PCICR принимает значение  0b00000100;
20  PCMSK2 |= (_BV(PCINT23) | _BV(PCINT21)); //Указываем, что надо реагировать только на пины 5,7
21  // для порта D соответствуют pcint 16-23
22  Serial.println(PCMSK2,BIN);
23  sei();//включаем прерывания
24  Serial.println("ready");
25}
26 
27 
28 
29void loop() {
30    if (ReadPortD) {  // если сюда что-то записано, значит было прерывание. Прерывания отключены, надо бы не забыть их включить.
31      Serial.println("int detect");
32      Serial.print("Pind: ");
33      Serial.println(ReadPortD,BIN);
34      ReadPortD=0; //мы все отработали, значит можно обнулить переменную
35      set_bit (PCICR,PCIE2);  //включаем прерывание. Вроде не забыл
36    }
37 
38}

Запускаю, сначала замыкаю 6-й пин на землю, потом 5й пин на землю. Получаю вывод:

10100000  //состояние PCMSK2. указание реагировать на изменения 5-го и 7-го 
ready
int detect
Pind: 10100111  //Опа! прерывание сработало на падении (PCINT22/OC0A/AIN0) PD6
int detect 
Pind: 11000111 //Снова прерывание, но падение уже на (PCINT21/OC0B/T1) PD5. Стоп! А где поднятие уровня на PD6?!
int detect
Pind: 11100111// третье прерывание, это уже восстановление уровня на PD5
 
 
 
Почему прерывание срабатывает на падение уровня на PD6?
strarbit
Offline
Зарегистрирован: 12.06.2016

стр# 30 условие не правильное

Image already added
 
 
 
Tohin
Offline
Зарегистрирован: 01.02.2016

А можно, для альтернативно одаренных, поподробнее? ReadPortD изначально равен 0. Условие не выполняется. Пока не сработает прерывание и не запишет в эту переменную значение порта D. Если при замыкании PD6 на землю срабатывает прерывание, то условие отрабатывается как истинное - и это правильно и логично.
Но почему срабатывает прерывание pcint 21, когда оно отключено маской PCMSK2?

strarbit
Offline
Зарегистрирован: 12.06.2016

можете видеть изменение  состояние выводов в прерывании

01volatile uint8_t ReadPortD = 0;
02volatile boolean StatePCINT2 = false;
03 
04ISR(PCINT2_vect) {
05  PCICR &= ~_BV(PCIE2);
06  ReadPortD = PIND;
07  PCICR |= _BV(PCIE2);
08  StatePCINT2 = true;
09}
10 
11void setup() {
12  Serial.begin(9600);
13  pinMode(5, INPUT_PULLUP);
14  pinMode(6, INPUT_PULLUP);
15  pinMode(7, INPUT_PULLUP);
16  PCICR |= _BV(PCIE2);
17  PCMSK2 |= _BV(PCINT21) | _BV(PCINT23);
18  Serial.print("PCMSK2 > ");
19  Serial.println(PCMSK2, BIN);
20  Serial.print("PIND > ");
21  Serial.println(PIND, BIN);
22}
23 
24void loop() {
25  if (StatePCINT2) {
26    Serial.println("PCINT2 > ");
27    Serial.println(ReadPortD, BIN);
28    StatePCINT2 = false;
29  }
30}

Если у вас включен PCINT только на одном выводе порта, вы можете предположить, что прерывание PCINT в PortX связано с единственным, которое вы включили. Но, если вы используете два или более на одном и том же порту, вам необходимо прочитать регистр, чтобы определить, какое из них вызвано.

 

Image already added
 
 
 
Tohin
Offline
Зарегистрирован: 01.02.2016

Опять непонятно. Я точно так же в прерывании записываю состояние всех пинов порта D и в основном цикле вывожу их. Оттуда и вижу, что идет срабатывание на PD6 (на выводе четко виден 6й бит Pind: 10100111), который отключен маской PCMSK2 (которую я тоже проверил выводом в конце setup 10100000).

Зачем лишняя переменная StatePCINT2 если значение ReadPortD может изменится только при вызове прерывания?

И какое отношение это имеет к вызову прерывания по падению PD6?

Как честный человек, я проверил предлагаемый код. И очень удивился - нет ложных срабатываний на PD6!

Для проверки убрал из кода лишнюю переменную:

01volatile uint8_t ReadPortD = 0;
02volatile boolean StatePCINT2 = false;
03 
04ISR(PCINT2_vect) {
05  PCICR &= ~_BV(PCIE2);
06  ReadPortD = PIND;
07}
08 
09void setup() {
10  Serial.begin(9600);
11  pinMode(5, INPUT_PULLUP);
12  pinMode(6, INPUT_PULLUP);
13  pinMode(7, INPUT_PULLUP);
14  PCICR |= _BV(PCIE2);
15  PCMSK2 |= _BV(PCINT21) | _BV(PCINT23);
16  Serial.print("PCMSK2 > ");
17  Serial.println(PCMSK2, BIN);
18  Serial.print("PIND > ");
19  Serial.println(PIND, BIN);
20}
21 
22void loop() {
23  if (ReadPortD) {
24    Serial.print("PCINT2 > ");
25    Serial.println(ReadPortD, BIN);
26    ReadPortD = false;
27    PCICR |= _BV(PCIE2);
28  }
29}

Код все равно продолжает работать правильно. Скомпилировал свой код (там где "условие не правильное") - оно опять работает! 

Повторить проблему не удалось. Что за волшебство?