ESP32-C3深度睡眠唤醒后LED无法立即点亮的问题求助
ESP32-C3深度睡眠唤醒同步点亮LED解决方案
核心问题根因
- 唤醒事件未被捕获:深度睡眠唤醒时,按钮处于按下(低电平)状态,但
lastButtonState初始值为0,与当前buttonState一致,触发不了计数器递增的状态变化逻辑,必须等按钮松开再按下才会触发。 - Preferences未正确持久化:原代码仅在setup中读取计数器后立即写回,未在计数器实际变化时保存,导致深度睡眠后计数器重置。
- 状态变量未跨睡眠保留:
lastButtonState、ledState等变量未用RTC_DATA_ATTR标记,深度睡眠后会被重置,无法正确追踪按钮状态变化。
关键修改点
- 在setup中检测GPIO唤醒原因,直接递增计数器并更新LED状态
- 将需要跨睡眠保留的变量标记为
RTC_DATA_ATTR - 仅在计数器变化时调用Preferences保存,确保数据持久化
- 优化按钮状态检测逻辑,避免重复触发
修改后的完整代码
#include <Arduino.h> #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> #include <Wire.h> #include <Preferences.h> const int buttonPin = 3; // 状态控制按钮引脚 const int buttonPin2 = 2; // BLE配对按钮引脚 const int ledPin = 5; // 绿色LED引脚 const int ledPin2 = 6; // 红色LED引脚 const int ledPin3 = 7; // 蓝色LED引脚 // 用RTC_DATA_ATTR标记跨睡眠保留的变量 RTC_DATA_ATTR int buttonState = 0; RTC_DATA_ATTR int lastButtonState = 0; int buttonState2 = 0; int lastButtonState2 = 0; RTC_DATA_ATTR int ledState = 0; RTC_DATA_ATTR int counter = 0; #define SERVICE_UUID "f0e279fc-a979-4ffd-924c-59ced5392948" #define CHARACTERISTIC_UUID "7f98738e-382d-43d9-b256-3cf8bd3120b7" BLEServer *pServer = NULL; BLEService *pService = NULL; BLECharacteristic *pCharacteristic = NULL; Preferences preferences; bool deviceConnected = false; class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; Serial.println("Connected"); delay(3000); Serial.println("Entering deep sleep"); digitalWrite(ledPin3, LOW); esp_deep_sleep_start(); }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; Serial.println("Disconnected!"); Serial.println("Advertising..."); pServer->startAdvertising(); } }; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value = pCharacteristic->getValue(); if (value.length() > 0) { Serial.println("*********"); Serial.print("New value: "); for (int i = 0; i < value.length(); i++) { Serial.print(value[i]); } Serial.println(); Serial.println("*********"); } } }; void setupBLEServer(void) { Serial.println("Starting BLE Server!"); BLEDevice::init("Pirouette-IoT-Device"); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY); pCharacteristic->setCallbacks(new MyCallbacks()); pCharacteristic->setValue("device_state_0_stored"); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); pAdvertising->setMinPreferred(0x12); pAdvertising->start(); } void pairing(){ digitalWrite(ledPin3, HIGH); setupBLEServer(); } void print_wakeup_reason() { esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); switch (wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal (RTC_IO)"); break; case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal (RTC_CNTL)"); break; case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break; case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break; case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break; case ESP_SLEEP_WAKEUP_GPIO: Serial.println("Wakeup caused by GPIO button"); break; default: Serial.printf("Wakeup not from deep sleep: %d\n", wakeup_reason); break; } } void setup() { Serial.begin(115200); // 初始化LED引脚为输出 pinMode(ledPin, OUTPUT); pinMode(ledPin2, OUTPUT); pinMode(ledPin3, OUTPUT); // 初始化按钮引脚为输入 pinMode(buttonPin, INPUT); pinMode(buttonPin2, INPUT_PULLUP); // 启用GPIO唤醒(低电平触发) esp_deep_sleep_enable_gpio_wakeup(1 << buttonPin, ESP_GPIO_WAKEUP_GPIO_LOW); gpio_set_direction((gpio_num_t)buttonPin, GPIO_MODE_INPUT); // 从Preferences加载计数器 preferences.begin("led-state", false); counter = preferences.getInt("counter", 0); preferences.end(); // 检测唤醒原因,若为GPIO唤醒则直接递增计数器 esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); if (wakeup_reason == ESP_SLEEP_WAKEUP_GPIO || wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) { counter++; ledState = !ledState; Serial.print("Button press count: "); Serial.println(counter); // 保存更新后的计数器 preferences.begin("led-state", false); preferences.putInt("counter", counter); preferences.end(); } // 初始化LED状态 if(counter == 1){ digitalWrite(ledPin, ledState); if(pCharacteristic != NULL){ pCharacteristic->setValue("device_state_1_ready"); pCharacteristic->notify(); } } else if(counter == 3){ digitalWrite(ledPin2, HIGH); digitalWrite(ledPin, LOW); if(pCharacteristic != NULL){ pCharacteristic->setValue("device_state_3_locked"); pCharacteristic->notify(); } } else if (counter >= 4){ digitalWrite(ledPin, LOW); digitalWrite(ledPin2, LOW); } } void loop(){ // BLE配对按钮处理 buttonState2 = digitalRead(buttonPin2); if (lastButtonState2 == HIGH && buttonState2 == LOW) { Serial.println("BLE pairing button pressed"); pairing(); } lastButtonState2 = buttonState2; // 打印唤醒原因(仅首次进入loop时执行,避免重复打印) static bool wakeup_printed = false; if(!wakeup_printed){ print_wakeup_reason(); wakeup_printed = true; } // 状态按钮处理(处理唤醒后的按钮松开和再次按下) buttonState = digitalRead(buttonPin); if (buttonState != lastButtonState) { // 处理按钮松开事件(高电平) if (lastButtonState == LOW && buttonState == HIGH) { // 可在此添加松开后的逻辑 } // 处理按钮再次按下事件(低电平) else if (lastButtonState == HIGH && buttonState == LOW) { counter++; ledState = !ledState; Serial.print("Button press count: "); Serial.println(counter); // 保存计数器到Preferences preferences.begin("led-state", false); preferences.putInt("counter", counter); preferences.end(); // 更新LED状态 if(counter == 1){ digitalWrite(ledPin, ledState); if(pCharacteristic != NULL){ pCharacteristic->setValue("device_state_1_ready"); pCharacteristic->notify(); } } else if(counter == 3){ digitalWrite(ledPin2, HIGH); digitalWrite(ledPin, LOW); if(pCharacteristic != NULL){ pCharacteristic->setValue("device_state_3_locked"); pCharacteristic->notify(); } } else if (counter >= 4){ digitalWrite(ledPin, LOW); digitalWrite(ledPin2, LOW); } } delay(50); // 消抖 } lastButtonState = buttonState; delay(50); }
修改说明
- RTC变量标记:将
buttonState、lastButtonState、ledState、counter标记为RTC_DATA_ATTR,确保深度睡眠后这些变量的值不会丢失。 - 唤醒时直接处理:在setup中检测到GPIO唤醒时,直接递增计数器并更新LED状态,实现唤醒即点亮LED。
- Preferences优化:仅在计数器实际变化时写入Preferences,避免无效操作,同时确保计数器值在深度睡眠后保留。
- 按钮逻辑优化:拆分按钮按下和松开的处理逻辑,避免重复触发,添加消抖延迟。
内容的提问来源于stack exchange,提问作者Abhi
相关产品推荐
相关产品推荐

