ESP32播放音频反馈后复位,报abort()错误求助
问题分析与修复方案
核心问题:内存泄漏与非法内存访问
ESP32触发abort()复位的主要原因是内存耗尽和非法指针操作,结合代码细节,以下是具体问题和修复方法:
1. 内存泄漏:malloc未释放
在updateSerial()函数中,使用malloc为lower分配内存后未调用free释放,每次处理短信都会占用新内存,最终堆内存耗尽触发系统abort。
修复代码:
在updateSerial()末尾添加内存释放逻辑:
// ... 原有代码 response = ""; res = ""; free(lower); // 释放malloc分配的内存 lower = nullptr; // 清空指针避免悬空
2. 非法指针与全局变量滥用
response = &res[0];:res是String对象,执行res = ""后,response会变成悬空指针,后续操作会访问非法内存。CheckWordInString_rs和CheckWordInString_rsDot函数接收source参数,但实际使用全局变量lower,逻辑混乱且易引发指针错误。
修复代码:
- 直接用String自带的
toLowerCase()方法转换,无需额外分配内存:
// 替换updateSerial中转换小写的代码 String lower_str = res.toLowerCase(); const char* lower = lower_str.c_str(); Serial.print("whole Msg - "); Serial.println(lower);
- 修改检查函数,使用传入的
source参数而非全局lower:
int CheckWordInString_rs(char source[100]) { int i = 0; const int src_len = strlen(source); // 遍历source并添加边界检查 while (i < src_len - 1 && (source[i] != 'r' || source[i + 1] != 's')) { i++; } // 未找到目标字符串则返回 if (i >= src_len -1) return -1; String result = String(source).substring(i + 3); // ... 后续代码不变 } int CheckWordInString_rsDot(char source[100]) { int i = 0; const int src_len = strlen(source); while (i < src_len - 2 && (source[i] != 'r' || source[i + 1] != 's' || source[i + 2] != '.')) { i++; } if (i >= src_len -2) return -1; String result = String(source).substring(i + 4); // ... 后续代码不变 }
3. SoftwareSerial与ESP32硬件冲突
ESP32自带多个硬件串口,使用SoftwareSerial会占用CPU资源,还可能与SIM800L使用的Serial2产生冲突,导致系统不稳定。
修复方案:
将DFPlayer Mini切换到硬件串口,比如Serial1:
// 删除原有SoftwareSerial定义 // SoftwareSerial mySoftwareSerial(33, 25); #define DFSerial Serial1 // 使用硬件串口1 void setup() { // ... 原有代码 DFSerial.begin(9600); // 初始化硬件串口 if (!myDFPlayer.begin(DFSerial, true, false)) { // 改用硬件串口通信 // ... 原有错误处理 } }
注意:需调整DFPlayer Mini的接线,连接到ESP32对应硬件串口的RX/TX引脚(具体引脚参考ESP32型号手册)。
4. 阻塞式循环导致系统异常
updateSerial()中的while (!SerialAT.available())会无限阻塞loop,导致DFPlayer状态无法及时处理,还可能因按钮频繁触发voice_commands引发资源竞争。
修复方案:
改为非阻塞式检查,添加按钮防抖:
void updateSerial() { // 替换原阻塞循环 if (!SerialAT.available()) { if (digitalRead(Prev_button) == LOW) { static unsigned long lastPress = 0; // 500ms防抖 if (millis() - lastPress > 500) { voice_commands(final_amount); lastPress = millis(); } } return; // 直接返回,不阻塞loop } // ... 原有读取串口代码 }
5. 字符串越界风险
CheckWordInString_rs和CheckWordInString_rsDot的循环未做边界检查,若字符串中无"rs"或"rs.",会导致数组越界访问触发系统错误。
修复方案:
在循环中添加长度判断,避免越界:
// 以CheckWordInString_rs为例 const int src_len = strlen(source); while (i < src_len -1 && (source[i] != 'r' || source[i + 1] != 's')) { i++; } // 未找到目标则直接返回 if (i >= src_len -1) return -1;
验证步骤
- 修复代码后重新编译上传至ESP32
- 测试收款短信触发音频播放,观察是否仍会复位
- 查看串口监视器,确认无内存相关错误信息
内容的提问来源于stack exchange,提问作者Athul Baby
相关产品推荐
相关产品推荐

