ESP32 не может спать дольше 35 минут.

esp32 sleep memory deep integer

Я пытаюсь получить свой Lilygo T5 4.7quot; epaper для глубокого сна на 12 часов. Но мне кажется, что я могу поспать на нем всего около получаса (2100 с). Если я устанавливаю таймер на большее время, он сразу же перезагружается.

#include <Arduino.h>
#include "epd_driver.h"

long DEEP_SLEEP_TIME_SEC = 43200;

void start_deep_sleep()
{
    epd_poweroff_all();
    esp_sleep_enable_timer_wakeup(1000000L * DEEP_SLEEP_TIME_SEC);
    Serial.println("Starting deep-sleep period...");
    esp_deep_sleep_start();
}

void setup() {  
  Serial.begin(115200); 
  Serial.println("\n- - - - - - - - -INITIALIZING - - - - - - - - - -");
  delay(10000);
  start_deep_sleep();    
}

void loop() {
}

Приведенный выше код дает следующее:

16:44:25.104 -> - - - - - - - - -INITIALIZING - - - - - - - - - -

16:44:35.105 -> Starting deep-sleep period...

16:44:35.105 -> ets Jul 29 2019 12:21:46
  • и он просто продолжает перезагружаться..

Может быть, я каким-то образом использую неправильные переменные?

С уважением Каспер

, 👍3

Обсуждение

обратитесь к техническому описанию ESP32, чтобы узнать о самом продолжительном глубоком сне., @jsotola

Я попробую Ul завтра, но поиск в таблице данных таймера и сна не помог мне узнать, как долго он будет спать., @Engberg

Я не знаю, какова максимальная продолжительность, но функция, которую вы вызываете, похоже, принимает uint64_t, и в этом случае вы, вероятно, ищете 1000000ULL, а не 1000000UL. Или uint64_t(1000000), или (uint64_t)1000000, или static_cast, или... что угодно. Другими словами, то же самое, кажется, говорит Джурадж, только более того., @timemage

хорошо, поэтому я изменил этот esp_sleep_enable_timer_wakeup(1000000ULL * DEEP_SLEEP_TIME_SEC); и пробовал в течение 1 часа (3600 с), и это сработало (+- 15 секунд). Не могли бы вы опубликовать ответ @timemage, чтобы я мог закрыть вопрос? Все еще не уверен, как долго это будет работать.. Кажется, у меня нет проблемы, которую предлагает @hcheung.., @Engberg

Я могу, я как бы подумал, что Юрадж опустил букву «L» и иначе думал об этом, но я вижу, что их комментарий пропал., @timemage


1 ответ


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

3

Итак, формализуя это в ответ:

long DEEP_SLEEP_TIME_SEC = 43200;
// ...
esp_sleep_enable_timer_wakeup(1000000L * DEEP_SLEEP_TIME_SEC);

Это попытка вычислить результат 1000000L * DEEP_SLEEP_TIME_SEC как тип long, поскольку оба операнда имеют тип long. Язык не учитывает значения операндов (вашей константы и переменной) оператора (умножения) при определении типа результата (произведения) и того, что вы делаете с результатом после этого (передавая его в функцию) .

Тип long в ESP32 имеет максимальное значение 2147483647, что, как вы сказали, составляет «около получаса». (не совсем 36 минут) на микросекунды.

Согласно документации esp_sleep_enable_timer_wakeup принимает тип uint64_t для запрашиваемого параметра продолжительности. Я не знаю, каково действительное максимальное значение для вызова, но первоначальный постер подтвердил, что оно достаточно велико для 12 часов.

unsigned long long является 64-битным на ESP32, а суффикс ULL в 1000000ULL заставляет компилятор рассматривать только беззнаковые типы, размер которых не меньше длинный длинный. На практике это означает создание unsigned long long со значением 1000000. В

esp_sleep_enable_timer_wakeup(1000000ULL * DEEP_SLEEP_TIME_SEC);

компилятор следует чему-то, что называется обычными арифметическими преобразованиями, что заставит его преобразовывать с повышением частоты. long типа DEEP_SLEEP_TIME_SEC для соответствия unsigned long long, найденному в 1000000ULL. Таким образом, умножение выполняется в типе unsigned long long, так что само вычисление занимает больше микросекунд, чем вы можете себе представить. Каков фактический максимум для esp_sleep_enable_timer_wakeup, пока неясно. Если я узнаю, я обновлю эту информацию.


Поддержка ESP32-Arduino поставляется с довольно полной стандартной библиотекой C++. Итак, если вы хотите пофантазировать, вы можете использовать заголовок <chrono> . а>. Просто чтобы привести пример того, как это может выглядеть в вашем контексте:

#include <chrono>
// ...
static constexpr auto DEEP_SLEEP_TIME = std::chrono::hours{12};
// ...
esp_sleep_enable_timer_wakeup(
    std::chrono::duration_cast<std::chrono::microseconds>(
        DEEP_SLEEP_TIME
    ).count()    
);

Я очень четко выразился выше. Но вы можете импортировать части пространства имен chrono, поэтому вам не нужно называть все полностью. Вы также можете импортировать поддержку хронолитералов, чтобы использовать константы времени, которые больше похоже на естественный язык (пока нет, я думаю, в Arduino-ESP32 до сих пор нет поддержки C++14). Вы можете управлять базовым целочисленным типом, используемым для представления единицы измерения. Также можно создавать и называть свои собственные типы длительности для представления таких вещей, как длительность битов в последовательном протоколе и т. д. Базовый тип по умолчанию для chrono::microseconds достаточно велик для того, что вы делаете; ширина базовых типов по умолчанию обычно довольно разумна. Разные единицы времени относятся к разным типам std::chrono, поэтому их нельзя случайно перепутать. duration_cast — это средство явного преобразования единиц времени. .count() в приведенном выше примере — это всего лишь способ получить необработанное целочисленное значение из типа хроно, когда вам нужно это сделать, например, вызвать эту функцию.

Если вы обертываете функцию собственными значениями std::chrono::milliseconds, преобразование единиц измерения может происходить автоматически при вызове вашей собственной оболочки:

static constexpr auto DEEP_SLEEP_TIME = std::chrono::hours{12};
//...
esp_err_t esp_sleep_enable_timer_wakeup_using_chrono(
  std::chrono::milliseconds duration
) {
  return esp_sleep_enable_timer_wakeup(
    duration.count()
  );
}
// ...
esp_sleep_enable_timer_wakeup_using_chrono(DEEP_SLEEP_TIME);

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

,