Экономит ли задержка в цикле энергию?

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

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

Если у меня есть цикл, который проверяет некоторые входные данные на наличие изменений, возможно ли, что добавление delay(10) сэкономит несколько циклов и, следовательно, мощность?

, 👍11

Обсуждение

Нет. Даже задержка "использует" циклы., @Majenko

@MarkLakata Многопоточность? В Ардуино? В 99,99% случаев реального планировщика нет, и в любом случае в остальных 0,01% случаев функция задержки не «освобождает» вызывающий поток (реализация задержки аналогична циклу for, который ничего не делает), @frarugi87


7 ответов


17

Нет, он сжигает энергию, ничего не делая.

Вам определенно следует перевести MCU в спящий режим и активировать его по событиям или использовать сторожевой таймер для пробуждения по истечении заданного периода времени.

,

8

Задержка функция не делает ничего особенного. По сути, он просто отсчитывает миллисекунды внутри цикла while и измеряет время с помощью micros().

void delay(unsigned long ms)
{
    uint32_t start = micros();

    while (ms > 0) {
        yield();
        while ( ms > 0 && (micros() - start) >= 1000) {
            ms--;
            start += 1000;
        }
    }
}
,

Вызов yield() несколько особенный, но да, это все еще занятое ожидание, которое тратит большую часть времени на выполнение инструкций., @Peter Cordes

@PeterCordes В вызове yield() нет ничего особенного. Это просто (слабо определенная) функция, которая ничего не делает. Это позволяет другим библиотекам или коду переопределять его и реализовывать какие-то совместные потоки, но код по умолчанию этого не делает, поэтому он ничего не делает. Это не похоже на вызов yield() в чем-то вроде VB, где он возвращает поток программы обратно в ОС..., @Majenko

@Majenko: Спасибо, я предположил, что «выход» подразумевает многозадачную ОС, а не просто заглушку на случай многозадачности. (И да, я думал, что это буквально [POSIX sched_yield(2)](http://man7.org/linux/man-pages/man2/sched_yield.2.html), и что это подразумевает, что Arduino запускает полная ОС, такая как Linux. Трудно отслеживать, какие платы разработки (RPi / Arduino / что-то еще) работают, когда я сам не использую ни одну из них. >.<), @Peter Cordes


5

Нет, короткая задержка (до 100 миллисекунд) обычно вставляется в цикл void(), когда вы подключены к внешнему датчику, чтобы стабилизировать показания. Но это никак не связано с энергопотреблением. В качестве примера, вот строки 49-52 из примерного скетча "AnalogInSerialOut":

      // ждем 2 миллисекунды перед следующим циклом
      // для расчета аналого-цифрового преобразователя
      // после последнего чтения:
      delay(2);
,

1

возможно ли, что добавление задержки (10) сэкономит несколько циклов и, следовательно, мощность?

Нет, функция delay() просто приостанавливает выполнение кода на указанное время. Он все еще работает и потребляет энергию для подсчета времени и ожидания его завершения.

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

Ура!

,

5

Ответы выше неверны, по крайней мере, для NodeMCU 0.9 (плата ESP-12) ESP8266, и я также тестировал плату Firebeetle ESP8266. Поскольку у меня есть USB-тестер, я могу проверить, что, если метод петли пуст, платы потребляют около 70 мА-80 мА, но во время задержки (мс) они потребляют около 20 мА-30 мА .

Это функция задержки для комментируемых плат:

void __delay(unsigned long ms) {
    if(ms) {
        os_timer_setfn(&delay_timer, (os_timer_func_t*) &delay_end, 0);
        os_timer_arm(&delay_timer, ms, ONCE);
    } else {
        esp_schedule();
    }
    esp_yield();
    if(ms) {
        os_timer_disarm(&delay_timer);
    }
}

Я не исследовал, почему функция задержки так экономит электроэнергию.

,

1

Я подозреваю, что ответ зависит от того, какой Arduino вы используете.

ESP8266 основан на ARM, и я считаю, что микросхемы ARM включают схемы управления питанием, в которых подсистемы автоматически переводятся в состояние пониженного энергопотребления, когда они не используются. Arduino на базе ARM, вероятно, будет потреблять гораздо меньше энергии при выполнении задержки, чем при выполнении других действий.

Я не думаю, что чипы AVR имеют какое-либо управление питанием, поэтому они "зажигают" весь свой кремний. всегда. Тем не менее, логические схемы CMOS потребляют больше энергии при переключении состояний, чем в режиме ожидания, поэтому даже Arduino на основе AVR, вероятно, будет потреблять немного меньше энергии в функции delay(), чем при выполнении инструкций, использующих арифметическое устройство. UART и другие подсистемы чипа.

Вы значительно сэкономите электроэнергию, переведя Arduino в спящий режим.

,

В AVR delay() использует ALU., @Edgar Bonet

Да, я думаю, он будет использовать ALU, чтобы увидеть, прошло ли достаточно времени. Я имел в виду это больше как пример различных подсистем чипа, чем точный список, но точка зрения принята., @Duncan C


1

Как указано в предыдущих ответах, по крайней мере, на версии AVR Ядро Arduino, delay() — это занятое ожидание, которое поддерживает работу ЦП. В В своем ответе Дункан С. правильно утверждает, что «логические схемы КМОП действительно используют больше энергии при переключении состояний, чем в режиме ожидания». Затем ожидается что инструкции, которые переключают большое количество вентилей или триггеров потребляют больше энергии, чем инструкции, которые переключают только несколько.

Из любопытства я разобрал вызов delay(), чтобы посмотреть, что инструкции, которые он выполняет. Я обнаружил, что «горячий путь» представляет собой петлю, которая выполняет 44 инструкции за итерацию:

  • 23 из них выполняют арифметические или логические операции (сложение, вычитание, сравнение, XOR)
  • 13 перемещать данные (загрузка регистра, копирование регистра, ввод-вывод, чтение ОЗУ)
  • 7 изменить ход программы (вызов функции, возврат, переход, условное ветви, условный пропуск)
  • 1 немного изменяет бит в регистре состояния

Не знаю, как это соотносится с «типичным» кодом, но большой доля инструкций, выполняющих арифметические и логические вычисления предполагает, что delay() должен потреблять гораздо больше энергии, чем, скажем, длинная последовательность инструкций nop. В конце концов, единственный способ точно знать, меняет ли delay() что-либо в степени потребление конкретной программы будет измерять ее.

Кстати, простой способ сэкономить немного энергии на платах AVR – #include <avr/sleep.h> и вставьте вызов sleep_mode() в конце из loop(). Сон с этим не длится долго, так как Arduino core устанавливает Таймер 0 на прерывание ЦП каждые 1024 мкс.

,