ESP32中断函数发送Telegram消息触发看门狗超时问题求助
ESP32中断中调用Telegram Bot发送消息导致看门狗超时崩溃问题
我基于DFRobot Firebeetle 2(ESP32-WROOM-32E)和Arduino IDE开发项目,实现温度超阈值时通过Telegram Bot发送告警消息的功能,该功能在loop()中运行正常。目前添加了一个状态按钮,计划通过触发中断发送状态消息(后续要使用ESP32休眠功能,休眠时loop()无法执行,故采用中断而非轮询),但在中断函数中发送消息会导致设备崩溃重启。
测试发现:将minStatusMsgInterval设为250并在setup()末尾调用SendStatusMessage()可正常收到消息,说明函数本身无问题,仅在中断调用时出错。错误提示为Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1),推测bot.sendMessage()执行耗时过长触发看门狗超时,但不确定如何解决,也无法确认是否误解了错误原因。
相关代码
#include <WiFi.h> #include "WiFiClientSecure.h" #include <ESP32Time.h> #include <DFRobot_DHT11.h> #include <UniversalTelegramBot.h> //WiFi #define WLAN_SSID "ESP32Test" #define WLAN_PASS "*********" //WiFiFlientSecure for SSL/TLS support WiFiClientSecure client; //Time ESP32Time rtc(0); // offset in seconds; 0 = GMT, 3600 = GMT+1 //Telegram #define TELEGRAM_TOKEN "*********:*************************" #define CHAT_ID "**********" UniversalTelegramBot bot(TELEGRAM_TOKEN, client); //Temperature DFRobot_DHT11 DHT; #define DHT11_PIN D11 //Buttons #define ONBOARD_BUTTON_PIN 27 //ESP32 pin 27 #define STATUS_BUTTON_PIN D10 //ESP32 pin 12 int StatusButtonLastInterrupt = 0; //Alerts int alertValue = 27; bool alertSent = false; int minStatusMsgInterval = 5000; void IRAM_ATTR SendStatusMessage() { if (millis() - StatusButtonLastInterrupt < minStatusMsgInterval) return; //Prevent executing multiple times per button press or more frequent than required String message = "Temperature Monitor Status\n\n"; message += "Internal temperature: " + String(DHT.temperature) + "C\n"; message += "Internal humidity: " + String(DHT.humidity) + "%\n"; //message += "System time: " + rtc.getDateTime(); // Causes ESP to crash and reset. Error: abort() was called at PC 0x40084cf7 on core 1 //TODO: Check WiFi is connected first - will need to connect when woken from sleep bot.sendMessage(CHAT_ID, message, ""); // Causes ESP to crash and reset. Error: Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1). StatusButtonLastInterrupt = millis(); } void SyncNTP() { Serial.print("Retrieving time: "); configTime(0, 3600, "time.google.com"); // get UTC time via NTP time_t now = time(nullptr); while (now < 24 * 3600) { Serial.print("."); delay(100); now = time(nullptr); } rtc.setTime(now); //Set the time on the realtime clock Serial.println(rtc.getDateTime()); } void setup() { pinMode(ONBOARD_BUTTON_PIN, INPUT_PULLUP); pinMode(STATUS_BUTTON_PIN, INPUT); Serial.begin(115200); //Interrupts attachInterrupt(STATUS_BUTTON_PIN, SendStatusMessage, FALLING); // Connect to WiFi access point. Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(WLAN_SSID); WiFi.mode(WIFI_MODE_STA); WiFi.begin(WLAN_SSID, WLAN_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); //Serial.print("."); Serial.print("WiFi Status: "); Serial.println(WiFi.status()); } Serial.println(); Serial.println("WiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org SyncNTP(); } void loop() { DHT.read(DHT11_PIN); Serial.print("temp:"); Serial.print(DHT.temperature); Serial.print(" humi:"); Serial.println(DHT.humidity); if (DHT.temperature >= alertValue) { if (!alertSent) { bot.sendMessage(CHAT_ID, "TEMPERATURE ALERT: Internal temperature is: " + String(DHT.temperature), ""); alertSent = true; } } else { if (alertSent) { bot.sendMessage(CHAT_ID, "Alert Cleared: Internal temperature is: " + String(DHT.temperature), ""); alertSent = false; //Reset the flag when temperature drops below alertValue } } delay(1000); }
串口监视器输出
Connecting to ESP32Test WiFi Status: 6 WiFi Status: 6 WiFi Status: 6 WiFi Status: 6 WiFi Status: 3 WiFi connected IP address: 192.168.1.2 Retrieving time: ....................Sun, Feb 19 2023 22:23:38 temp:25 humi:57 temp:24 humi:53 temp:24 humi:60 temp:24 humi:60 temp:24 humi:60 temp:24 humi:60 Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1). Core 1 register dump: PC : 0x40090362 PS : 0x00060f34 A0 : 0x8008f47e A1 : 0x3ffbeb00 A2 : 0x3ffde700 A3 : 0x3ffbd994 A4 : 0x00000004 A5 : 0xb33fffff A6 : 0x00000001 A7 : 0x00000001 A8 : 0x3ffbd994 A9 : 0x3ffbd994 A10 : 0x00000019 A11 : 0x00000019 A12 : 0x3ffc3afc A13 : 0xb33fffff A14 : 0x00000001 A15 : 0x00000001 SAR : 0x0000000f EXCCAUSE: 0x00000006 EXCVADDR: 0x00000000 LBEG : 0x400896b0 LEND : 0x400896c6 LCOUNT : 0xffffffff Core 1 was running in ISR context: EPC1 : 0x400e8e33 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x40090362 Backtrace:0x4009035f:0x3ffbeb000x4008f47b:0x3ffbeb20 0x4008de7c:0x3ffbeb40 0x40106ab7:0x3ffbeb80 0x400f408f:0x3ffbeba0 0x401071c5:0x3ffbebd0 0x40107464:0x3ffbebf0 0x400f379d:0x3ffbec40 0x400d49d2:0x3ffbec60 0x400d472d:0x3ffbeed0 0x400d483e:0x3ffbef00 0x400d6c31:0x3ffbef20 0x400d7ece:0x3ffbef80 0x400d8406:0x3ffbf000 0x4008139e:0x3ffbf070 0x400d93f5:0x3ffbf0d0 0x40084a8d:0x3ffbf0f0 0x40173c7f:0x3ffc78f0 0x400e82e9:0x3ffc7910 0x4008e417:0x3ffc7930 Core 0 register dump: PC : 0x40090522 PS : 0x00060634 A0 : 0x8008fc1b A1 : 0x3ffb3290 A2 : 0x3ffbf108 A3 : 0x3ffb32ac A4 : 0x00060623 A5 : 0xb33fffff A6 : 0x0000cdcd A7 : 0x0000abab A8 : 0x0000abab A9 : 0x0000abab A10 : 0x3ffde770 A11 : 0x000000d0 A12 : 0x3ffc6948 A13 : 0xb33fffff A14 : 0x00000001 A15 : 0x00000001 SAR : 0x00000011 EXCCAUSE: 0x00000006 EXCVADDR: 0x00000000 LBEG : 0x400896b0 LEND : 0x400896c6 LCOUNT : 0xffffffff Backtrace:0x4009051f:0x3ffb32900x4008fc18:0x3ffb32d0 0x4008dd9c:0x3ffb32f0 0x401069c0:0x3ffb3330 0x40106d0e:0x3ffb3350 0x400f56bb:0x3ffb3370 0x400f5739:0x3ffb3390 0x400f812c:0x3ffb33b0 0x400f8211:0x3ffb33e0 0x40108557:0x3ffb3400 0x400f3f19:0x3ffb3420 ELF file SHA256: 0000000000000000 Rebooting... ets Jul 29 2019 12:21:46 rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0030,len:1412 load:0x40078000,len:13400 load:0x40080400,len:3672 entry 0x400805f8 Connecting to ESP32Test
问题原因
你的推测完全正确:ESP32的中断服务函数(ISR)执行时间有严格限制,中断看门狗会监控ISR的运行时长,一旦超过阈值(通常为几毫秒)就会触发panic重启。bot.sendMessage()涉及SSL/TLS加密、网络IO等耗时操作,完全不适合在ISR中执行。
此外,ISR中还应避免以下操作:
- 调用
delay()等阻塞函数 - 使用动态内存分配(比如
String拼接,可能引发内存碎片或竞争问题) - 访问主程序正在操作的共享资源(比如
DHT.temperature,可能导致数据不一致)
解决方法
采用中断触发标记+主程序处理的嵌入式标准模式:
- 定义全局布尔变量作为触发标记,标记是否需要发送状态消息
- 中断函数仅执行防抖检查和设置标记的极简逻辑
- 在
loop()中定期检查标记,若标记为真则执行消息发送逻辑,随后重置标记
修改后的代码示例
#include <WiFi.h> #include "WiFiClientSecure.h" #include <ESP32Time.h> #include <DFRobot_DHT11.h> #include <UniversalTelegramBot.h> //WiFi #define WLAN_SSID "ESP32Test" #define WLAN_PASS "*********" //WiFiFlientSecure for SSL/TLS support WiFiClientSecure client; //Time ESP32Time rtc(0); // offset in seconds; 0 = GMT, 3600 = GMT+1 //Telegram #define TELEGRAM_TOKEN "*********:*************************" #define CHAT_ID "**********" UniversalTelegramBot bot(TELEGRAM_TOKEN, client); //Temperature DFRobot_DHT11 DHT; #define DHT11_PIN D11 //Buttons #define ONBOARD_BUTTON_PIN 27 //ESP32 pin 27 #define STATUS_BUTTON_PIN D10 //ESP32 pin 12 volatile int StatusButtonLastInterrupt = 0; volatile bool sendStatusMsgFlag = false; // 中断触发标记 //Alerts int alertValue = 27; bool alertSent = false; int minStatusMsgInterval = 5000; void IRAM_ATTR StatusButtonISR() { // 仅处理防抖和设置标记 if (millis() - StatusButtonLastInterrupt < minStatusMsgInterval) return; sendStatusMsgFlag = true; StatusButtonLastInterrupt = millis(); } void SendStatusMessage() { String message = "Temperature Monitor Status\n\n"; message += "Internal temperature: " + String(DHT.temperature) + "C\n"; message += "Internal humidity: " + String(DHT.humidity) + "%\n"; // 检查WiFi连接状态 if(WiFi.status() == WL_CONNECTED){ bot.sendMessage(CHAT_ID, message, ""); } } void SyncNTP() { Serial.print("Retrieving time: "); configTime(0, 3600, "time.google.com"); // get UTC time via NTP time_t now = time(nullptr); while (now < 24 * 3600) { Serial.print("."); delay(100); now = time(nullptr); } rtc.setTime(now); //Set the time on the realtime clock Serial.println(rtc.getDateTime()); } void setup() { pinMode(ONBOARD_BUTTON_PIN, INPUT_PULLUP); pinMode(STATUS_BUTTON_PIN, INPUT); Serial.begin(115200); //Interrupts attachInterrupt(STATUS_BUTTON_PIN, StatusButtonISR, FALLING); // Connect to WiFi access point. Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(WLAN_SSID); WiFi.mode(WIFI_MODE_STA); WiFi.begin(WLAN_SSID, WLAN_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("WiFi Status: "); Serial.println(WiFi.status()); } Serial.println(); Serial
相关产品推荐
相关产品推荐

