Правильное использование прерывания смены контакта


10

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

Если я правильно понял таблицу, для использования прерывания смены штифта необходимо сделать следующее:

  1. Установите, какие PIN-коды вы хотите контролировать в реестре PCMSK
  2. Включите регистр ПИН-кодов для управления прерыванием смены пинов (PCICR)
  3. Включить прерывания
  4. Используйте соответствующий вектор прерывания

Проект: Простой Moodlamp, Цвета управляются с помощью 4 кнопок.

Настроить:

  • Atmega168A-PU
  • 4 мини кнопочных переключателя
  • МОП-транзисторы для управления моим 3-ваттным светодиодом RGB

Вот код, который я использую, который не работает должным образом:

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

#define BUTTON1 (1<<PC5) 
#define BUTTON2 (1<<PC4) 
#define BUTTON3 (1<<PC3) 
#define BUTTON4 (1<<PC2) 

#define GREEN   (1<<PB1) 
#define BLUE    (1<<PB2) 
#define RED     (1<<PB3) 

void init() {

        // enable LED
        DDRB |= GREEN;
        DDRB |= BLUE;
        DDRB |= RED;

        // button pullups
        PORTC |= BUTTON1;
        PORTC |= BUTTON2;
        PORTC |= BUTTON3;
        PORTC |= BUTTON4;

        // pin change interrupts for buttons
        PCMSK1 |= PCINT13;
        PCMSK1 |= PCINT12;
        PCMSK1 |= PCINT11;
        PCMSK1 |= PCINT10;

        // enable pin change for buttons
        PCICR |= PCIE2;

        sei();

}

ISR(PCINT2_vect) {

                PORTB = BLUE;
}


void ledTest() {

                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;


                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;

                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
}

int main() {

        init();
        ledTest();

        _delay_ms(500);
        PORTB |= GREEN;

        while(1) {
                _delay_ms(100);
        }
}

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

Вопрос: правильно ли я пытаюсь использовать прерывания?

Проблемы с моей настройкой:

  • Кнопки 1-3 полностью игнорируются.
  • Button4 запускает сброс Atmega

Вещи, которые я проверил:

  • Кнопки никак не связаны с ПИН-кодом сброса
  • Кнопки правильно подключены к GND при нажатии
  • Кнопки не подключены к GND, если не нажаты
  • Кнопки работают хорошо, если я использую их без прерывания, например:

    if (! (PINC & BUTTON4)) {PORTB ^ = СИНИЙ; }

  • 16 МГц внешний кристалл / внутренний кристалл
  • Любые ошибки в маршрутизации
  • Я использую 100 нФ конденсатор между PWR и GND на Atmega
  • VCC (7), GND (8), GND (22), AVCC (20) подключены (так как мне не нужен AREF, он не подключен)

Вам нужен флаг PCIE1 (не PCIE2) и PCINT1_vect (не PCINT2)
микротерион

Почему PCIE1? Я использую регистр C, так что если я посчитаю, это будет A (PCIE0), B (PCIE1), C (PCIE2)? Во всяком случае, я попробовал это с PCIE1 nad PCINT1_vect, и нет никакой реакции, если я нажимаю кнопки.
echox

1
Может быть немного рискованно предполагать ортогональность в таких назначениях. В этом конкретном случае вы были бы почти правы, за исключением того, что ATmega168 не имеет порта A. В любом случае, я пошел по таблице и распиновке. Другая подсказка состояла в том, что вы использовали PCIE2, но устанавливали биты в PCMSK1; это не может быть правдой (к сожалению, я не знаю, почему ваш исправленный эскиз все еще не работает).
микротерион

Спасибо, я также понимаю, что сочетание программного обеспечения для отладки, которое зависит от аппаратного обеспечения самостоятельной сборки, не так просто ;-)
echox

Ответы:


14

Прерывания смены контактов, как правило, не являются хорошим способом определения действий кнопок. Это происходит потому, что механические кнопки отскакивают, и вы получите много бессмысленных прерываний, а затем вам все равно придется делать отладку в любом случае.

Лучшим способом является периодическое прерывание, например, каждые 1 мс (частота 1 кГц). На большинстве процессоров это длительное время, поэтому доля времени, затрачиваемого на прерывание, будет небольшой. Просто выберите состояние кнопки для каждого прерывания. Объявите новое состояние кнопки, если вы видели новое состояние 50 мс подряд. 50 мс длиннее, чем большинство кнопок отскакивают, но все еще достаточно коротки, чтобы люди не замечали или не заботились о задержке.

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

Подробнее о времени отклика:

Иногда, как и в этом случае, кто-то говорит, что 50 мс - это слишком длительное время отката. Это не относится к обычным кнопкам, нажимаемым людьми. Это может быть проблемой, возможно, в очень критичных по времени приложениях, таких как секундомер, но до сих пор я не сталкивался с ними. Я проверял это в начале 1980-х, и многие другие тоже.

Это правда, что типичное время отскока кнопки составляет около 10 мс, а почти все устанавливаются на 25 мс. Ограничивающим фактором времени отклика является человеческое восприятие. 50 мс немного короче, чем когда люди начинают замечать задержку, когда они ее не ищут. Даже тогда, это занимает намного больше времени, чтобы это раздражало. В некоторых случаях человек может обнаружить разницу между задержкой в ​​50 мс и 0 мс, если он специально ищет ее , но это совсем не то, что нажать кнопку и увидеть, что что-то происходит, и не думать о задержке.

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

Я сделал много продуктов с кнопками, отсеиваемыми прошивкой, используя время ожидания 50 мс. Ни разу клиент не упомянул даже о задержке. Они все приняли кнопки как работающие без проблем.


1
50 мс может быть слишком длинным для некоторых случаев (обычно 10-20 мс - это предел человеческого восприятия, и этого должно быть достаточно для обсуждения), но метод, описанный здесь, является подходящим способом.
Ласло Валько,

1
@Laszlo: Нет, 50 мс не слишком долго для обычного случая. Смотрите дополнение к моему ответу.
Олин Латроп

Я пробовал 50 мс, что отлично работает для меня :-) Мне все еще любопытно, почему не работает прерывание смены штырьков (кроме прыгающего), но это работает :-) Спасибо.
echox

1

Прерывания смены булавки - лучший способ отменить, чем опрос. Прерывание обычно проходит через некоторую логику, такую ​​как D-Flip Flop или D-Latch. Хотя это действительно так, реализовать эту процедуру отладки с помощью компиляторов более высокого уровня сложнее. Как только прерывание происходит, флаг прерывания не очищается, и разрешение прерывания очищается до тех пор, пока не произошла задержка. Как только задержка произошла, проверяется состояние контакта, и если он все еще находится в заданном состоянии, которое вызвало прерывание, состояние кнопки изменяется, и флаг прерывания очищается, и устанавливается разрешение прерывания. Если не в состоянии, которое вызвало инициирование, устанавливается разрешение прерывания, и состояние остается тем же. Это освобождает процессор для других задач. Периодическое прерывание тратит время в программе.


-1

«Прерывания смены контактов, как правило, не являются хорошим способом определения действий кнопок».

Неправильно. ПК INT является лучшим вариантом. Если вы используете опрос для проверки состояния кнопки, большую часть времени ничего не будет выполнено. Вы тратите много драгоценного процессорного времени. ПК INT позволяет выполнять действия только по запросу.

«Это потому, что механические кнопки отскакивают, и вы получите много бессмысленных прерываний, а затем вам все равно придется делать отладку».

Правильно о подпрыгивании. Тем не менее, вы НИКОГДА не должны отсоединять кнопку / переключатель внутри процедуры прерывания (та же самая причина: потеря процессорного времени). ISR должны быть очень короткими и эффективными с точки зрения кода. Просто используйте аппаратный дебасинг. Держите свое программное обеспечение в чистоте!

Аппаратная отладка более удобна, см. Здесь / RC debouncing + триггер Шмитта для справки. Я использовал его для ПК бесчисленное количество раз, он никогда не подводил.

Так что да, вы можете (и должны) использовать ПК INT для получения состояния кнопки. Но вы также должны использовать правильное аппаратное устранение неполадок.


2
Устранение неполадок программного обеспечения является правильным подходом, и большую часть времени небольшая дополнительная загрузка ЦП не имеет значения. Утверждение о том, что вам обычно приходится разбираться в оборудовании, в лучшем случае сомнительно. Сказать, что вы должны использовать аппаратный дебасинг во всех случаях, просто неправильно.
Олин Латроп

В большинстве приложений контроллер в большинстве случаев работает вхолостую, выполняя основной цикл. Кроме того, время ЦП, необходимое для выполнения проверки состояния ввода-вывода и потенциального приращения переменной, минимально. Внедрение простого устранения неполадок в программном обеспечении происходит практически бесплатно, оборудование стоит денег. И не смейтесь над несколькими центами, сборка также стоит денег, и если вы используете средние или большие объемы продукта, это немаловажно. Это правда, что время ISR должно быть коротким, но это вряд ли аргумент в этом случае. Вероятно, более критично, если PC INT ISR срабатывает 50 раз подряд из-за отскока.
rev1.0

@ Нельсон, «пустая трата процессорного времени» имеет значение в некоторых приложениях, а не во многих других. Вы должны квалифицировать свой ответ для ситуации, когда время процессора является критическим.
user1139880
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.