Многозадачность на Arduino

Платформы Arduino с ядром Cortex-M0+ и Cortex-M3 позволяют выполнять несколько задач одновременно — микрокотроллер просто переключается с одной задачи на другую. Для многопоточного программирования пригодится библиотека Scheduler, которая включает в себя функции управление между задачами.

Настроим несколько функций для одновременно выполнения с loop(). По итогу на выходе будет несколько независмых loop-функций, не требующих отдельного таймера.

В качестве примера улучшим первый эксперимент из набора матрёшкимаячок. Сделаем три отдельных лампочки с разными задержками мигания.

Что понадобится?

Как собрать?

В зависимости от управляющей платформы соберите схему проекта.

Схема для Arduino MKR Zero

Схема для Arduino M0 и Arduino M0 Pro

Схема для Arduino Due

Пример кода

Для работы примера — установите библиотеку Scheduler из менеджера библиотек.

scheduler-multiple-blinks.ino
// подключаем библиотеку «Scheduler» для выполнения несколько задач одновременно
#include <Scheduler.h>
 
// имена пинов светодиодов
#define LED_RED     10
#define LED_GREEN   9
#define LED_BLUE    8
 
void setup() { 
  // выставляем светодиоды в режим выхода
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);
 
  // добавляем в планировщик функции loop2 и loop3;
  // loop() всегда запускается по умолчанию:
  Scheduler.startLoop(loop2);
  Scheduler.startLoop(loop3);
}
 
// задача номер 1: мигать светодиодом с двух секундной задержкой
void loop() {
  // зажигаем светодиод
  digitalWrite(LED_BLUE, HIGH);
  // когда запущено несколько задач
  // delay() переводит задачу в состояние ожидания и передает управление другим задачам
  // тем самым гарантируя, что они будут выполняться
  delay(2000);
  // гасим светодиод
  digitalWrite(LED_BLUE, LOW);
  delay(2000);
}
 
// задача номер 2: мигать светодиодом каждые 500 мс
void loop2() {
  // зажигаем светодиод
  digitalWrite(LED_GREEN, HIGH);
  delay(500);
  // гасим светодиод
  digitalWrite(LED_GREEN, LOW);
  delay(500);
}
 
// задача номер 3: мигать светодиодом каждые 200 мс
void loop3() {
  // зажигаем светодиод
  digitalWrite(LED_RED, HIGH);
  delay(200);
  // гасим светодиод
  digitalWrite(LED_RED, LOW);
  delay(200);
 
  // функцию yield() нужно вызывать постоянно
  // чтобы передавать управление другим задачам
  yield();
}

После загрузки кода вы увидите, что каждый «loop» живёт своей жизнью. И задержки функцией «delay» влияют только на свой блок внутри функции.