Как эффективно закодировать долговременный таймер

Я работаю над проектом, работающим на батарейках. Я пытаюсь написать код, который проверяет напряжение батареи каждые 30 минут и соответствующим образом меняет цвет светодиода. Должен ли я по-прежнему использовать millis() или есть более эффективный способ создать таймер, который отслеживает эти более длительные периоды времени? Должен ли я беспокоиться о том, что значение миллиса сбрасывается каждые 50 дней, используя пример таймера, подобного этому:

bool timer(unsigned long &last_time, unsigned long period)
{
  unsigned long now = millis();
  if (now - last_time >= period) {
    last_time = now;
    return true;
  }
  return false;
}

, 👍1


4 ответа


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

4

Должен ли я по-прежнему использовать millis() или есть более эффективный способ создать таймер, который отслеживает эти более длительные периоды времени?

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

Должен ли я беспокоиться о том, что значение миллиса сбрасывается каждые 50 дней, используя пример таймера, подобного этому:

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

,

спасибо, что откликнулись. Плата основана на микропроцессоре SAMD21G18A (arduino zero). Как вы думаете, будет ли работать следующая библиотека, или мне понадобится внешний RTC? https://www.arduino.cc/reference/en/libraries/rtczero/, @Zhelyazko Grudov

@ZhelyazkoGrudov Это должно сработать нормально., @Majenko

Большое вам спасибо :), @Zhelyazko Grudov


2

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

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

Что касается энергопотребления процессора, на котором выполняется ваш код, единственный способ быть энергоэффективным - это большую часть времени переводить его в спящий режим и будить только тогда, когда нужно выполнить полезную работу. К сожалению, ядро Arduino не обеспечивает стандартного способа перехода в спящий режим. Возможно , вам придется изучить решения, зависящие от конкретной архитектуры, или поискать библиотеку, которая абстрагирует это для вас. Например, на AVR вы можете значительно снизить потребление, позвонив sleep_mode() один раз в вашем цикле (). Это переведет ваше устройство в “неглубокий” спящий режим, и оно будет разбужено следующим прерыванием таймера (это происходит каждые 1,024 мс). Если вы хотите погрузиться в глубокий сон, вам придется настроить источник пробуждения, отличный от прерывания по таймеру. RTC может быть одним из вариантов. Однако, если вам не нужен точный 30-минутный период, вы также можете использовать сторожевой таймер (который имеет сверхнизкое энергопотребление) в качестве источника прерывания.

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

,

Спасибо за подробный ответ, Эдгар. Многое нужно распаковать и обдумать. Это плата на базе SAMD21, поэтому я могу использовать ее библиотеку, чтобы перевести ее в спящий режим, а затем прервать работу датчика Bosch, чтобы разбудить ее. На данный момент попытаюсь включить светодиод через ШИМ, чтобы избежать замены оборудования, может быть, это поможет? Точность таймера не имеет существенного значения, поэтому рассмотрим watchdog vs rtc. И спасибо вам за ссылку на статью., @Zhelyazko Grudov

@ZhelyazkoGrudov: Да, с помощью PWM вы можете контролировать средний ток через светодиод, что влияет как на его яркость, так и на использование батареи., @Edgar Bonet

Потрясающе, спасибо вам!, @Zhelyazko Grudov


1

Ваш опубликованный код никогда не подведет.

Видишь http://gammon.com.au/millis

Позвольте мне сформулировать это так. Ваши часы "выходят из строя" в полночь?

Вычитание времени начала из времени теперь всегда работает (даже через 50 дней) из-за того, как работают целые числа без знака.

,

Не знал, что эта статья существует! Спасибо за сообщение! Стыдно признаться, но я стал одним из тех людей, которые задают этот вопрос. :), @Zhelyazko Grudov

Спасибо @NickGammon за написание вашей статьи о Миллисе. Я использую это вместо того, чтобы объяснять это своим друзьям по arduino. Я сам понял это много лет назад, а затем наткнулся на ваше объяснение на вашем форуме несколько дней спустя. Если бы я просто прочитал это раньше, вы бы избавили меня от необходимости ломать голову над самоанализом. Мое резюме всегда было "никогда не сравнивайте время, сравнивайте длительности" и "позже минус раньше всегда работает для вычисления длительности - при условии, что максимальная интересующая длительность находится в пределах диапазона счетчика"., @Rudy Albachten


2

Библиотека, которая мне нравится для такого рода задач, - это Ticker

#include <Ticker.h>

void batterycheck() {
    // вызывается тикером battcheck каждые 30 минут
    // считывает_вольтажа...
    // set_led_color...
}

Ticker battcheck(batterycheck, 30*60*1000, 0);

setup() {
    battcheck.start();
}

loop() {
    battcheck.update();
}

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

,

Спасибо, что связали это, я проведу тест, @Zhelyazko Grudov