Является ли плохой практикой многозадачность без ограничений по времени

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

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

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

Это все еще считается неблокирующим программированием?

Я написал несколько макетов кода, чтобы лучше проиллюстрировать, что я имею в виду. Большое вам спасибо за то, что дочитали до конца.

void loop() {
    Button();
    Sensor();
    LED();
    // ...
}

void Button() {
  // Чтение кнопок
  button_state = digitalRead(button_pin);
  if (button_state == LOW) {
    // ...
  };
};

void Sensor() {
  // Чтение датчика
  int sensor_state = analogRead(sensor_pin);
  if (sensor_state >= 150) {
    // ...
  };
};

, 👍3

Обсуждение

Все немного блокируется, верно? Дело в том, что задержка () (обычно) - это бессмысленная блокировка, с которой можно было бы справиться лучше. Лучше использовать прерывания для мониторинга датчиков, когда это практично. Это преодолевается некоторыми ограничениями "одной нити" скетча и позволяет MCU выполнять >1 действий за один раз., @dandavis


2 ответа


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

5

Как часто бывает, ответ таков: все зависит.

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

Например: Вы считываете аналоговое значение в каждом цикле. analogRead() займет около 100us (ссылка). Я предполагаю, что значение вашего датчика довольно медленное (так что время сигнала выше 150 будет довольно долгим). Кроме того, вы читаете кнопку с помощью digitalRead(). Чтение занимает около 3.6 us (ссылка). Таким образом, в общей сложности у вас есть цикл - скажем - 150us (с включенными накладными расходами и итерацией loop ()). Но событие, которое вы хотите поймать - нажатие кнопки - будет находиться в пределах 100 мс, что в 667 раз больше, чем общее время вашего цикла() (когда никакого события не произошло). Так что по отношению к самому короткому событию (нажатие кнопки) все считывания можно считать неблокирующими. (Хотя вы все еще можете получить блокировку через код внутри операторов if. Что на вас расследовать)

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

Итак, чтобы проверить, действительно ли вы используете неблокирующий код, вам нужно спросить себя: Даю ли я каждой части кода достаточно времени для правильного выполнения и улавливания всех запланированных событий? Если да, то вы не блокируете. Если нет, то вы блокируете.


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

,

Привет, Крис, спасибо за ответ. Это было очень ясно и помогло мне понять мыслительный процесс, лежащий в основе принятия решений, так что теперь у меня есть лучшая структура для работы., @Zhelyazko Grudov


2

Если у вас разряжается аккумулятор, то вам следует подумать о том, чтобы микроконтроллер спал как можно больше, и не опрашивать датчики чаще, чем это необходимо. AFAIK, библиотека ядра Arduino не предоставляет возможности для управления спящим режимом, но некоторые сторонние библиотеки доступны для этой цели.

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

,

Привет, Эдгар, спасибо, что снова откликнулся. Он будет работать от батареи, так что мне придется подумать о том, как его реализовать., @Zhelyazko Grudov

@ZhelyazkoGrudov: Достижение низкого энергопотребления-это обширная тема. Я предлагаю вам начать с чтения книги "Методы энергосбережения для микропроцессоров". (https://www.gammon.com.au/forum/?id=11497), Ник Гэммон., @Edgar Bonet

О, как мило! Спасибо за указатель, иначе я уверен, что у меня был бы еще один замечательный момент, просто начавшийся в глуши., @Zhelyazko Grudov