【问题标题】:ESP8266 repeatedly throws Exception(0)ESP8266 反复抛出 Exception(0)
【发布时间】:2020-04-01 08:11:55
【问题描述】:

我正在制作一个带有连接到 Arduino 的称重传感器的物联网称重秤。然后 Arduino 将数据发送到通过串行连接的 ESP8266,该 ESP8266 随后将更新我在 Google 的 Firebase 上的数据库。但是,我的 ESP8266 在启动时会引发异常。一半的时间它工作得很好。当我连接串行电缆时,另一半会引发以下错误。此错误反复运行,因此我认为它可能是 void loop() 内部的错误,但我似乎无法弄清楚究竟是什么问题。另外,我的电缆质量不是最好的,但我不确定这是否会影响任何事情

Exception (0):
epc1=0x4025803e epc2=0x00000000 epc3=0x00000000 excvaddr=0x0000000a depc=0x00000000

>>>stack>>>

ctx: sys
sp: 3fffe0c0 end: 3fffffb0 offset: 01a0
3fffe260:  00000000 00000000 00000000 00000000  
3fffe270:  00000000 00000000 00000000 40104b72  
3fffe280:  40104b54 3fffc100 0000001a 00000000  
3fffe290:  00000000 4025803e 00000000 00000000  
3fffe2a0:  400005e1 00000000 00000000 00000000  
3fffe2b0:  4025803e 00000033 00000010 00000000  
3fffe2c0:  4025803e 40266fd0 00000000 00000001  
3fffe2d0:  fbf8ffff 04000002 3feffe00 00000100  
3fffe2e0:  0000001a 00000018 04000102 40104b54  
3fffe2f0:  3fffc100 0000001a 00000000 00000000  
3fffe300:  00000000 00000000 00000000 00000000  
3fffe310:  00000000 00000000 00000000 00000000  
3fffe320:  00000000 00000000 00000000 00000000  
3fffe330:  00000000 00000000 00000000 00000000  
3fffe340:  00000000 00000000 00000000 00000000  
3fffe350:  00000000 00000000 00000000 00000000  
3fffe360:  00000000 00000000 00000000 00000000  
3fffe370:  00000000 00000000 00000000 00000000  
3fffe380:  00000000 00000000 00000000 00000000  
3fffe390:  00000000 00000000 00000000 00000000  
3fffe3a0:  00000000 00000000 00000000 00000000  
3fffe3b0:  00000000 00000000 00000000 00000000  
3fffe3c0:  00000000 00000000 00000000 40104b72  
3fffe3d0:  40104b54 3fffc100 0000001a 00000000  
3fffe3e0:  00000000 4025803e 00000000 00000000  
3fffe3f0:  400005e1 00000000 00000000 00000000  
3fffe400:  4025803e 00000033 00000010 00000000  
3fffe410:  4025803e 40266fd0 00000000 00000001  
3fffe420:  fbf8ffff 04000002 3feffe00 00000100  
3fffe430:  0000001a 00000018 04000102 40104b54  
3fffe440:  3fffc100 0000001a 00000000 00000000  
3fffe450:  00000000 00000000 00000000 00000000  
3fffe460:  00000000 00000000 00000000 00000000  
3fffe470:  00000000 00000000 00000000 00000000  
3fffe480:  00000000 00000000 00000000 00000000  
3fffe490:  00000000 00000000 00000000 00000000  
3fffe4a0:  00000000 00000000 00000000 00000000  
3fffe4b0:  00000000 00000000 00000000 00000000  
3fffe4c0:  00000000 00000000 00000000 00000000  
3fffe4d0:  00000000 00000000 00000000 00000000  
3fffe4e0:  00000000 00000000 00000000 00000000  
3fffe4f0:  00000000 00000000 00000000 00000000  
3fffe500:  00000000 00000000 00000000 00000000  
3fffe510:  00000000 00000000 00000000 40104b72  
3fffe520:  40104b54 3fffc100 0000001a 00000000  
3fffe530:  00000000 4025803e 00000000 00000000  
3fffe540:  400005e1 00000000 00000000 00000000  
3fffe550:  4025803e 00000033 00000010 00000000  
3fffe560:  4025803e 40266fd0 00000000 00000001  
3fffe570:  fbf8ffff 04000002 3feffe00 00000100  
3fffe580:  0000001a 00000018 04000102 40104b54  
3fffe590:  3fffc100 0000001a 00000000 00000000  
3fffe5a0:  00000000 00000000 00000000 00000000  
3fffe5b0:  00000000 00000000 00000000 00000000  
3fffe5c0:  00000000 00000000 00000000 00000000  
3fffe5d0:  00000000 00000000 00000000 00000000  
3fffe5e0:  00000000 00000000 00000000 00000000  
3fffe5f0:  00000000 00000000 00000000 00000000  
3fffe600:  00000000 00000000 00000000 00000000  
3fffe610:  00000000 00000000 00000000 00000000  
3fffe620:  00000000 00000000 00000000 00000000  
3fffe630:  00000000 00000000 00000000 00000000  
3fffe640:  00000000 00000000 00000000 00000000  
3fffe650:  00000000 00000000 00000000 00000000  
3fffe660:  00000000 00000000 00000000 40104b72  
3fffe670:  40104b54 3fffc100 0000001a 00000000  
3fffe680:  00000000 4025803e 00000000 00000000  
3fffe690:  400005e1 00000000 00000000 00000000  
3fffe6a0:  4025803e 00000033 00000010 00000000  
3fffe6b0:  4025803e 40266fd0 00000000 00000001  
3fffe6c0:  fbf8ffff 04000002 3feffe00 00000100  
3fffe6d0:  0000001a 00000018 04000102 40104b54  
3fffe6e0:  3fffc100 0000001a 00000000 00000000  
3fffe6f0:  00000000 00000000 00000000 00000000  
3fffe700:  00000000 00000000 00000000 00000000  
3fffe710:  00000000 00000000 00000000 00000000  
3fffe720:  0af8a400 00000001 647a4f3a 00000000  
3fffe730:  0af8a400 00000001 647a4f3a 00000000  
3fffe740:  00000000 00000000 00000000 00000000  
3fffe750:  00000000 00000000 00000000 00000000  
3fffe760:  00000000 00000000 00000000 00000000  
3fffe770:  00000000 15f14800 000015f1 00004800  
3fffe780:  0000c8f4 000215f1 00000000 00000000  
3fffe790:  c8f49e74 00009e74 00000000 00000000  
3fffe7a0:  00000000 00000000 00000000 00000000  
3fffe7b0:  00000000 00000000 00000000 40104b72  
3fffe7c0:  40104b54 3fffc100 0000001a 00000000  
3fffe7d0:  00000000 4025803e 647a4f3a 00000000  
3fffe7e0:  400005e1 00000002 000000ad 00000000  
3fffe7f0:  4025803e 00000033 00000010 004e11a5  
3fffe800:  4025803e 40266fd0 00000000 00000001  
3fffe810:  fbf8ffff 04000002 3feffe00 00000100  
3fffe820:  0000001a 00000018 04000102 40104b54  
3fffe830:  3fffc100 0000001a 00000000 00000000  
3fffe840:  ffffffff 00000000 00000001 00000000  
3fffe850:  00005201 00000000 4026492a ffffffff  
3fffe860:  00000000 fffffffd 00000000 00000000  
3fffe870:  00000000 00000000 00000001 40006545  
3fffe880:  00000000 00000000 00000000 40006545  
3fffe890:  00000001 00000001 00000000 40006589  
3fffe8a0:  00000000 3fffe922 00000000 40264b1e  
3fffe8b0:  40264b32 00000001 00000000 00000000  
3fffe8c0:  3fffe8d3 00000000 00000000 40006545  
3fffe8d0:  000005e0 3fffe918 3ffef288 40226a30  
3fffe8e0:  00000608 00000000 00000000 00000000  
3fffe8f0:  00000000 00000020 402532c3 00000001  
3fffe900:  ffffffff 00000000 3ffe8e91 40104b72  
3fffe910:  40104b54 3fffc100 0000001a 00000000  
3fffe920:  00000000 4025803e 00000020 401001a4  
3fffe930:  400005e1 00000000 00000000 401015bc  
3fffe940:  4025803e 00000033 00000010 3ffed11c  
3fffe950:  4025803e 40266fd0 00000000 00000001  
3fffe960:  fbf8ffff 04000002 3feffe00 00000100  
3fffe970:  0000001a 00000018 04000102 40104b54  
3fffe980:  3fffc100 0000001a 00000000 00000000  
3fffe990:  00000000 00000002 3ffee8a0 402660a3  
3fffe9a0:  c0266089 7fffffff 00000002 40211114  
3fffe9b0:  3ffe8765 00000002 3ffee898 4026608a  
3fffe9c0:  00000000 7fffffff 3fff17ec 3ffed29c  
3fffe9d0:  00000000 3ffeea48 3ffe8765 40222cde  
3fffe9e0:  3fffea00 3ffeea1c 3ffe8765 3ffeea78  
3fffe9f0:  3ffe8765 3ffeea9c 3ffe8765 40222cde  
3fffea00:  3fffea20 3ffeebb4 3ffeeb24 3ffed29c  
3fffea10:  3ffe8765 00000000 3ffee678 402063e8  
3fffea20:  40247cf1 00000000 3ffeeaa8 402037d8  
3fffea30:  ffffffff 00000000 3ffeeaa8 402109af  
3fffea40:  00000000 00000000 00000001 401001a4  
3fffea50:  3ffedffc 3ffee028 3ffe8abc 40104b72  
3fffea60:  40104b54 3fffc100 0000001a 00000000  
3fffea70:  00000000 4025803e 00000001 402587be  
3fffea80:  400005e1 00001000 40104e0d 000003fd  
3fffea90:  4025803e 00000033 00000010 00000000  
3fffeaa0:  4025803e 40266fd0 00000000 00000001  
3fffeab0:  fbf8ffff 04000002 3feffe00 00000100  
3fffeac0: c_⸮⸮rS⸮

这是我在 ESP8266 上的代码。对于任何不良的编程习惯,我深表歉意。

#include <ESP8266WiFi.h>
#include <FirebaseESP8266.h>

//Hidden for security
#define WIFINAME   
#define WIFIPASSWORD
#define BAUTRATE 9600
#define FIREBASE_HOST  
#define FIREBASE_COMMAND_ADDRESS
#define FIREBASE_AUTH 

WiFiClientSecure client;
FirebaseData firebaseData;
unsigned long previousTime;
String firebaseWriteAddress;
String firebaseReadAddress;
String weight; // Stored in a string to accomodate the "loading" text
bool maxWRead;
bool minWRead;
bool displayPrefRead;
bool instructedToConnectWifi;

void readWeights(){
  // function to read the min and max weights, then send to Arduino

  if (!maxWRead){
    String maxWAddress = firebaseReadAddress + "/Product/MaxW";
    if (Firebase.get(firebaseData,maxWAddress)){
      if (firebaseData.dataType() == "string"){
        String maxWMessage = "max:"+ firebaseData.stringData();
        Serial.println(maxWMessage);
        maxWRead = true;
      }
    }
  }

  if (!minWRead){
    String minWAddress = firebaseReadAddress + "/Product/MinW";
    if (Firebase.get(firebaseData,minWAddress)){
      if (firebaseData.dataType() == "string"){
        String minWMessage = "min:"+ firebaseData.stringData();
        Serial.println(minWMessage);
        minWRead = true;
      }
    }
  }
}

void readDisplayPref(){
  String displayAddress = firebaseReadAddress + "/Display";
  if (Firebase.get(firebaseData,displayAddress)){
    if (firebaseData.dataType() == "string"){
      String displayMessage = "dsp:"+ firebaseData.stringData();
      Serial.println(displayMessage);
      displayPrefRead = true;
    }
  }
}

void sendFireBase(){
  // function to send data to Firebase Real-time Database
  Firebase.setString(firebaseData, firebaseWriteAddress,weight);
}

void readFireBase(){
  Firebase.begin(FIREBASE_HOST,FIREBASE_AUTH);
  if(Firebase.get(firebaseData, FIREBASE_COMMAND_ADDRESS)){
    if (firebaseData.dataType() == "string"){
      String data = firebaseData.stringData();
      String command = data.substring(0,4);
      if (command == "read"){ 
        firebaseReadAddress = "/UserData/" + data.substring(4);
        readWeights();
        firebaseWriteAddress =  "/UserData/" + data.substring(4)
        + "/Weight";
      }
    }
  }
}

void connectWifi(){

  WiFi.begin(WIFINAME, WIFIPASSWORD);

  byte wifiCounter = 0;
  // Allow some buffer time to connect to WiFi
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    wifiCounter ++;

    if (wifiCounter > 50){
      // tries for 5 sec.
      break;
    }
  }

  if (WiFi.status() == WL_CONNECTED){
    Serial.print("WiFi Connected!\n");
    instructedToConnectWifi = true;
  }

  else {
    Serial.print("Can't Connect. Trying Again\n");
    connectWifi();
  }
}

void readArd(){
// function to read Serial inputs from arduino
  String message = Serial.readStringUntil('\n');
    if (message == "ConnectWifi"){
      connectWifi();
    }
    else{
      weight = message;
      // stores weight without the percentage sign. Only stores if its within 0-100
      sendFireBase();
    }
}

void setup() {
  Serial.begin(BAUTRATE);
  previousTime = millis();
  maxWRead = false;
  minWRead = false;
  displayPrefRead = false;
  instructedToConnectWifi = false;
}
 
void loop() {

  if (Serial.available()){
    readArd();
  }
  
  if (instructedToConnectWifi){
      // if wifi disconnects halfway, auto connect back
      if (WiFi.status() != WL_CONNECTED){
      connectWifi();
    }
  }
  
   unsigned long currentTime = millis();
  if (currentTime - previousTime >2000){
    // cycles every 2 sec to prevent spam
    // TODO: fix overflow problem (49 days) if it becomes product
    
    if (instructedToConnectWifi){
      if (!minWRead || !maxWRead){
        // stop once max and min has been read
        readFireBase();
        previousTime = currentTime;
      }
      else {
        readDisplayPref();
        previousTime = currentTime;
      }
    }
  }
}

【问题讨论】:

    标签: exception arduino esp8266


    【解决方案1】:

    这些异常分析给了我以下结果:

    Exception 0: Illegal instruction
    

    深入研究错误会发现:

    std::basic_string , std::allocator  >::basic_string(char const*, std::allocator  const&) 
    

    这种错误模式是 String 类的典型错误。
    用固定字符数组替换所有字符串(不是动态创建的(!))
    原因:String 类倾向于破坏导致 ESP 崩溃的堆(8266 以及 ESP32)。
    为什么?因为我们使用它们(在 WiFi 场景 (IoT) 中,与“正常”Arduinos 的比例为 99% 相对)。所以内存中发生了很多事情。
    该怎么办?摆脱 String 类(如果使用,则使用 delay())

    String firebaseWriteAddress;
    String firebaseReadAddress;
    String weight; // Stored in a string to accomodate the "loading" text
    

    以上这些与(动态定义的字符串变量)之类的函数结合使用

    String data = firebaseData.stringData();
      String command = data.substring(0,4);
      if (command == "read"){ 
        firebaseReadAddress = "/UserData/" + data.substring(4);
        readWeights();
        firebaseWriteAddress =  "/UserData/" + data.substring(4)
        + "/Weight";
    

    将确保 ESP 很快崩溃。由于没有垃圾收集(并且无论如何都没有足够的内存),您在某个时间写入占用的内存 - 请参阅我的错误分析的第一行 - 崩溃。
    为什么要使用固定字符? - 它们被编译到闪存中,并且您大部分时间都使用指针进行操作。所以所有“固定”的短信都会进入闪存(示例)

    char firebaseReadAddress[64] = {'\0'}; //Takes 63 chars
    

    像以前一样使用

     strcpy(firebaseReadAddress, "/UserData/");
     strcat(firebaseReadAddress, dataContent);
    

    要检查 char 数组是否以“read”开头,请使用以下方法:

     if (strncmp( command, "read", 4) == 0) {  /** Compare the first 4 characters - returns 0 if they are equal */
    

    处理与 String 类一样简单,但它可以让您的应用程序永远运行(至少只要有电源)
    检查是否使用过大量使用 String 的库(特别是如果它们不是专用于 ESP 的情况下) )。如果他们这样做了 - 抛弃它们或重写它们 ;-)
    firebase lib 是一个积极的例子,没有使用动态字符串和大量使用 char 数组。
    抱歉这个坏消息
    如果你重写你的程序想要一个稳定的应用程序,如果有特殊问题,我可以为您提供帮助 - 请在此处发表评论。

    【讨论】:

    • 感谢您的建议。我现在正在更改我的代码。但是如果数据现在是字符数组而不是字符串,我该如何转换代码“data.substring(4)”?
    • 请将此问题标记为已解决并提出一个新问题(以便其他人可以找到它)然后我将提供代码和详细信息
    • @Richard Ding,C++ 没有“非法指令”错误,这意味着它来自机器代码中其他更低级别的内容。它可能是由非法操作码引起的,通常是由导致程序跳转到边界外某处的错误引起的,例如缺少return 有时可能会导致这种情况。此外,Stack 与 Heap 不同,因此它可能不是由建议的堆碎片引起的。这对我来说充其量只是一些最佳实践建议,但不能解决您的问题。
    • 您有时间可以阅读the evils of Arduino Strings。同时,我建议您将代码减少到最少,以查看导致问题的部分。
    • @hcheung 如果您知道软件的“构造”与 ESP 架构相结合,您就不会写 C++ espressifs Api 之上的 Arduino 代码/ESP 之上的封闭源代码由于不存在核心库指南,固件是 C、C++ 和一些奇怪实现的粗略混合。我有测试程序供我的学生演示各种“虚拟”错误。错误中的堆栈总是在发生错误时显示 - 您需要 espressif 开发工具来找到“真正的”问题。我在我的开发环境中运行该程序并猜测字符串是什么
    猜你喜欢
    • 2015-05-30
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多