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


10

Я намагаюся використовувати переривання зміни штифтів, щоб виявити натиснуті кнопки. До цих пір я ніколи не працював з подібними перервами, і є деякі проблеми, тому я хочу переконатися, чи це правильне використання.

Якщо я отримав правильний опис даних, необхідно зробити наступне, щоб використовувати переривання зміни штифта:

  1. Встановіть, які PIN-коди потрібно керувати в регістрі PCMSK
  2. Увімкніть регістр PIN-кодів для управління перериванням зміни PIN-коду (PCICR)
  3. Увімкнути переривання
  4. Використовуйте відповідний вектор переривання

Проект: Простий Moodlamp, Кольори керовані за допомогою 4 кнопок.

Налаштування:

  • Atmega168A-PU
  • 4 міні-кнопкових вимикача
  • MOSFETS для управління моїм світлодіодним світлодіодом RGB 3 Вт

Ось код, який я використовую, працює не так, як очікувалося:

#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 запускає скидання атмеги

Те, що я перевірив:

  • Кнопки жодним чином не підключені до PIN-коду для скидання
  • Кнопки належним чином підключені до GND, якщо їх натиснути
  • Кнопки не підключаються до GND, якщо їх не натискати
  • Кнопки чудово працюють, якщо я використовую їх без перерви, наприклад:

    if (! (PINC & BUTTON4)) {PORTB ^ = BLUE; }

  • 16 МГц зовнішній кристал / внутрішній кристал
  • Будь-які помилки в маршрутизації
  • Я використовую 100nF конденсатор між PWR і GND на atmega
  • VCC (7), GND (8), GND (22), AVCC (20) підключені (оскільки мені не потрібен AREF, його не підключено)

Вам потрібні прапор PCIE1 (не PCIE2) та PCINT1_vect (не PCINT2)
microtherion

Чому PCIE1? Я використовую Реєстр C, тож якщо я порахую, це буде A (PCIE0), B (PCIE1), C (PCIE2)? У всякому разі, я спробував це з PCIE1 nad PCINT1_vect, і реакції немає, якщо натискати кнопки.
ехокс

1
Припустити ортогональність таких завдань може бути трохи ризикованою. У цьому конкретному випадку ви були б майже правильні, за винятком того, що ATmega168 не має порту А. У будь-якому випадку я пройшов таблицю даних та розбірку. Ще одна порада полягала в тому, що ви використовуєте 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 мс, що добре працює для мене :-) Мені все ще цікаво, чому переривання зміни штифтів не працює (поруч з підстрибуючими речами), але це працює :-) Дякую.
ехокс

1

Переривання зміни штифтів - кращий спосіб дебютування, ніж опитування. Перерваність зазвичай проходить через певну логіку, таку як D-Flip Flop або D-Latch. Хоча це правда, важче реалізувати цю процедуру дебютування з компіляторами вищого рівня. Як тільки відбувається переривання, прапор переривання не знімається, а включення переривання знімається, поки не наступить затримка. Як тільки затримка настала, перевіряється стан штифта, і якщо він все ще знаходиться у заданому стані, що викликало переривання, стан кнопки змінюється, а прапор переривання видаляється та встановлюється включення переривання. Якщо немає в стані, який спричинив ініціювання, встановлюється включення переривання, і стан залишається таким же. Це звільняє процесор від інших завдань. Періодично перериває витрачений час у програмі.


-1

"Переривання зміни шпильки зазвичай не є хорошим способом виявлення дій кнопки."

Неправильно. PC INT - найкращий варіант. Якщо ви користуєтесь опитуванням для перевірки стану кнопки, більшість часу нічого не буде виконано. Ви витрачаєте багато дорогоцінного часу на процесор. PC INT дозволяє виконувати дії лише за запитом.

"Це тому, що механічні кнопки відскакують, і ви отримаєте безліч безглуздих переривань, і тоді вам все одно доведеться робити розмову".

Правильно щодо підстрибування. Тим не менш, НІКОЛИ не слід відмовлятись від кнопки / перемикання всередині програми переривання (та сама причина: витрата часу на процесор). ІСР повинні бути дійсно короткими та ефективними, з урахуванням коду. Просто використовуйте апаратне розблокування. Зберігайте програмне забезпечення в чистоті!

Зручніше розблокувати апаратне забезпечення, дивіться тут / RC деблокація + тригер Schmitt для довідки. Я безліч разів використовував його з ПК INT, він ніколи не виходив з ладу.

Так що так, ви можете (і повинні) використовувати ПК INT, щоб отримати стан кнопки. Але ви також повинні використовувати належну апаратну розборку.


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

У більшості застосунків контролер працює в режимі очікування більшу частину часу, так чи інакше, виконуючи основний цикл. Також час процесора, необхідний для проведення перевірки стану IO і потенційно збільшення змінної, мінімальний. Реалізація простого деблокування в програмному забезпеченні майже не "безкоштовно", апаратне забезпечення коштує грошей. І не смійтесь за кілька центів, а складання коштує також грошей, і якщо ви використовуєте середні та великі обсяги товару, це не незначно. Це правда, що час ISR повинен бути коротким, але це навряд чи є аргументом у цьому випадку. Це, мабуть, більш критично, якщо ПК INT ISR спрацьовує 50 разів поспіль через підстрибування.
Rev1.0

@Nelson, "втрата часу процесора" має значення в одній програмі, а не в багатьох інших. Ви повинні кваліфікувати свою відповідь у ситуації, коли час процесора є критичним.
користувач1139880
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.