Информация из этого урока справедлива для AVR Arduino (UNO, Nano, Mega). На других платформах функция yield может иметь другое назначение, см. документацию
Разработчики Arduino позаботились о том, чтобы функция delay() не просто блокировала выполнение кода, но и позволяла выполнять другой код во время этой задержки. Данный "костыль" получил название yield() (здесь можно перевести как передать управление) и работает следующим образом: если объявить функцию
void yield() {
// ваш код
}
то расположенный внутри неё код будет циклично выполняться во время задержки delay(). Это решение хоть и кажется нелепым, но в то же время позволяет быстро и без написания лишних костылей и таймеров реализовать пару параллельно выполняющихся задач, одна из которых выполняется синхронно через задержки, а вторая - асинхронная (тикер). Это вполне соответствует идеологии Arduino - максимально простая и быстрая разработка прототипа.
Рассмотрим простой пример - стандартный мигающий светодиод, но с опросом кнопки:
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000); // вызывает yield() на протяжении 1 сек
digitalWrite(LED_BUILTIN, LOW);
delay(500); // вызывает yield() на протяжении 500 мс
}
void yield() {
// а тут можно опрашивать кнопку
// и не пропустить нажатия из за delay!
}
Таким же образом можно опрашивать энкодер или другие железки, которые требуют максимально частого опроса. Не менее жизненным будет пример со сценарием движения шагового мотора или плавного движения сервопривода, которые требуют частого вызова "функций движения".
Рассмотрим абстрактный пример движения мотора по нескольким заданным точкам, функция вращения мотора должна вызываться как можно чаще (так сделано почти во всех библиотеках для шаговых моторов):
void setup() {}
void loop() {
// задать целевой угол №1
delay(1000);
// задать целевой угол №2
delay(120);
// задать целевой угол №3
delay(2000);
// задать целевой угол №4
delay(250);
// задать целевой угол №5
delay(600);
}
void yield() {
// вращать мотор
}
Таким образом мы быстро и просто расписали "траекторию" движения для шагового мотора по времени, не используя таймеры и состояния. Для более сложных программ, например с движением двух моторов, такой фокус уже может не пройти и будет проще работать с таймером и машиной состояний из следующих уроков.
Рекурсия #
Нужно понимать, что delay() вызывает внутри себя yield(), поэтому если вызвать delay() внутри yield() - программа сломается, т.к. произойдёт бесконечная рекурсия:
void loop() {
delay(100);
}
void yield() {
delay(100); // катастрофа
}
Полезные страницы #
- Набор GyverKIT – наш большой стартовый набор Arduino, продаётся в России
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])
- Поддержать автора за работу над уроками