我正在尝试通过 GPIO 唤醒在 ESP8266 上实现轻度睡眠。一切工作正常,除了如果唤醒后 GPIO 保持在与 WAKEUP 触发电平相反的状态,则 ESP 会因 HW WDT 复位而崩溃。同样需要一些帮助。
我想实现什么目标: 我有一个连接到流量计的 ESP。流量计转动时发送高/低脉冲。我需要的是能够使 ESP 浅睡眠并在流程再次开始时将其唤醒。为此,我将流量计输出连接到 ESP 上的 WAKE PIN,以便在流量开始时唤醒 ESP。由于我不知道睡眠开始时流量计输出是低电平还是高电平,所以我读取了 GPIO,然后决定是否将 WAKEUP 触发器配置为
GPIO_PIN_INTR_LOLEVEL
或 GPIO_PIN_INTR_HILEVEL
有什么问题: 如果 ESP 在 GPIO 为低电平时休眠,那么它必须在高信号时唤醒,它会这样做,但如果流量计在高信号处停止,则 ESP 在大约 7 秒后崩溃。无论唤醒后已经过了多长时间,这种情况都会发生。如果由于任何原因 GPIO(连接到流量计)将停止并保持在高电平,ESP 将在 7 秒内崩溃。如果它在 GPIO 为高电平时休眠,然后在低电平时唤醒,则同样适用,如果 GPIO 随时变为低电平,则硬件看门狗定时器复位将导致崩溃。 我在blog上读到,浅睡眠唤醒只能在脉冲触发器上工作,所以如果是这样的话,这是有道理的,但我仍然无法接受这个GPIO不能在任何时候处于特定状态的事实唤醒后的程序中。
我尝试过什么: 在我意识到这是崩溃的原因之前,我尝试了很多事情,所以我不会详细讨论这些,但将其仅限于这个原因。
wifi_fpm_close();
,但没有解决问题。崩溃时输出
19:15:39.318 > ets Jan 8 2013,rst cause:4, boot mode:(3,7)
19:15:39.321 >
19:15:39.321 > wdt reset
19:15:39.321 > load 0x4010f000, len 3424, room 16
19:15:39.328 > tail 0
19:15:39.329 > chksum 0x2e
19:15:39.329 > load 0x3fff20b8, len 40, room 8
19:15:39.331 > tail 0
19:15:39.331 > chksum 0x2b
19:15:39.334 > csum 0x2b
19:15:39.334 > v00044c80
19:15:39.336 > ~ld
删除所有不相关内容的代码:
#define DEBOUNCE_INTERVAL 10 //debouncing time in ms for interrupts
#define IDLE_TIME 15 //300 //idle time in sec beyond which the ESP goes to sleep , to be woken up only by a pulse from the meter
#define PULSE_PIN 4 // defines the pin to which the encoder is connected
#define WAKEUP_PIN 14 // defines the pin to which the wakeup signal is connected, in this case it is the same as the encoder pin
// ************ HASH DEFINES *******************
#include <Arduino.h>
#include "secrets.h"
#include "Debugutils.h"
#include <ESP8266WiFi.h>
#include <user_interface.h> // for RTC memory functions
// ************ GLOBAL OBJECTS/VARIABLES *******************
unsigned int pulses = 0; //stores the no of pulses detected by the sensor, it is reset after SENSOR_UPDATE_INTERVAL
unsigned long last_sleep_time = millis();//stores the no of ms since a message was last published , used to sleep the ESP beyond a certain value
unsigned long idle_time = millis();
volatile unsigned long lastMicros;
// ************ GLOBAL OBJECTS/VARIABLES *******************
void IRAM_ATTR pulseHandler() {
if((long)(micros() - lastMicros) >= DEBOUNCE_INTERVAL * 1000) { //note DEBOUNCE_INTERVAL is in ms , so multiply by 1000 for microsec
pulses += 1;
lastMicros = micros();
}
}
void light_sleep(){
WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work
// extern os_timer_t* timer_list;
// timer_list = nullptr; // stop (but don't disable) the 4 OS timers
wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
bool wakeup_pin_state = digitalRead(WAKEUP_PIN);
gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKEUP_PIN), wakeup_pin_state? GPIO_PIN_INTR_LOLEVEL:GPIO_PIN_INTR_HILEVEL);// only LOLEVEL or HILEVEL interrupts work, no edge, that's a CPU limitation
Serial.printf("CPU going to sleep, pull WAKE_UP_PIN %s to wakeup",wakeup_pin_state?"LOW":"HIGH");Serial.flush();
wifi_fpm_open();
wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF, any other value and it won't disconnect the RTC timer
delay(10); // it goes to sleep during this delay() and waits for an interrupt
Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed*/
wifi_fpm_close(); // Disable force sleep mode
//sometimes the above statement gets printed before actually sleeping off, doesnt happen all the time though
//But the code works as expected, the ESP sleeps after printing Woke up
}
void setup() {
Serial.begin(115200);
pinMode(WAKEUP_PIN, INPUT_PULLUP);//INPUT_PULLUP
pinMode(PULSE_PIN, INPUT_PULLUP);
attachInterrupt(PULSE_PIN, pulseHandler, RISING);
Serial.println("Setup complete");
}
void loop() {
idle_time = millis() - last_sleep_time;
if(idle_time >= IDLE_TIME * 1000)
{
Serial.print("going to sleep after being idle for :"); Serial.print(idle_time/1000);Serial.println(" sec");Serial.flush();
light_sleep();
//now that we're awake , add the sleep time to the previous value
last_sleep_time = millis();
}
yield();
}
如果硬件解决方案可以接受,请使用外部单稳态多谐振荡器(例如单稳态模式下的 555 定时器)将信号转换为固定持续时间的脉冲。这确保唤醒信号始终是瞬态的,避免崩溃。
您可以在此处查看更多参考。 https://www.theengineeringprojects.com/2016/02/555-timer-projects.html
您可以在 GPIO 引脚和地之间使用 0.1 µF 等小电容器。这将创建一个低通滤波器,平滑过渡并确保短暂的脉冲而不是持续的电平。这可能会阻止 GPIO 停留在触发看门狗的状态。