Делать несколько вещей одновременно с функциями, объектами или прерываниями?

Прежде всего, спасибо, что нашли время прочитать это. Я новичок, поэтому приношу свои извинения (примеры приведены на веб-сайте arduino, базовый C++).

Я пытаюсь понять, как лучше всего структурировать скетч, который должен выполнять несколько задач одновременно. Например, считывание датчика IMU и использование его для управления мышью, считывание кнопки включения/выключения и, скажем, мигание светодиода. У меня повторяющиеся травмы, так что это проект, который я пытаюсь завершить, но принцип должен быть масштабируемым для более сложных проектов.

Я наткнулся на несколько замечательных ресурсов, и, насколько я понимаю, вы можете использовать:

  1. функции (например, мигание без задержки)

  2. объекты (совместная многозадачность)

  3. прерывает

  4. что-то вроде RTOS

Где мои пределы лежат, так это понимание преимуществ/ограничений этих вариантов и выбор того, на чем следует сосредоточиться для моего проекта. Например, если достаточно использовать функции, почему люди беспокоятся о прерываниях и установке RTOS?

Я был бы признателен за любые указания относительно того, как должен выглядеть эффективный подход.

Еще раз спасибо.

, 👍1

Обсуждение

Функции и объекты не имеют ничего общего с “выполнением нескольких вещей одновременно”, это просто способы инкапсулировать некоторую логику. В обоих случаях вы выполняете **неблокирующее** программирование. Наиболее полезной парадигмой программирования для неблокирующего программирования является [конечная машина](https://majenko.co.uk/blog/finite-state-machine)., @Edgar Bonet

Пожалуйста, ознакомьтесь с концепцией "реального времени". Это не означает, что что-то происходит быстро, это просто означает, что это достаточно быстро (на основе любых стандартов, которые вы применяете). Например, если ваш мигающий светодиод имеет перекос в несколько миллисекунд, вы не заметите - это не имеет значения., @PMF

Спасибо за ссылку, я просматриваю ее сегодня., @Zhelyazko Grudov

если вы будете следовать приведенным примерам, и не в вашем коде используется функция delay(), она, естественно, должна выполнять много действий одновременно, с учетом времени процессора и памяти. Для того, что вы описываете, трудно представить, что даже Uno не справится с задачей., @dandavis

Спасибо Дэвису за комментарий, @Zhelyazko Grudov


1 ответ


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

2

RTOS может быть хорошим вариантом для запуска сложного приложения на довольно мощном Arduino. Однако многие Arduino (основанные на AVR) слишком ограничены для запуска сложных приложений, и накладные расходы на ОСРВ для них весьма значительны. В этом случае у вас есть два варианта:

  • неблокирующее программирование
  • прерывает

Что будет лучше, зависит от конкретных задач, которыми вы управляете.

Неблокирующее программирование

Это лучше всего иллюстрирует учебник по Arduino "Мигай без задержки ". Общий принцип состоит в том, чтобы разбить ваш код на небольшие неблокирующие задачи и выполнять каждую из них только тогда, когда для этого наступит подходящее время . Разбиение логики программы на набор неблокирующих задач не всегда является полностью тривиальным, но вы можете использовать конечную машину, что является очень мощной и общей концепцией для систематического выполнения этого.

Как только все задачи будут неблокирующими, основной цикл программы будет выглядеть следующим псевдокодом:

void loop() {
    if (task_1_should_be_performed_now()) {
        perform_task_1();
    }
    if (task_2_should_be_performed_now()) {
        perform_task_2();
    }
    // и т.д...
}

В большинстве случаев все условия являются ложными, и программа быстро проходит тесты, завершая цикл за очень короткое время. Иногда он выполняет одну из задач, что делает цикл длиннее , но, поскольку задачи никогда не блокируются, все равно не очень долго. Типичное время цикла сильно зависит от особенностей вашего кода, но я бы ожидал, что в большинстве случаев оно составит не более одной миллисекунды.

Это, вероятно, наиболее распространенный шаблон для многозадачности в Arduino. Вы можете инкапсулировать эту логику в функции, объекты, библиотеки и т. Д. Этот подход я бы рекомендовал при условии, что ни одна из ваших задач не является настолько срочной, чтобы она не могла подождать одну итерацию цикла.

Прерывает

Иногда у вас может возникнуть задача настолько срочная, что она не может дождаться следующей итерации цикла. Это должно быть сделано прямо сейчас. Или, может быть, цикл занимает очень много времени из-за блокирующего вызова в библиотеке , которую вы не контролируете. В таких ситуациях прерывание может быть лучшим вариантом.

Прерывания связаны с некоторыми сложными проблемами программирования, которые требуют некоторых мер предосторожности со стороны программиста:

  • они блокируют другие прерывания, увеличивая их задержку → процедуры обслуживания прерываний должны быть как можно короче

  • они могут вызвать проблемы с невозвратными библиотечными функциями → этих функций следует избегать в контексте прерываний

  • они могут плохо взаимодействовать с оптимизатором → переменные, используемые как в контексте прерывания, так и в обычном контексте, должны быть квалифицированы как изменчивые

  • они могут вызвать проблемы с синхронизацией данных, совместно используемых с основным кодом → доступ к этим данным в обычном контексте должен быть защищен в критических разделах.

По всем этим причинам лучше всего использовать прерывания только при необходимости, т. Е. Только тогда, когда задача не может дождаться следующей итерации цикла().

,

Привет, Эдгар, я действительно ценю, что ты потратил время и усилия, чтобы ответить таким полезным образом. Я перейду по ссылке и потрачу остаток дня на то, чтобы усвоить контент. Большое спасибо. Просто чтобы подтвердить пару быстрых моментов. Вы подразумеваете, что с точки зрения многозадачности не имеет значения, инкапсулирую ли я код в функции или объекты? Каким был бы пример задачи, которая не может ждать повторения цикла? Будет ли достаточным нажатие кнопки для выполнения такого действия, как включение/выключение аналогового датчика, квалифицироваться?, @Zhelyazko Grudov

если позволите; потоковое аудио, некоторые взаимодействия с Wi-Fi, захват образцов АЦП высокой скорости и т. Д. Посмотрите на прерывания, которые в основном являются событиями, которые могут вставать в очередь для обработки в реальном времени таких вещей, как нажатие кнопок. Ваш аналоговый датчик не возражает подождать мс, чтобы взять еще один образец., @dandavis

@Желязкогрудов: 1. Объект-это просто удобный способ инкапсуляции функций (называемых _методами) вместе с данными. Правильный уровень инкапсуляции может помочь сделать ваш код чище и проще в обслуживании, но он не имеет никакого отношения к многозадачный подход. 2. Для обнаружения нажатия кнопки вам может потребоваться использовать прерывания, если кнопка будет управляться [Ртуть](https://en.wikipedia.org/wiki/Quicksilver_(Marvel_Comics)). Если оператор-обычный человек, задержка в миллисекунду или две не имеет значения., @Edgar Bonet

Такой хороший ответ! Может быть, я разрабатываю проект для мстителей, никогда не знаешь... Со всей серьезностью, спасибо за объяснение., @Zhelyazko Grudov