Пользовательская функция, такая как yield

Насколько я понимаю, yield() используется, когда у вас длинный код (например, цикл), чтобы фоновая обработка, требуемая esp8266, не приостанавливалась на долгое время.

У меня есть приложение, в котором звук должен воспроизводиться постоянно, и одновременно программа должна выполнять другие действия, которые могут включать длинные циклы (которые я внутри них вызываю с помощью yield()). Эти длинные циклы приводят к прерыванию звука.

Какой наилучший идиоматический способ имитировать функцию yield() в моей программе? Поэтому я делаю что-то вроде этого:

for(int i=0;i<10000;++i){
    yield();
    customeYield();
    someFunction(i);
}

Где customeYield() содержит необходимые инструкции для воспроизведения звука. Вот как это выглядит (я использую ESP8266Audio):

if (mp3_->isRunning()) {
    if (!mp3_->loop()) {
        mp3_->stop();
        return true;
    }
    return false;
}
return true;

Конечно, я могу просто назвать его так, как я это сделал (сделав его глобальным или что-то в этом роде). Однако мне было интересно, есть ли стандартный способ для такой задачи.

, 👍1

Обсуждение

yield() должен быть вызван через определенный промежуток времени, иначе сторожевой таймер перезапустит esp8266. Вы должны вызвать свою функцию, иначе музыка остановится. Никакой магии. yield() делает то, что нужно, и возвращается., @Juraj


1 ответ


Лучший ответ:

3

Без подсказки, что именно вы делаете в своих длинных циклах, сложно сказать, какой способ будет оптимальным в вашем случае. Не думаю, что есть стандартный способ, но, по сути, существует всего два способа реализовать многозадачность на микроконтроллере:

  1. Управление прерыванием: можно установить прерывание по таймеру, которое будет срабатывать регулярно для вызова функции AudioGenerator::loop() (которая заполняет буфер следующими данными).
  2. Неблокирующий код: Используя неблокирующий код, вы можете сначала выполнить одно действие, а затем другое последовательно, настолько быстро, что оба кода будут выполняться достаточно часто. Именно для этого и предназначена используемая вами библиотека (согласно файлу README).

Если вы используете более одного такого длинного цикла в своей функции loop(), вы можете рассмотреть возможность использования конечного автомата (FSM), чтобы вам не приходилось каждый раз добавлять функцию AudioGenerator::loop() в свои длинные циклы, а нужно добавлять ее только один раз для обычной функции loop().

,

Большое спасибо за ответ. Вообще-то да, я использую FSM. Однако я не совсем понял, как это изменит ситуацию? В конце концов, если какая-то основная функция состояния содержит длинный цикл, она всё равно приостановит выполнение остального кода. Я что-то пропустил?, @Humam Helfawi

Конечный автомат поможет вам разбить длинные циклы на небольшие части, чтобы одно выполнение основной функции loop() не занимало много времени. Затем вы выполняете AudioGenerator::loop() в каждом цикле основной функции loop(). Таким образом, вы немного приостанавливаете длинный цикл для выполнения фоновой задачи (в данном случае: воспроизведения звука) между ними. Это всего лишь стиль кодирования. То, как именно разбить длинные циклы на небольшие части, зависит от кода внутри них. Надеюсь, теперь стало понятнее., @chrisl

А, ладно! Теперь понял... Я думал, что у шаблона есть встроенная поддержка. Реализую по вашему совету, и, кажется, работает... Большое спасибо!, @Humam Helfawi