ESP8266随机软WDT复位

时间:2018-02-19 14:06:36

标签: firebase arduino esp8266

我使用带有Bosche BME680传感器屏蔽的WeMos D1 mini Pro。我从传感器获取数据并将它们频繁地放入Firebase数据库。一切正常,除了我的设备有随机崩溃。

传感器库的工作方式是,大约5分钟左右它没有显示IAQ数据(它返回iaq = 25,精度= 0)。 ESP8266在工作程序的第5分钟左右崩溃 - 当IAQ数据可用且已经进行了一些正确读数时。

我认为问题可能是bsec_iot_loop()引起的,问题太长了。我试图在yield()的随机位置使用bsec_iot_loop(),但它不起作用。当我注释掉Firebase集合方法时,程序运行正常。

我的代码中有很大一部分是基于官方的博世文档。坦率地说,它是扩展的复制粘贴。这是文档:https://www.bosch-sensortec.com/bst/products/all_products/bsec

以下是代码:

/**********************************************************************************************************************/
/* header files */
/**********************************************************************************************************************/

#include "bsec_integration.h"
#include <Wire.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <FirebaseArduino.h>
#include <time.h>

#define DEVICE_NAME "device1"

#define SSID "ssid"
#define PWD "pass"

#define FIREBASE_HOST "host"
#define FIREBASE_AUTH "auth"

#define UPDATE_INTERVAL 20

int startupTime;

/**********************************************************************************************************************/
/* functions */
/**********************************************************************************************************************/

/*!
 * @brief           Write operation in either Wire or SPI
 *
 * param[in]        dev_addr        Wire or SPI device address
 * param[in]        reg_addr        register address
 * param[in]        reg_data_ptr    pointer to the data to be written
 * param[in]        data_len        number of bytes to be written
 *
 * @return          result of the bus communication function
 */
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
{
    Wire.beginTransmission((uint8_t) 0x77);
    Wire.write(reg_addr);    /* Set register address to start writing to */

    /* Write the data */
    for (int index = 0; index < data_len; index++) {
        Wire.write(reg_data_ptr[index]);
    }

    return (int8_t)Wire.endTransmission();
}

/*!
 * @brief           Read operation in either Wire or SPI
 *
 * param[in]        dev_addr        Wire or SPI device address
 * param[in]        reg_addr        register address
 * param[out]       reg_data_ptr    pointer to the memory to be used to store the read data
 * param[in]        data_len        number of bytes to be read
 *
 * @return          result of the bus communication function
 */
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
{
    int8_t comResult = 0;
    Wire.beginTransmission((uint8_t) 0x77);
    Wire.write(reg_addr);                    /* Set register address to start reading from */
    comResult = Wire.endTransmission();

    delayMicroseconds(150);                 /* Precautionary response delay */
    Wire.requestFrom((uint8_t) 0x77, (uint8_t)data_len);    /* Request data */

    int index = 0;
    while (Wire.available())  /* The slave device may send less than requested (burst read) */
    {
        reg_data_ptr[index] = Wire.read();
        index++;
    }

    return comResult;
}

/*!
 * @brief           System specific implementation of sleep function
 *
 * @param[in]       t_ms    time in milliseconds
 *
 * @return          none
 */
void sleep(uint32_t t_ms)
{
    delay(t_ms);
}

/*!
 * @brief           Capture the system time in microseconds
 *
 * @return          system_current_time    current system timestamp in microseconds
 */
int64_t get_timestamp_us()
{
    return (int64_t) millis() * 1000;
}

/*!
 * @brief           Load previous library state from non-volatile memory
 *
 * @param[in,out]   state_buffer    buffer to hold the loaded state string
 * @param[in]       n_buffer        size of the allocated state buffer
 *
 * @return          number of bytes copied to state_buffer
 */
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
{
    // ...
    // Load a previous library state from non-volatile memory, if available.
    //
    // Return zero if loading was unsuccessful or no state was available,
    // otherwise return length of loaded state string.
    // ...
    return 0;
}

/*!
 * @brief           Save library state to non-volatile memory
 *
 * @param[in]       state_buffer    buffer holding the state to be stored
 * @param[in]       length          length of the state string to be stored
 *
 * @return          none
 */
void state_save(const uint8_t *state_buffer, uint32_t length)
{
    // ...
    // Save the string some form of non-volatile memory, if possible.
    // ...
}

/*!
 * @brief           Load library config from non-volatile memory
 *
 * @param[in,out]   config_buffer    buffer to hold the loaded state string
 * @param[in]       n_buffer        size of the allocated state buffer
 *
 * @return          number of bytes copied to config_buffer
 */
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
{
    // ...
    // Load a library config from non-volatile memory, if available.
    //
    // Return zero if loading was unsuccessful or no config was available,
    // otherwise return length of loaded config string.
    // ...
    return 0;
}

void connectToWiFi() {
  Serial.print("Connecting to ");
  Serial.println(SSID);

  WiFi.begin(SSID, PWD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void configureFirebase() {
  Serial.print("Connecting to ");
  Serial.println(FIREBASE_HOST);
  Serial.println("");

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);

  delay(500);
}

void configureTime() {
  configTime(0, 0, "pool.ntp.org", "time.nist.gov");
  Serial.println("\nWaiting for time");
  while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("");
}

void configureSensor() {
  return_values_init ret;

  /* Init I2C and serial communication */
  Wire.begin();

  /* Call to the function which initializes the BSEC library
   * Switch on low-power mode and provide no temperature offset */
  ret = bsec_iot_init(BSEC_SAMPLE_RATE_LP, 5.0f, bus_write, bus_read, sleep, state_load, config_load);
  if (ret.bme680_status)
  {
      /* Could not intialize BME680 */
      Serial.println("Error while initializing BME680");
      return;
  }
  else if (ret.bsec_status)
  {
      /* Could not intialize BSEC library */
      Serial.println("Error while initializing BSEC library");
      return;
  }

  Serial.println("Sensor success");
}

/*!
 * @brief           Handling of the ready outputs
 *
 * @param[in]       timestamp       time in nanoseconds
 * @param[in]       iaq             IAQ signal
 * @param[in]       iaq_accuracy    accuracy of IAQ signal
 * @param[in]       temperature     temperature signal
 * @param[in]       humidity        humidity signal
 * @param[in]       pressure        pressure signal
 * @param[in]       raw_temperature raw temperature signal
 * @param[in]       raw_humidity    raw humidity signal
 * @param[in]       gas             raw gas sensor signal
 * @param[in]       bsec_status     value returned by the bsec_do_steps() call
 *
 * @return          none
 */
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
     float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status)
{
    yield();
    char startupTimeStr[32];
    itoa(startupTime, startupTimeStr, 10);
    //Get current time
    time_t now = time(nullptr);

    //Get last update time
    int lastUpdate = Firebase.getInt("device1/lastUpdate");
    if (Firebase.failed()) {
      Serial.print("getting device1/lastUpdate failed:");
      Serial.println(Firebase.error());
      return;
    }

    if (lastUpdate + UPDATE_INTERVAL <= (int) now) {
      //Set last update
      Firebase.setInt("device1/lastUpdate", (int) now);

      //Set the reading
      char nowStr[32];
      itoa(now, nowStr, 10);
      String path = "device1/readings/" + String(nowStr);
      // Firebase.setInt(path + "/iaq", iaq);
      // Firebase.setFloat(path + "/temp", temperature);
      // Firebase.setFloat(path + "/humid", humidity);
      // Firebase.setFloat(path + "/press", pressure);

      //Set uptime
      int uptime = (int) now - startupTime;
      //Firebase.setInt("device1/uptimes/" + String(startupTimeStr), uptime);

      //Verbose data
      Serial.print("Updated: ");
      Serial.print((int) now);
      Serial.print(" | Uptime: ");
      Serial.print(uptime);
      Serial.print(" | IAQ: ");
      Serial.print(iaq);
      Serial.print(" | Acc: ");
      Serial.println(iaq_accuracy);
    }
}

void setup()
{
    Serial.begin(9600);
    while (!Serial);

    connectToWiFi();
    configureFirebase();
    configureTime();
    configureSensor();

    startupTime = (int) time(nullptr);
    Serial.print("Startup time:");
    Serial.println(startupTime);

    /* Call to endless loop function which reads and processes data based on sensor settings */
    /* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes  */
    bsec_iot_loop(sleep, get_timestamp_us, output_ready, state_save, 10000);
}

void loop()
{
}

这是典型的串行监视器转储的开始:

Soft WDT reset

ctx: cont
sp: 3fff0df0 end: 40101b51 offset: 01b0


>>>stack>>>
3fff0fa0:  3fff31f4 3fff70ec 3fff662c 3fff372c
3fff0fb0:  0002d5a7 3fff70ec 3fff662c 40208866
3fff0fc0:  3fff662c 00000000 3fff703c 40201952
3fff0fd0:  3fff703c 00001388 3fff3b04 3fff0680
3fff0fe0:  000001bb 3fff662c 3fff31f4 3fff0680
3fff0ff0:  000001bb 3fff662c 3fff31f4 402089fd
3fff1000:  3ffe9770 5561c923 3ffe9770 5561c923
3fff1010:  3fff367c 00000000 3fff3684 4020717c
3fff1020:  00000000 00000206 00000206 4020526c
3fff1030:  fffffff4 00000000 3fff3684 40207980
3fff1040:  3ffe9584 00000046 3ffe96a9 40201ff3
3fff1050:  3fff36fc 3fff10c0 3fff367c 4020204c
3fff1060:  3fff3708 00000000 00000000 3ffe96a6
3fff1070:  3fff367c 3fff10a0 3ffe96a6 3ffe96a6
3fff1080:  3fff367c 3fff0680 3fff1188 402030fa
3fff1090:  3fff0660 3fff0680 3fff1188 40203b71
3fff10a0:  3fff3708 3e9b1316 3e9b1316 3d003b33
3fff10b0:  41ad99fb bf64685f 00000000 40212b8c
3fff10c0:  3fff39d0 af3cd700 0000d700 00000012
3fff10d0:  00000000 3fff11ac 3fff1198 3fff065c
3fff10e0:  3fff1128 3fff1128 402030e4 40202032
3fff10f0:  3fff112c 40590000 3ed1ca3e 3fff0660
3fff1100:  3fff11ac 3fff1120 3fff1188 40203e0a
3fff1110:  3fff1120 40fb6e3e 3fff2180 40219384
3fff1120:  3fff367c 3fff3944 3fff0680 41ad99fb

3 个答案:

答案 0 :(得分:1)

我几乎可以肯定这是因为你的代码永远不会到达loop()函数,在ESP8266 Arduino库上它会重置看门狗定时器每次循环函数的交互。

我认为你可以通过两种方式解决问题,一种是打开函数bsec_iot_loop()并将调用放在while(1)loop()函数中,另一种选择是调用{在ESP.wdtFeed()内{1}}重置看门狗定时器。

以下链接对ESP Arduino库上的看门狗定时器有很好的解释。

https://techtutorialsx.com/2017/01/21/esp8266-watchdog-functions/

答案 1 :(得分:1)

好的,所以我解决了这个问题。我怀疑看门狗定时器有问题。具体来说,代码永远不会达到while(1)函数,因为bsec_iot_loop()位于while(1)内。解决方案很简单。我将loop()内的代码放入{{1}}。其余的代码bsec_iot_loop()是变量的声明,我把它们变成了全局。

答案 2 :(得分:0)

不释放系统资源是arduino库中的常见问题。特别是在具有单核CPU的系统(例如esp8266)上,该系统没有本机线程可用。底层RTOS需要处理时间来维护其TCP-Stack和其他内容。时不时地调用yield()并不是一个可靠的解决方案。

esp8266的arduino标准库主要由阻塞函数组成,这经常使程序员陷入WDT-Pitfalls。

我总是建议人们为esp8266使用异步库。有很多可用的。并且始终将控制权尽可能地返回给操作系统,因为即使是简单的delay()-Calls都能触发WDT-Reset。