ESP32矩阵按键游戏手柄深度睡眠与唤醒功能实现求助
ESP32游戏手柄深度睡眠与按键唤醒实现方案
核心实现思路
利用ESP32的EXT1外部唤醒功能实现多引脚触发唤醒,适配按键矩阵的任意按键唤醒需求;通过跟踪设备最后操作时间,超时1分钟后触发深度睡眠以节省电量。具体逻辑:
- 记录每次用户操作(按键按下、编码器转动)的时间戳
- 配置按键矩阵的行引脚为EXT1唤醒源,任意按键按下时触发电平变化唤醒设备
- 循环检测时间差,超时则进入深度睡眠
代码修改步骤
1. 添加全局变量
在代码开头添加用于跟踪操作时间和超时阈值的变量:
unsigned long lastActivityTime = 0; const unsigned long SLEEP_TIMEOUT = 60000; // 1分钟超时,单位毫秒
2. 配置深度睡眠唤醒引脚
在setup()函数末尾添加唤醒配置,将所有行引脚设为EXT1唤醒源:
// 配置EXT1唤醒:任意行引脚变为高电平时唤醒设备 uint64_t wakeupPinMask = 0; for (uint8_t i = 0; i < ROWS; i++) { wakeupPinMask |= (1ULL << rowPins[i]); } esp_sleep_enable_ext1_wakeup(wakeupPinMask, ESP_EXT1_WAKEUP_ANY_HIGH);
3. 刷新操作时间戳
在所有用户操作的逻辑中添加时间刷新:
- 按键矩阵事件中刷新:
void keypadEvent(KeypadEvent key){ lastActivityTime = millis(); // 刷新操作时间 uint8_t keystate = customKeypad.getState(); if (keystate==PRESSED) { pressKey(key); } if (keystate==RELEASED) { releaseKey(key); } } - 编码器旋转时刷新:
if (cntr!=prevenccntr[i]) { lastActivityTime = millis(); // 刷新操作时间 // 原编码器处理代码... } - 补充编码器按键检测并刷新时间(原代码未实现):
// -- ROTARY ENCODERS : PUSH SWITCH -- // bool currentPrs = digitalRead(uppPin[i]); // 假设按键接在uppPin,按下为高电平 if (currentPrs != prevprs[i]) { lastActivityTime = millis(); if (currentPrs) { sendKey(28 + i); // 示例按键码,需根据实际需求调整 } prevprs[i] = currentPrs; }
4. 检测超时并进入深度睡眠
在loop()函数末尾添加超时检测逻辑:
// 检查是否超时无操作 if (millis() - lastActivityTime > SLEEP_TIMEOUT) { Serial.println("超时无操作,进入深度睡眠..."); if (bleGamepad.isConnected()) { bleGamepad.end(); // 关闭BLE连接 } esp_deep_sleep_start(); // 触发深度睡眠 }
完整修改后代码
#include <ESP32Encoder.h> #include <Keypad.h> #include <BleGamepad.h> BleGamepad bleGamepad("WirelessGameHub", "breeze", 100); // 深度睡眠相关全局变量 unsigned long lastActivityTime = 0; const unsigned long SLEEP_TIMEOUT = 60000; // 1分钟超时 ////////////////////// BUTTON MATRIX ////////////////////// #define ROWS 5 #define COLS 4 uint8_t rowPins[ROWS] = {13, 14, 15, 16, 33}; uint8_t colPins[COLS] = {17, 18, 19, 21}; uint8_t keymap[ROWS][COLS] = { {0,1,2,3}, {4,5,6,7}, {8,9,10,11}, {12,13,14,15}, {24,25,26,27} }; Keypad customKeypad = Keypad( makeKeymap(keymap), rowPins, colPins, ROWS, COLS); //////////// ROTARY ENCODERS (WITH PUSH SWITCHES) //////////// #define MAXENC 4 uint8_t uppPin[MAXENC] = {22, 25, 27, 04}; uint8_t dwnPin[MAXENC] = {23, 26, 32, 05}; uint8_t encoderUpp[MAXENC] = {16,18,20,22}; uint8_t encoderDwn[MAXENC] = {17,19,21,23}; ESP32Encoder encoder[MAXENC]; unsigned long holdoff[MAXENC] = {0,0,0,0}; int32_t prevenccntr[MAXENC] = {0,0,0,0}; bool prevprs[MAXENC] = {0,0,0,0}; #define HOLDOFFTIME 150 void setup() { Serial.begin(115200); for (uint8_t i=0; i<MAXENC; i++) { encoder[i].clearCount(); encoder[i].attachSingleEdge(dwnPin[i], uppPin[i]); pinMode(uppPin[i], INPUT_PULLDOWN); // 根据硬件接线调整上下拉 } customKeypad.addEventListener(keypadEvent); customKeypad.setHoldTime(1); bleGamepad.begin(); Serial.println("Booted!"); // 配置EXT1唤醒源 uint64_t wakeupPinMask = 0; for (uint8_t i = 0; i < ROWS; i++) { wakeupPinMask |= (1ULL << rowPins[i]); } esp_sleep_enable_ext1_wakeup(wakeupPinMask, ESP_EXT1_WAKEUP_ANY_HIGH); lastActivityTime = millis(); // 初始化操作时间 } void loop() { unsigned long now = millis(); // -- ROTARY ENCODERS : ROTATION -- // for (uint8_t i=0; i<MAXENC; i++) { int32_t cntr = encoder[i].getCount(); if (cntr!=prevenccntr[i]) { lastActivityTime = now; if (!holdoff[i]) { if (cntr>prevenccntr[i]) { sendKey(encoderUpp[i]); } if (cntr<prevenccntr[i]) { sendKey(encoderDwn[i]); } holdoff[i] = now; if (holdoff[i]==0) holdoff[i] = 1; } else if (now-holdoff[i] > HOLDOFFTIME) { prevenccntr[i] = encoder[i].getCount(); holdoff[i] = 0; } } // -- ROTARY ENCODERS : PUSH SWITCH -- // bool currentPrs = digitalRead(uppPin[i]); if (currentPrs != prevprs[i]) { lastActivityTime = now; if (currentPrs) { sendKey(28 + i); // 示例按键码,按需调整 } prevprs[i] = currentPrs; } } customKeypad.getKey(); // 读取按键矩阵 // 超时检测 if (now - lastActivityTime > SLEEP_TIMEOUT) { Serial.println("进入深度睡眠..."); if (bleGamepad.isConnected()) bleGamepad.end(); esp_deep_sleep_start(); } } void keypadEvent(KeypadEvent key){ lastActivityTime = millis(); uint8_t keystate = customKeypad.getState(); if (keystate==PRESSED) { pressKey(key); } if (keystate==RELEASED) { releaseKey(key); } } void sendKey(uint8_t key) { uint32_t gamepadbutton = pow(2,key); Serial.print("pulse "); Serial.println(key); if(bleGamepad.isConnected()) { bleGamepad.press(gamepadbutton); delay(150); bleGamepad.release(gamepadbutton); } } void pressKey(uint8_t key) { uint32_t gamepadbutton = pow(2,key); Serial.print("hold "); Serial.println(key); if(bleGamepad.isConnected()) { bleGamepad.press(gamepadbutton); } } void releaseKey(uint8_t key) { uint32_t gamepadbutton = pow(2,key); Serial.print("release "); Serial.println(key); if(bleGamepad.isConnected()) { bleGamepad.release(gamepadbutton); } }
注意事项
- 引脚上下拉配置需匹配硬件接线:若按键按下时行引脚为低电平,需将唤醒模式改为
ESP_EXT1_WAKEUP_ANY_LOW - 深度睡眠唤醒后,设备会重新执行
setup(),BLE连接需重新建立 - 编码器按键的检测逻辑需根据实际硬件调整,示例假设按键接在
uppPin并使用下拉输入 millis()约50天后会溢出,可添加溢出处理逻辑优化超时检测
内容的提问来源于stack exchange,提问作者Muhammad Ismail
相关产品推荐
相关产品推荐

