ESP32中断代码运行触发Guru Meditation错误求助
在Arduino IDE 2.1.0环境下开发ESP32中断相关代码时,持续触发Guru Meditation Error,错误显示Core 1因CPU1中断看门狗超时panic。代码预期通过引脚18、19的外部触发切换MainLoop变量值,进入对应主循环逻辑,以下是错误日志、问题分析及修复方案。
错误日志
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).
Core 1 register dump:
PC : 0x4008e6b4 PS : 0x00060c35 A0 : 0x8008d64e A1 : 0x3ffbefac
A2 : 0x3ffb8a00 A3 : 0x3ffb8890 A4 : 0x00000004 A5 : 0x00060c23
A6 : 0x00060c23 A7 : 0x00000001 A8 : 0x3ffb8890 A9 : 0x00000018
A10 : 0x3ffb8890 A11 : 0x00000018 A12 : 0x3ffc42d4 A13 : 0x00060c23
A14 : 0x007bf158 A15 : 0x003fffff SAR : 0x0000000e EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x40089c09 LEND : 0x40089c19 LCOUNT : 0xfffffffc
Core 1 was running in ISR context:
EPC1 : 0x400dffeb EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x00000000
Backtrace:0x4008e6b1:0x3ffbefac |<-CORRUPTED
Core 0 register dump:
PC : 0x4008e833 PS : 0x00060035 A0 : 0x8008d277 A1 : 0x3ffbeaac
A2 : 0x3ffbf158 A3
问题根源
- ISR内执行耗时/阻塞操作:
LimitSwitches中断服务函数中调用SensorN17.getCumulativePosition(),该函数涉及I2C总线操作,属于依赖中断的耗时操作。ESP32的ISR要求尽可能短小,不能执行阻塞或依赖其他中断的代码,否则会导致中断看门狗超时。 - Switch语句缺少Break:ISR中的switch未添加
break,匹配case 11后会继续执行case 22和default逻辑,造成MainLoop变量被错误修改,逻辑混乱。 - 主循环死阻塞:主循环中
while(GetTimeN17)是无限死循环,完全阻塞主循环,导致ESP32无法处理系统任务、看门狗喂狗操作,最终触发看门狗panic。 - 标志位逻辑错误:主循环末尾每次都将
LastLimitState设为true,会覆盖ISR中设置的false,导致中断触发逻辑失效。
修复方案
- 简化ISR逻辑:ISR仅负责修改标志位和
MainLoop变量,所有耗时操作(如传感器读取、串口打印)移到主循环中执行。 - 修复Switch语句:为每个case添加
break,避免逻辑串执行。 - 替换死循环:将
while(GetTimeN17)改为条件判断,每次循环执行一次打印,避免阻塞主循环。 - 调整标志位赋值:仅在处理完中断逻辑后,在主循环中重置
LastLimitState,而非每次循环都赋值。
修复后的完整代码
#include <Wire.h> #include <AS5600.h> #include <WiFi.h> #include <esp_now.h> #define HES 19 #define LimitPins 18 #define TCA9548A_ADDR 0x70 #define N17AS5600 3 #define N23AS5600 2 #define AS5600_ADDR 0x36 volatile bool HESstate = true; volatile bool LastHESState = true; volatile int Count = 0; volatile bool LimiteState = true; volatile bool LastLimitState = true; volatile bool N17Direction = false; volatile int MainLoop = 1; volatile int StartValue; volatile int StopValue; volatile int DistanceN17; volatile long LastButtonPress = 0; volatile bool FirstTimeN17 = false; volatile bool HomeZeroN17 = false; volatile bool GetTimeN17 = false; volatile bool NeedUpdateDistance = false; // 新增标志位,标记需要读取传感器数据 volatile bool FirstTimeN23 = false; volatile bool HomeZeroN23 = false; int16_t Angle17; int16_t Angle23; int32_t Distance17; int32_t Distance23; int32_t OffsetD17; int32_t OffsetD23; AS5600 SensorN17; AS5600 SensorN23; uint8_t broadcastAddress[] = {0xC8, 0xF0, 0x9E, 0xA6, 0x08, 0xF0}; typedef struct struct_message { int MSG; } struct_message; struct_message myData; esp_now_peer_info_t peerInfo; void TCA9548A(byte bus){ if(bus > 7) return; Wire.beginTransmission(TCA9548A_ADDR); Wire.write(1 << bus); Wire.endTransmission(); } void SetupInterrupts(){ pinMode(HES, INPUT_PULLUP); attachInterrupt(HES, HallEffectSensor, FALLING); pinMode(LimitPins, INPUT_PULLUP); attachInterrupt(LimitPins, LimitSwitches, RISING); } void SetupTCA9548A(){ TCA9548A(N17AS5600); SensorN17.begin(21, 22); // .begin(sda, scl) pour ESP32 TCA9548A(N23AS5600); SensorN23.begin(21, 22); // .begin(sda, scl) pour ESP32 OffsetD23 = -1 * SensorN23.getCumulativePosition(); } void SetupESP_NOW(){ WiFi.mode(WIFI_STA); if(esp_now_init() != ESP_OK){ Serial.println("Error initializing ESP-NOW"); return; } memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; if(esp_now_add_peer(&peerInfo) != ESP_OK){ Serial.println("Failed to add peer"); return; } } void setup() { Serial.begin(9600); Wire.begin(); SetupInterrupts(); SetupTCA9548A(); SetupESP_NOW(); delay(5000); } void loop() { // 处理传感器数据读取 if(NeedUpdateDistance){ TCA9548A(N17AS5600); // 切换到N17的I2C总线 DistanceN17 = SensorN17.getCumulativePosition(); NeedUpdateDistance = false; } if(MainLoop == 1){ myData.MSG = 170; // 170: Nema17 va UP. esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); MainLoop = 11; } // 替换死循环为条件判断,每次循环执行一次打印 if(GetTimeN17){ Serial.print("Temps: "); Serial.print(StopValue - StartValue); Serial.print(" | Vitesse: "); Serial.println(DistanceN17 / (StopValue - StartValue)); // 如果需要停止打印,可以添加停止条件,比如设置GetTimeN17 = false } if(MainLoop == 2){ myData.MSG = 171; // 171: Nema17 va DOWN. esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); MainLoop = 22; if(!FirstTimeN17){ StartValue = millis(); FirstTimeN17 = true; } } if(MainLoop == 9){ myData.MSG = 179; // 179: Nema17 à l'arrêt. esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); if(!HomeZeroN17){ TCA9548A(N17AS5600); OffsetD17 = -1 * SensorN17.getCumulativePosition(); HomeZeroN17 = true; MainLoop = 2; } else { MainLoop = 11; } } // 仅在ISR处理完成后重置标志位 if(!LastLimitState){ LastLimitState = true; } } void HallEffectSensor(){ // 保留原有注释逻辑,如需启用请确保逻辑正确 /*if(LastHESState){ if(!N23Homed){ myData.MSG = 239; // 239: Nema23 à l'arrêt. esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); N23Homed = true; } //HESstate = !HESstate; LastHESState = false; }*/ } void LimitSwitches(){ if(LastLimitState){ switch(MainLoop){ case 11: MainLoop = 9; break; // 添加break,避免执行后续case case 22: MainLoop = 1; StopValue = millis(); NeedUpdateDistance = true; // 设置标志位,让主循环读取传感器数据 GetTimeN17 = true; break; // 添加break default: MainLoop = 0; break; } LastLimitState = false; } }
内容的提问来源于stack exchange,提问作者Vi Peeters

