Багатозадачність і переривання на arduino, роботоша
Багатозадачність і переривання на Arduino
Що таке переривання?
Переривання - це сигнал, який повідомляє процесору, що потрібно негайно зупинити те, що він зараз робить, і зробити деякі операції, що мають високий пріоритет. Ця обробка з високим пріоритетом називається обробником переривань (interrupt handler).
Якщо ми реалізуємо деякуфункцію і приєднані її до переривання, то ця функція буде викликана всякий раз, коли з'явиться сигнал переривання. Після повернення з обробника переривання, процесор продовжить обробляти те, що він робив до переривання.
Переривання можуть бути створені декількома джерелами:
- Одним з таймерів Arduino. формуючи переривання по таймеру;
- Зміною стану одного з входів зовнішніх переривань;
- Зміна стану одного з групи пинов.
При використанні переривань, немає необхідності писати код в loop (). постійно перевіряє високопріоритетних умова переривання. Не потрібно турбуватися про повільної реакції або пропущених натисканнях кнопок через занадто довго виконуються підпрограм.
Процесор буде автоматично зупиняти те, що він робить в момент виникнення переривання і викликати ваш обробник переривання. Вам просто потрібно написати код, який відповідає на переривання щоразу, коли воно відбувається.
Переривання по таймеру Arduino
Таймер і переривання по таймеру дозволяють нам зробити саме це. Ми можемо встановити таймер, щоб він переривав нас один раз в мілісекунди. Таймер буде, насправді, повідомляти нам, що пора перевірити годинник!
Arduino має три таймера: Timer0. Timer1 і Timer2. Timer0 вже налаштований для генерації мілісекунд переривань, оновлюючи лічильник мілісекунд, що передається в millis (). Це саме те, що нам потрібно!
Таймери - це прості лічильники, які вважають за певною частотою, що отримується з системних 16Мгц. Ми можемо конфігурувати дільник частоти для отримання необхідної частоти і різних режимів рахунку. Ми також можемо налаштувати їх для генерації переривань при досягненні таймером деяких заданих значень.
Timer0 є 8-бітовим, вважає від 0 до 255 і генерує переривання, при переповненні (перевищенні значення в 255). Він використовує тактовий дільник на 64 за замовчуванням, щоб дати нам частоту переривань 976.5625 Гц (досить близько до 1 кГц для наших цілей). Ми не будемо змінювати частоту в Timer0, тому що це точно порушить роботу millis ()!
регістри порівняння
У регістрах порівняння зберігаються дані, які постійно порівнюються зі станом таймера / лічильника. Встановимо регістр порівняння (OCR0A) для генерації іншого переривання десь в середині цього рахунку. Наведений нижче код буде генерувати переривання TIMER0_COMPA щоразу, коли значення лічильника проходить 0xAF.
Бібліотеки для роботи з перериваннями
У мережі можна знайти кілька бібліотек для роботи з таймерами. Багато просто постійно опитують millis () так само, як ми робили це в минулий раз. Але є деякі, які дозволяють налаштувати таймери для генерації переривань.
Відмінні бібліотеки TimerOne і TimerThree від Paul Stoffregan дають безліч низькорівневих можливостей для конфігурації переривань за таймером. Бібліотека TimerThree не працює на Arduino UNO. Її можна використовувати з Leonardo. Mega 2560 і деякими платами Teensy.
Arduino UNO має тільки два входи зовнішніх переривань. Але що робити якщо потрібно більше двох входів? На щастя Arduino UNO підтримує переривання «pin-change» (зі зміни входу) для всіх пинов.
Переривання по зміні входу - це те ж саме що і зовнішні переривання. Різниця в тому, що перші генеруються по зміні стану на будь-якому з 8 відповідних пинов. Вони трохи більш складні в обробці, так як ви повинні відслідковувати останнє відоме стан всіх 8 пинов, щоб з'ясувати, який з 8 пинов викликав це переривання.
Бібліотека PinChangeInt реалізує зручний інтерфейс для переривань по зміні входу.
Правила роботи з перериваннями
Для того, щоб все працювало гладко, краще використовувати не більше 10 різних переривань.
Якщо все має високий пріоритет, значить високого пріоритету немає ні у чого
Обробники переривань повинні використовуватися для обробки тільки пріоритетних, чутливих до часу подій. Пам'ятайте, що переривання відключені, поки ви перебуваєте в обробнику переривання. Якщо ви спробуєте зробити занадто багато на рівні переривання, ви отримаєте найгірший відповідь на інші переривання.
Одне переривання в кожен момент часу
Коли програма знаходиться в функції обробки переривання, то інші переривання відключені. Це має два важливих наслідки:
- Робота, яка виконується в функції обробки переривання повинна бути короткою, щоб не пропустити не одного переривання.
- Код, що виконується в функції обробки переривання не повинен викликати нічого такого, що вимагало б, щоб переривання були активні (наприклад, delay (). Або що-небудь, що використовує шину I 2 C). Це призведе до зависання програми.
Відкладіть тривалу обробку в loop ()
Якщо вам необхідно зробити велику обробку у відповідь на переривання, використовуйте оброблювач переривання для того, щоб зробити те, що необхідно, а потім встановіть змінну стану volatile. показує, що подальша обробка не потрібна. При виконанні функції Update () з loop () перевірте змінну стану, на предмет того, чи не потрібна якась наступна обробка.
Перевірка перед переконфігуруванні таймера
Таймери є обмеженим ресурсом. На Arduino UNO їх всього 3, і вони використовуються для багатьох речей. Якщо ви заплуталися з конфігурацією таймера, деякі речі можуть перестати працювати. Наприклад, на Arduino UNO:
Безпечне спільне використання даних
Оскільки переривання призупинить всі, що процесор робить, ми повинні потурбуватися про обмін даними між обработчиками переривань і кодом в loop ().
Іноді компілятор спробує оптимізувати свій код для збільшення продуктивності. Іноді, в результаті цієї оптимізації, копії часто використовуваних змінних будуть зберігатися в регістрі для швидкого доступу до них. Проблема в тому, що якщо одна з цих змінних спільно використовується оброблювачем переривання і кодом в loop (). то, в кінцевому підсумку, в ній може виявитися несвіжа копія замість реального значення. Маркування змінної як voltatile повідомляє компілятору, що не потрібно робити ці потенційно небезпечні оптимізації.
Навіть позначка змінної як volatile буде не достатнім в разі, якщо змінна більше, ніж ціле (наприклад, рядок, масив, структура і т.п.). Великим змінним іребуется кілька циклів інструкцій для поновлення, і якщо переривання відбувається в середині цього оновлення, дані можуть бути пошкоджені. Якщо у вас є великі змінні або структури, які спільно використовуються з обробником переривань, ви повинні відключити переривання при оновленні їх з loop (). Зауважу, що переривання відключені в обробнику переривання вже за замовчуванням.
Як ви оцінюєте цю публікацію? (57 голосів, середня оцінка: 4.86 з 5)