- Що таке багатозадачність?
- Чому пропускати затримку () в Arduino?
- Навіщо використовувати міліс ()?
- Потрібні компоненти
- Кругова діаграма
- Програмування Arduino UNO для багатозадачності
Багатозадачність привела комп'ютери до революції, де одна або кілька програм можуть працювати одночасно, що підвищує ефективність, гнучкість, адаптивність і продуктивність. У вбудованих системах мікроконтролери також можуть обробляти багатозадачність і виконувати дві або більше завдань одночасно, не зупиняючи поточні інструкції.
У цьому підручнику ми дізнаємося, як Arduino виконує багатозадачність за допомогою функції Arduino millis. Зазвичай функція затримки () використовується в Arduino для періодичного завдання, такого як світлодіодне блимання, але ця функція затримки () зупиняє програму на певний час і не дозволяє виконувати інші операції. Тож у цій статті пояснюється, як ми можемо уникнути використання функції delay () і замінити її на millis () для одночасного виконання декількох завдань та перетворення Arduino на багатозадачність. Перш ніж вдаватися до деталей, давайте почнемо з заниження багатозадачності.
Що таке багатозадачність?
Багатозадачність означає просто одночасне виконання декількох завдань або програм. Майже всі операційні системи мають багатозадачність. Цей тип операційних систем відомий як MOS (багатозадачна операційна система). MOS може бути мобільним або настільним ПК. Хороший приклад багатозадачності в комп'ютерах - це коли користувачі одночасно запускають електронну пошту, веб-браузер, медіаплеєр, ігри, і якщо користувачі не хочуть використовувати програму, вона працює у фоновому режимі, якщо вона не закрита. Кінцевий користувач використовує всі ці програми одночасно, але ОС сприймає цю концепцію дещо інакше. Давайте обговоримо, як ОС управляє багатозадачністю.
Як видно на малюнку, центральний процесор ділить час на три рівні частини і призначає кожну частину кожному завданням / застосунку. Так виконується багатозадачність у більшості систем. Концепція буде майже однаковою для багатозадачності Arduino, за винятком того, що розподіл часу буде дещо іншим. Оскільки Arduino працює на низьких частотах, а оперативна пам'ять порівняно з ноутбуком / мобільним пристроєм / ПК, тому час, що відводиться кожному завданню, також буде різним. Arduino також має функцію затримки (), яка широко використовується. Але перед початком обговоримо, чому ми не повинні використовувати функцію delay () у будь-якому проекті.
Чому пропускати затримку () в Arduino?
Якщо враховується довідкова документація Arduino, то існує два типи функцій затримки, перша - delay (), а друга - delayMicroseconds (). Обидві функції однакові з точки зору генерації затримки. Єдина відмінність полягає в тому, що у функції delay () ціле число параметра передається в мілісекундах, тобто якщо ми пишемо delay (1000), тоді затримка буде 1000 мілісекунд, тобто 1 секунду. Подібно до функції delayMicroseconds () параметр передається в мікросекундах, тобто якщо ми пишемо delayMicroseconds (1000), тоді затримка буде 1000 мікросекунд, тобто 1 мілісекунда.
Ось справа в тому, що обидві функції призупиняють програму на час, пройдений функцією затримки. Отже, якщо ми даємо затримку в 1 секунду, тоді процесор не може перейти до наступної інструкції, поки не пройде 1 секунда. Подібним чином, якщо затримка становить 10 секунд, програма зупиниться на 10 секунд, а процесор не дозволить виконувати наступні інструкції, поки не пройде 10 секунд. Це заважає роботі мікроконтролера з точки зору швидкості та виконання інструкцій.
Найкращим прикладом для пояснення недоліку функції затримки є використання двох кнопок. Розглянемо, що ми хочемо перемикати два світлодіоди за допомогою двох кнопок. Отже, якщо натиснути одну кнопку, тоді відповідний світлодіод повинен світитися протягом 2 секунд, так само, якщо натискати другу, тоді світлодіод повинен світитися протягом 4 секунд. Але коли ми використовуємо затримку (), якщо користувач натискає першу кнопку, програма зупиниться на 2 секунди, а якщо користувач натисне другу кнопку до затримки 2 секунди, тоді мікроконтролер не прийме вхід, оскільки програма є на етапі зупинки.
В офіційній документації Arduino це чітко згадується в описі функції "Примітки та попередження про затримку ()". Ви можете пройти це і перевірити це, щоб зробити це більш зрозумілим.
Навіщо використовувати міліс ()?
Щоб подолати проблему, спричинену затримкою, розробник повинен використовувати функцію millis (), якою легко скористатися, як тільки ви станете звичною, і вона використовуватиме 100% продуктивність процесора, не створюючи жодних затримок у виконанні інструкцій. millis () - це функція, яка просто повертає кількість мілісекунд, що минули з тих пір, як плата Arduino почала запускати поточну програму, не заморожуючи програму. Це число буде переповнено (тобто повернеться до нуля) приблизно через 50 днів.
Подібно до того, як Arduino має delayMicroseconds (), він також має мікроверсію millis () як мікро (). Різниця між мікро та мілісекунтами полягає в тому, що мікросигнал () переповнюється приблизно через 70 хвилин, порівняно із мілісекундами (), який становить 50 днів. Отже, залежно від програми, ви можете використовувати міліс () або мікро ().
Використання міліс () замість затримки ():
Щоб використовувати millis () для синхронізації та затримки, вам потрібно записати та зберегти час, коли відбулася дія, щоб почати час, а потім з інтервалом перевірити, чи минув визначений час. Отже, як зазначено, зберігайте поточний час у змінній.
unsigned long currentMillis = millis ();
Нам потрібні ще дві змінні, щоб з’ясувати, чи минув необхідний час. Ми зберегли поточний час у змінній currentMillis, але нам також потрібно знати, що коли почався період синхронізації та скільки часу це період. Так оголошено Interval та previousMillis . Інтервал повідомляє нам про затримку часу, а previosMillis зберігатиме останній раз, коли сталася подія.
unsigned long previousMillis; без підпису довгий період = 1000;
Щоб це зрозуміти, візьмемо приклад простого миготіння світлодіода. Період = 1000 покаже нам, що світлодіод блиматиме протягом 1 секунди або 1000 мс.
const int ledPin = 4; // контактний номер світлодіода підключений int ledState = LOW; // використовується для встановлення стану світлодіода unsigned long longMillis = 0; // буде зберігати останній раз, коли світлодіод блимав const long period = 1000; // період, протягом якого блимати в ms void setup () { pinMode (ledPin, OUTPUT); // встановлюємо ledpin як вихід } void loop () { unsigned long currentMillis = millis (); // зберігаємо поточний час if (currentMillis - previousMillis> = period) {// перевіряємо, чи пройшло 1000 мс previousMillis = currentMillis; // зберігаємо останній раз, коли ви блимали світлодіодом if (ledState == LOW) {// якщо світлодіод вимкнений, увімкніть його і навпаки ledState = HIGH; } ще { ledState = LOW; } digitalWrite (ledPin, ledState); // встановити світлодіод із ledState знову блимати } }
Ось, твердження
Переривання в Arduino працюють так само, як і в інших мікроконтролерах. На платі Arduino UNO є два окремі штирі для кріплення переривань на штифтах GPIO 2 та 3. Ми докладно висвітлили це в підручнику Arduino Interrupts, де ви можете дізнатись більше про переривання та як ними користуватися.
Тут ми покажемо багатозадачність Arduino, працюючи одночасно з двома завданнями. Завдання включатимуть блимання двох світлодіодів з різною затримкою за часом, а також кнопку, яка буде використовуватися для керування станом увімкнення / вимкнення світлодіода. Тож одночасно будуть виконуватися три завдання.
Потрібні компоненти
- Arduino UNO
- Три світлодіоди (будь-який колір)
- Опіри (470, 10k)
- Перемички
- Макет
Кругова діаграма
Схема для демонстрації використання функціонування Arduino Millis () дуже проста і не має багато компонентів для приєднання, як показано нижче.
Програмування Arduino UNO для багатозадачності
Програмування Arduino UNO для багатозадачності вимагатиме лише тієї логіки, яка стоїть за тим, як працює millis (), що пояснюється вище. Перед початком програмування Arduino UNO для багатозадачності рекомендується знову і знову вправляти світлодіод, що блимає, використовуючи мілісекунди, щоб зрозуміти логіку і почувати себе комфортно. У цьому посібнику переривання також використовується одночасно з millis () для багатозадачності. Кнопка буде перериванням. Отже, щоразу, коли генерується переривання, тобто натискається кнопка, світлодіод перемикається в стан увімкнення або вимкнення.Програмування починається з оголошення номерів контактів, де підключені світлодіоди та кнопка.
int led1 = 6; int led2 = 7; int toggleLed = 5; int pushButton = 2;
Далі ми пишемо змінну для збереження стану світлодіодів для подальшого використання.
int ledState1 = LOW; int ledState2 = LOW;
Як пояснено вище у прикладі блимання, змінні для періоду та попереднього мільйона оголошено для порівняння та генерування затримки для світлодіодів. Перший світлодіод блимає через кожну 1 секунду, а інший світлодіод блимає через 200 мс.
unsigned long previousMillis1 = 0; const довгий період1 = 1000; unsigned long previousMillis2 = 0; const довгий період2 = 200;
Ще одна міліс-функція буде використана для генерування затримки розриву звуку, щоб уникнути багаторазових натискань кнопки. Буде такий же підхід, як і вище.
int debouncePeriod = 20; int debounceMillis = 0;
Ці три змінними буде використовуватися для зберігання стану кнопки, як переривання, перемикання світлодіода і кнопкового стану.
bool buttonPushed = false; int ledChange = LOW; int lastState = HIGH;
Визначте дію штифта, який штифт працюватиме як ВХІД або ВИХІД.
pinMode (led1, OUTPUT); pinMode (led2, OUTPUT); pinMode (toggleLed, OUTPUT); pinMode (pushButton, INPUT);
Тепер визначте вивід переривання, приєднавши переривання із визначенням ISR та режиму переривання. Зауважте, що рекомендується використовувати digitalPinToInterrupt (pin_number) при оголошенні функції attachInterrupt (), щоб перевести фактичний цифровий pin в певний номер переривання.
attachInterrupt (digitalPinToInterrupt (pushButton), pushButton_ISR, CHANGE);
Підпрограма переривання записана, і вона змінить лише прапор buttonPushed. Зверніть увагу, що підпрограма переривання повинна бути якомога коротшою, тому спробуйте написати її та мінімізуйте зайві інструкції.
void pushButton_ISR () { buttonPushed = true; }
Цикл починається із збереження значення міліс у змінній currentMillis, яке зберігатиме значення часу, що минув кожен раз, коли цикл повторюється.
unsigned long currentMillis = millis ();
У багатозадачності є три функції: блимайте одним світлодіодом через 1 секунду, блимайте другим світлодіодом через 200 мс і якщо натиснута кнопка, вимкніть / увімкніть світлодіод. Тож для виконання цього завдання ми напишемо три частини.
Першим є перемикання світлодіодів стану після кожної 1 секунди, порівнюючи Мілліс пройшло.
якщо (currentMillis - попереднійMillis1> = період1) { попереднійMillis1 = поточнийMillis; якщо (ledState1 == LOW) { ledState1 = HIGH; } ще { ledState1 = LOW; } digitalWrite (led1, ledState1); }
По- друге, по-друге, він перемикає світлодіод через кожні 200 мс, порівнюючи минулі мілі. Пояснення вже пояснено раніше в цій статті.
якщо (currentMillis - попереднійMillis2> = період2) { попереднійMillis2 = поточнийMillis; якщо (ledState2 == LOW) { ledState2 = HIGH; } ще { ledState2 = LOW; } digitalWrite (led2, ledState2); }
Нарешті, відстежується прапорець buttonPushed , і після генерування затримки розриву в 20 мс він просто перемикає стан світлодіода, що відповідає кнопці, прикріпленій як переривання.
if (buttonPushed = true) // перевіряємо, чи викликається ISR { if ((currentMillis - debounceMillis)> debouncePeriod && buttonPushed) // генеруємо 20мс затримки розмивання, щоб уникнути багаторазових натискань { debounceMillis = currentMillis; // зберігаємо час останньої затримки розмови, якщо (digitalRead (pushButton) == LOW && lastState == HIGH) // змінимо світлодіод після натискання кнопки { ledChange =! ledChange; digitalWrite (toggleLed, ledChange); lastState = LOW; } ще if (digitalRead (pushButton) == HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = false; } }
На цьому підручник з Arduino millis () закінчений. Зауважте, що для того, щоб звикнути до milis (), просто потренуйтеся впровадити цю логіку в деякі інші програми. Ви також можете розширити його, використовуючи двигуни, сервомотори, датчики та інші периферійні пристрої. У разі будь-яких сумнівів, будь ласка, пишіть на наш форум або коментуйте нижче.
Повний код та відео для демонстрації використання функції milis в Arduino наведено нижче.