Вам понадобится
- - Arduino;
- - 1 светодиод;
- - 1 пьезопищалка.
Инструкция
1
Вообще говоря, Arduino не поддерживает настоящее распараллеливание задач, или мультипоточность.
Но можно при каждом повторении цикла "loop()" указать микроконтроллеру проверять, не наступило ли время выполнить некую дополнительную, фоновую задачу. При этом пользователю будет казаться, что несколько задач выполняются одновременно.
Например, давайте будем мигать светодиодом с заданной частотой и параллельно этому издавать нарастающие и затихающие подобно сирене звуки из пьезоизлучателя.
И светодиод, и пьезоизлучатель мы уже не раз подключали к Arduino. Соберём схему, как показано на рисунке. Если вы подключаете светодиод к цифровому выводу, отличному от "13", не забывайте о токоограничивающем резисторе примерно на 220 Ом.
Но можно при каждом повторении цикла "loop()" указать микроконтроллеру проверять, не наступило ли время выполнить некую дополнительную, фоновую задачу. При этом пользователю будет казаться, что несколько задач выполняются одновременно.
Например, давайте будем мигать светодиодом с заданной частотой и параллельно этому издавать нарастающие и затихающие подобно сирене звуки из пьезоизлучателя.
И светодиод, и пьезоизлучатель мы уже не раз подключали к Arduino. Соберём схему, как показано на рисунке. Если вы подключаете светодиод к цифровому выводу, отличному от "13", не забывайте о токоограничивающем резисторе примерно на 220 Ом.
2
Напишем вот такой скетч и загрузим его в Ардуино.
После загрузки платы видно, что скетч выполняется не совсем так как нам нужно: пока полностью не отработает сирена, светодиод не мигнёт, а мы бы хотели, чтобы светодиод мигал ВО ВРЕМЯ звучания сирены. В чём же здесь проблема?
Дело в том, что обычным образом эту задачу не решить. Задачи выполняются микроконтроллером строго последовательно. Оператор "delay()" задерживает выполнение программы на указанный промежуток времени, и пока это время не истечёт, следующие команды программы не будут выполняться. Из-за этого мы не можем задать разную длительность выполнения для каждой задачи в цикле "loop()" программы.
Поэтому нужно как-то сымитировать многозадачность.
После загрузки платы видно, что скетч выполняется не совсем так как нам нужно: пока полностью не отработает сирена, светодиод не мигнёт, а мы бы хотели, чтобы светодиод мигал ВО ВРЕМЯ звучания сирены. В чём же здесь проблема?
Дело в том, что обычным образом эту задачу не решить. Задачи выполняются микроконтроллером строго последовательно. Оператор "delay()" задерживает выполнение программы на указанный промежуток времени, и пока это время не истечёт, следующие команды программы не будут выполняться. Из-за этого мы не можем задать разную длительность выполнения для каждой задачи в цикле "loop()" программы.
Поэтому нужно как-то сымитировать многозадачность.
3
Вариант, при котором Arduino будет выполнять задачи псевдо-параллельно, предложен разработчиками Ардуино в статье https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay.
Суть метода в том, что при каждом повторении цикла "loop()" мы проверяем, настало ли время мигать светодиодом (выполнять фоновую задачу) или нет. И если настало, то инвертируем состояние светодиода. Это своеобразный вариант обхода оператора "delay()".
Существенным недостатком данного метода является то, что участок кода перед блоком управления светодиодом должен выполняться быстрее, чем интервал времени мигания светодиода "ledInterval". В противном случае мигание будет происходить реже, чем нужно, и эффекта параллельного выполнения задач мы не получим. В частности, в нашем скетче длительность изменения звука сирены составляет 200+200+200+200 = 800 мсек, а интервал мигания светодиодом мы задали 200 мсек. Но светодиод будет мигать с периодом 800 мсек, что в 4 раза отличается от того, что мы задали. Вообще, если в коде используется оператор "delay()", в таком случае трудно сымитировать псевдо-параллельность, поэтому желательно его избегать.
В данном случае нужно было бы для блока управления звуком сирены также проверять, пришло время или нет, а не использовать "delay()". Но это бы увеличило количество кода и ухудшило читаемость программы.
Суть метода в том, что при каждом повторении цикла "loop()" мы проверяем, настало ли время мигать светодиодом (выполнять фоновую задачу) или нет. И если настало, то инвертируем состояние светодиода. Это своеобразный вариант обхода оператора "delay()".
Существенным недостатком данного метода является то, что участок кода перед блоком управления светодиодом должен выполняться быстрее, чем интервал времени мигания светодиода "ledInterval". В противном случае мигание будет происходить реже, чем нужно, и эффекта параллельного выполнения задач мы не получим. В частности, в нашем скетче длительность изменения звука сирены составляет 200+200+200+200 = 800 мсек, а интервал мигания светодиодом мы задали 200 мсек. Но светодиод будет мигать с периодом 800 мсек, что в 4 раза отличается от того, что мы задали. Вообще, если в коде используется оператор "delay()", в таком случае трудно сымитировать псевдо-параллельность, поэтому желательно его избегать.
В данном случае нужно было бы для блока управления звуком сирены также проверять, пришло время или нет, а не использовать "delay()". Но это бы увеличило количество кода и ухудшило читаемость программы.
4
Чтобы решить поставленную задачу, воспользуемся замечательной библиотекой ArduinoThread, которая позволяет с лёгкостью создавать псевдо-параллельные процессы. Она работает похожим образом, но позволяет не писать код по проверке времени - нужно выполнять задачу в этом цикле или не нужно. Благодаря этому сокращается объём кода и улучшается читаемость скетча. Давайте проверим библиотеку в действии.
Первым делом скачаем с официального сайта https://github.com/ivanseidel/ArduinoThread/archive/master.zip архив библиотеки и разархивируем его в директорию "libraries" среды разработки Arduino IDE. Затем переименуем папку "ArduinoThread-master" в "ArduinoThread".
Первым делом скачаем с официального сайта https://github.com/ivanseidel/ArduinoThread/archive/master.zip архив библиотеки и разархивируем его в директорию "libraries" среды разработки Arduino IDE. Затем переименуем папку "ArduinoThread-master" в "ArduinoThread".
5
Схема подключений останется прежней. Изменится лишь код программы. Теперь он будет такой, как на врезке.
В программе мы создаём два потока, каждый выполняет свою операцию: один мигает светодиодом, второй управляет звуком сирены. В каждой итерации цикла для каждого потока проверяем, пришло ли время его выполнения или нет. Если пришло - он запускается на исполнение с помощью метода "run()". Главное - не использовать оператор "delay()".
В коде даны более подробные пояснения.
Загрузим код в память Ардуино, запустим. Теперь всё работает в точности так, как надо!
В программе мы создаём два потока, каждый выполняет свою операцию: один мигает светодиодом, второй управляет звуком сирены. В каждой итерации цикла для каждого потока проверяем, пришло ли время его выполнения или нет. Если пришло - он запускается на исполнение с помощью метода "run()". Главное - не использовать оператор "delay()".
В коде даны более подробные пояснения.
Загрузим код в память Ардуино, запустим. Теперь всё работает в точности так, как надо!