Багатозадачність та управління часом на Arduino

Багатозадачність в Arduino

Я не експерт з Arduino, хоча я давно не користувався цією платою. І робив це як інструмент, копіюючи та вставляючи вже створений код, але без особливого інтересу до вивчення того, як це працює, а просто з наміром змусити його працювати та вважати це корисним. Цього Різдва я трохи налаштував вертеп за допомогою світлодіодів та ультразвукового датчика HC-SR04. І я зупинився, щоб подивитися, що потрібно зробити.

Я просто хотів зробити різні речі з двома світлодіодами з одного й того ж сигналу. Упс, я швидко натрапив на те, що, на мою думку, буде одним з перших обмежень, з якими ви зіткнетеся, коли почнете возитися з Arduino. І не потрібно сильно ускладнювати. Я говорю лише про деякі світлодіоди, ви розумієте, що не можете зробити те, що хочете, правильно.

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

Розповім вам цей випадок детальніше. На Різдво я катався на вертепі та хотів, щоб певні світлодіодні лампочки вмикалися, коли наближалися мої доньки. Нічого складного, я просто хотів, щоб дві гілки світлодіодних лампочок працювали по-різному залежно від значень датчика наближення.

Я хотів, щоб коли хтось наближався менше ніж на 10 см:

  • Гілка вогнів, що веде до зірок, залишається увімкненою протягом 10 секунд
  • Інший, що входить всередину будинків, залишається увімкненим 10 секунд з моменту, коли вони відходять від Різдва.

Здається, це просто, чи не так? Що ж, це може спричинити великі проблеми. Оскільки Arduino не вміє працювати багатозадачно, він виконує одну команду за іншою.

Багатозадачність в Arduino, відредагована за допомогою fritzing

Я зібрав збірку з ультразвуковим датчиком HC-SR04 та двома світлодіодами, кожен з яких еквівалентний гілці Різдва. Перша частина зараз не важлива, оскільки вона полягає в налаштуванні налаштувань та роботи ультразвукового датчика в LOOP, але це можна знайти на тисячах сайтів. Можливо, іншим разом, якщо я запитаю більше, я зроблю спеціальний запит, поки що ось у вас (вибачте, я не вказав авторство, але я не пам'ятаю, звідки я це взяв).

Код HC-SR04 в Arduino

int ledPin1=8; int ledPin2=7; long distancia; long tiempo; long currenttime; long timepast; void setup() { // ініціалізувати цифровий вивід LED_BUILTIN як вихід. pinMode(ledPin1, OUTPUT); pinMode(ledPin2, OUTPUT); Serial.begin(9600); pinMode(3, OUTPUT); /*Активація виводу 9 як виходу: для ультразвукового імпульсу*/ pinMode(2, INPUT); /*Активація виводу 8 як входу: час відскоку ультразвуку*/ } // функція циклу виконується знову і знову нескінченно void loop() { digitalWrite(3,LOW); /* стабілізація датчика*/ delayMicroseconds(5); digitalWrite(3, HIGH); /* надсилання ультразвукового імпульсу*/ delayMicroseconds(10); tiempo=pulseIn(2, HIGH); /* Функція для вимірювання тривалості вхідного імпульсу. Виміряйте час, що минув між відправкою ультразвукового імпульсу та моментом, коли датчик отримує відскок, тобто: з моменту початку прийому відскоку на виводі 12 (ВИСОКИЙ рівень), до моменту припинення прийому (НИЗЬКИЙ рівень), тривалість вхідного імпульсу*/ distancia= int(0.017*tiempo); /*формула для розрахунку відстані з отриманням цілочисельного значення*/ /*Контроль відстані в сантиметрах за допомогою монітора послідовного порту*/ Serial.println("Відстань"); Serial.println(distancia); Serial.println("см"); delay(1000);

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

ДИВИСЬ ТАКОЖ  Повний посібник з найкращих IDE для Arduino

Рішення для керування світлодіодами

Перше, що спадає на думку, це почати ставити затримки. Не знаю чому, але всі новачки думають про затримку (), і це значно обмежує можливості, оскільки під час використання затримки () плата не працює, і тому ви не можете нічого іншого робити під час цього призупинення. Рішенням є використання millis ()

Тут я знайшов рішення, просте, засноване на if та лічильниках. Як сказав один мій вчитель, що завгодно можна запрограмувати з багатьма if поспіль. Але, звісно, ​​правда не дуже елегантна.

//якщо відстань менша за 10, увімкнути 2 світлодіоди та почати відлік часу за допомогою milis() if (distancia < 10){ digitalWrite(ledPin1, HIGH); digitalWrite(ledPin2, HIGH); currenttime=millis(); } //якщо відстань більша за 10, перевірити час від увімкнення, і вона більша за вимкнення LED1 if (distancia > 10){ timepast=millis()-currenttime; digitalWrite(ledPin1, LOW); //якщо відстань більша за 10000, вимкнути LED2 if(timepast>10000){ digitalWrite(ledPin2,LOW); } } }

Цей код має на меті забезпечити постійне виконання цих трьох умов if, щоб він проходив через них так швидко, що здається, що він робить кілька речей одночасно. Але, як ми знаємо, він продовжує виконувати речення одне за одним.

Після вимірювання відстані та її збереження у змінній distance, буде виконано обчислення if:

  • Перша перевіряє, чи відстань менша за бажані 10 сантиметрів. Якщо так, ми вмикаємо два світлодіоди та починаємо відлік часу за допомогою milis().
  • і ми перейдемо до другого, якщо для відстані більше 10 см. Якщо це відповідає вимогам, ми обчислюємо час, що минув, і вимикаємо світлодіод 1, який залежав лише від відстані.
  • Ми б перейшли до третього, якби перевірили, чи минуло більше 10 секунд з моменту активації лічильника, і якщо так, то вимкнули контакт 2.
  • І так цикл продовжується. І знову.
ДИВИСЬ ТАКОЖ  Як виправити AVRDUDE: ser_open(): не вдається відкрити пристрій на Arduino

Зрештою, хоча рішення спрацювало, стало зрозуміло, що з цією проблемою стикалися багато людей, і що має бути більш ортодоксальне рішення. Я почав шукати і знайшов гарне рішення (напевно, не єдине) від хлопців з Adafruit та об'єктно-орієнтованого програмування . Воно полягає у створенні об'єктів з визначеними класами для швидких викликів і відсутності необхідності повторювати код сотні разів у нашій програмі.

Зрештою, це «те саме», що й моє рішення з лічильниками if +, але набагато елегантніше, і це забезпечує набагато читабельніший та набагато ефективніший код.

Управління багатозадачністю неминуче призводить до управління часом в Arduino . Спочатку це не поміщалося в статті, але я думаю, що це дуже цікаво.

Функції часу Arduino

Як я вже казав, я думаю, що існує велика залежність із затримкою (), можливо тому, що люди, які починають, бачать цю функцію у всіх прикладах, які зазвичай використовуються, від моргання до будь-якого світлофора чи будь-якої маніпуляції з увімкненням та вимкненням світлодіодів.

Затримка має дуже велику проблему, і вона полягає в тому, що коли ми викликаємо delay() на певний час, все зупиняється. Плата не зчитує жодного датчика, не продовжує виконувати речення і взагалі нічого не робить, просто чекає, поки мине вказаний нами час, і, звичайно, якщо ми хочемо використовувати плату для кількох речей одночасно, це неможливо.

Нам доведеться поглянути на millis() та навіть delayMicroseconds(). А ще у нас є micros() , яка повертає кількість мікросекунд з моменту початку роботи програми.

Блимати без затримки

Класний приклад того, як це працює, — це запустити міфічний Blink без затримки . Основна відмінність полягає в тому, щоб забути про функцію delay() і використовувати milis(), щоб мати змогу рахувати час між операціями.

2 думки про “Багатозадачність та управління часом на Arduino”

  1. Не впевнений, чи це допоможе, але перегляньте TaskManager ( https://github.com/drsteveplatt/TaskManager ). Це легкий перемикач завдань, якому потрібно близько 20 мкс для перемикання між завданнями. У мене на nano працювало понад десяток незалежних завдань, включаючи запуск багатьох світлодіодів, що змінюються, контролер таймлапсу для камери Canon, інтерфейс клавіатури/MIDI (fluxamasynth)/панелі перемикання тощо. (Усі це різні програми, не всі одночасно.)

    відповісти

Залишити коментар