• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Спящий режим и выход из него

Norfo

New member
Добрый день! Тут стандартные фразы про то, что я новичок и т.д. Лучше перейду к делу. Прошу Вашей помощи вот в каком вопросе. Необходимо реализовать на модуле ESP8266 систему автовыключения (перехода в режим глубокого сна) с целью сохранения заряда батареи. При этом нет таймера по которому плата бы выходила из этого режима, выход должен происходить при подаче высокого уровня на один из пинов. Подскажите, пожалуйста, возможно ли это и каким образом реализуется.
 

Slacky

Member
@nikolz читали.

deep_speel не подходит, остается light_sleep. Но, есть нюансы.

Wemos D1 mini в таком коде через некоторое время (пара часов) перестает реагировать на сигнал на пине.

Код:
#include <ESP8266WiFi.h>
extern "C" {
#include "gpio.h"
}
extern "C" {
#include "user_interface.h"
}
const char* ssid = "myNetwork";
const char* password = "myPassword";
WiFiClient client;
void setup() {
  Serial.begin(115200);
  Serial.print("initializing GPIOs");
  gpio_init();
  pinMode(0, INPUT); // this pin is connected to the PIR sensor.
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  delay(1000);
}
void loop() {
  Serial.println("Ready to go into light sleep...");
  delay(1000);
  Serial.println("3...");
  delay(1000);
  Serial.println("2...");
  delay(1000);
  Serial.println("1...");
  sleepNow();
}
void sleepNow() {
  Serial.println("going to light sleep...");
  wifi_station_disconnect();
  wifi_set_opmode(NULL_MODE);
  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); //light sleep mode
  gpio_pin_wakeup_enable(GPIO_ID_PIN(0), GPIO_PIN_INTR_HILEVEL); //set the interrupt to look for HIGH pulses on Pin 0 (the PIR).
  wifi_fpm_open();
  delay(100);
  wifi_fpm_set_wakeup_cb(wakeupFromMotion); //wakeup callback
  wifi_fpm_do_sleep(0xFFFFFFF);
  delay(100);
}
void wakeupFromMotion(void) {
  wifi_fpm_close;
  wifi_set_opmode(STATION_MODE);
  wifi_station_connect();
  Serial.println("Woke up from sleep");
}
К тому же мне было нужно реагировать на изменение на двух пинах, как это сделать, я так и не нашел, а сам не придумал ...
 
Последнее редактирование:

Slacky

Member
1) system_deep_sleep(0): there is no wakeup timer; in order to wake up, connect
a GPIO to pin RST; the chip will wake up by a falling-edge on pin RST.
2) для нескольких сигналов делайте монтажное или .
В режиме deed_sleep модуль полностью перегружается, а мне это не подходило.

Все-таки нужно еще все проверить, тем более как раз пришли MC14490 и о дребезге можно забыть ...
 

Slacky

Member
@nikolz да мне не нужно наибольшее время работы от батарейки. Мне нужно пережить кратковременное отключение от 220 ...
 

Slacky

Member
Вы бы сначала конкретизировали задачу.
"Кратковременно" - это сколько?
или это надо угадывать?
Да это же был не вопрос :)))

А кратковременно - ну на сколько бывает выключают электричество в московской квартире? Максимум на несколько часов (1 - 6) ...
 

Slacky

Member
Многое зависит от алгоритма работы устройства.
Да забейте, я же ничего не спрашиваю :)))

Допилил код. Засыпает, просыпается по низкому уровню. При этом успевает отработать прерывание и посчитать этот импульс (по прерываниям в Arduino IDE mode установлен в RISING, т.е. по заднему фронту).

Есть только один нюанс, с которым я пока не знаю что делать. Этот код падает к корку, если в момент сна очень быстро придет несколько импульсов на вход. Но так как у меня система тихоходная, то скорей всего это будет отрабатывать нормально. Требует испытаний временем :))

Для Wemos D1 mini (для другой платки возможно нужно изменить пины). D0 - GPIO16 - через сопротивление 12 кОм на +5 вольт (из-за внутреннего подтягивающего резистора получется где-то 3.3 вольта на ножке). При отключении +5 вольт считаем, что внешнее напряжение пропало.

Код:
#include <ESP8266WiFi.h>

extern "C" {
#include "gpio.h"
#include "user_interface.h"
}

const char* ssid = "Slacky";
const char* password = "**********";
WiFiClient client;

#define HOT_PIN D1                                /* Number of Pin for hot water       */
#define COLD_PIN D2                               /* Number of Pin for cold water      */
#define EXT_POWER_PIN D0

volatile unsigned long counterHotWater, counterColdWater;

bool offWiFi;
int powerPause;



void setup() {
  Serial.begin(115200);
  Serial.println("\n\nInitializing GPIOs");
  initPin();
  initInterrupt();
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  delay(1000);
  counterHotWater = 0; counterColdWater = 0;
  powerPause = 0;
}

void loop() {

  Serial.printf("counterHotWater: %lu\n", counterHotWater);
  Serial.printf("counterColdWater: %lu\n", counterColdWater);
  Serial.printf("powerPause: %d\n", powerPause);
 
  ESP.wdtFeed();
  offWiFi = false;
  checkExtPower();
  if (offWiFi) sleepNow();

  delay(1000);
 
}

void sleepNow() {
  Serial.println("going to light sleep...");
  wifi_station_disconnect();
  wifi_set_opmode(NULL_MODE);
  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); //light sleep mode
  gpio_pin_wakeup_enable(GPIO_ID_PIN(HOT_PIN), GPIO_PIN_INTR_LOLEVEL); //set the interrupt to look for HIGH pulses on Pin 0 (the PIR).
  gpio_pin_wakeup_enable(GPIO_ID_PIN(COLD_PIN), GPIO_PIN_INTR_LOLEVEL); //set the interrupt to look for HIGH pulses on Pin 0 (the PIR).
  wifi_fpm_open();
  delay(100);
  wifi_fpm_set_wakeup_cb(wakeupFromMotion); //wakeup callback
  wifi_fpm_do_sleep(0xFFFFFFF);
  delay(100);
}

void wakeupFromMotion(void) {
  initInterrupt();
  wifi_fpm_close();
  wifi_set_opmode(STATION_MODE);
  wifi_station_connect();
  Serial.println("Woke up from sleep");
}


void initPin() {
  pinMode(HOT_PIN, INPUT);
  digitalWrite(HOT_PIN, HIGH);
  pinMode(COLD_PIN, INPUT);
  digitalWrite(COLD_PIN, HIGH);
  pinMode(EXT_POWER_PIN, INPUT_PULLDOWN_16);
}

/* Init external interrupt           */
void initInterrupt() {
  attachInterrupt(digitalPinToInterrupt(HOT_PIN), hotInterrupt, RISING);
  attachInterrupt(digitalPinToInterrupt(COLD_PIN), coldInterrupt, RISING);
}

/* External interrupt for hot water  */
void hotInterrupt() {
  counterHotWater++;
  Serial.printf("counterHotWater: %lu\n", counterHotWater);
}

/* External interrupt for cold water */
void coldInterrupt() {
  counterColdWater++;
  Serial.printf("counterColdWater: %lu\n", counterColdWater);
}

bool checkExtPower() {

  int val = digitalRead(EXT_POWER_PIN);

  if (val) {
    if (offWiFi) {
      Serial.println("External power high. WiFi on");
      offWiFi = false;
    }
    powerPause = 0;
    return true;
  }
  else {
    if (!offWiFi) {
      if (powerPause > 9) {
        Serial.println("External power low. WiFi off.");
        offWiFi = true;
        powerPause = 0;
        return false;
      } else {
        powerPause++;
      }
    }
    return false;
  }
}
 
Последнее редактирование:

Slacky

Member
Перенес код в проект. Все работает. Ничего не перегружается. Единственное, что изменил - добавил
ESP.wdtFeed() в в самое начало функции wakeFromMotion() на всякий случай.

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

В принципе я добился чего хотел. Если раньше, при включенном WiFI потребление на USB-амперметре показывало 0.06А, при выключении WiFi - 0.01А, то в light-sleep он показывает 0.00А, т.е. он уже не может измерить такой мелкий ток.

Всем спасибо :)))
 
Сверху Снизу