天天看點

關于Arduino架構下開發ESP8266+Blinker應用EEPROM不能正常使用的問題關于Arduino架構下開發ESP8266+Blinker應用EEPROM不能正常使用的問題

關于Arduino架構下開發ESP8266+Blinker應用EEPROM不能正常使用的問題

最近在嘗試用ESP8266+Blinker開發一個語音控制的智能開關,涉及到一些使用者資料的存儲,嘗試加入之前寫的EEPROM代碼後發現原來正常的代碼到這卻不能跑了。

踩了整整一天的坑,網上很多人也遇到了類似的問題,但沒有給出完整的解決方案,在這裡總結一下。

問題的核心是,Blinker庫也使用了EEPROM。

在每次使用EEPROM前都要調用begin方法

這是一個比較隐蔽但非常坑的問題。

先貼一個Arduino的EEPROM例程(删掉了所有注釋),相信這是很多人的EEPROM啟蒙教材:

#include <EEPROM.h>

int address = 0;
byte value;

void setup() {
  Serial.begin(115200);
  EEPROM.begin(512);
}

void loop() {
  value = EEPROM.read(address);

  Serial.print(address);
  Serial.print("\t");
  Serial.print(value, DEC);
  Serial.println();

  address = address + 1;
  
  if (address == 512) {
    address = 0;
  }

  delay(500);
}
           

瞅着沒啥問題,運作起來也沒啥問題是吧。

那我們看看Blinker裡邊對EEPROM的操作,挑裡邊

BlinkerESPMQTTAT

這個類來看看,隻關注EEPROM的操作就可以:

class BlinkerESPMQTTAT : public BlinkerApi
{
    public :
        void begin()
        {
            BApi::begin();

            ::delay(100);

            EEPROM.begin(BLINKER_EEP_SIZE);
            EEPROM.get(BLINKER_EEP_ADDR_SERIALCFG, serialSet);

            uint32_t ss_baud = serialSet >> 8 & 0x00FFFFFF;
            ss_cfg = serConfig();

            if (ss_baud != 300    || ss_baud != 1200    || ss_baud != 2400   ||
                ss_baud != 4800   || ss_baud != 9600    || ss_baud != 19200  ||
                ss_baud != 38400  || ss_baud != 57600   || ss_baud != 74880  ||
                ss_baud != 115200 || ss_baud != 230400  || ss_baud != 250000 ||
                ss_baud != 500000 || ss_baud != 1000000 || ss_baud != 2000000)
            {
                serialSet = BLINKER_SERIAL_DEFAULT;
                ss_baud = 9600;
                ss_cfg = SERIAL_8N1;
                
                EEPROM.put(BLINKER_EEP_ADDR_SERIALCFG, serialSet);
            }

            EEPROM.commit();
            EEPROM.end(); // 注意這裡!!!!!!!!!!!!!!!!!!!!

            Serial.begin(ss_baud, ss_cfg);
            Transp.serialBegin(Serial, true);
            transport(Transp);
            BApi::atBegin();
            // strcpy(BApi::_authKey, this->conn.authKey().c_str());
            // strcpy(BApi::_deviceName, this->conn.deviceName().c_str());
            BApi::loadTimer();
            BLINKER_LOG(BLINKER_F("BLINKER_MQTT_AT initialized..."));
        }

    private :
        BlinkerMQTTAT Transp;
};
           

Blinker庫在調用完EEPROM後,用了

end()

方法!

他在玩一種很新的東西,這會導緻什麼呢,我們去EEPROM的源碼裡看看這個方法做了什麼:

bool EEPROMClass::end() {
  bool retval;

  if(!_size) {
    return false;
  }

  retval = commit();
  if(_data) {
    delete[] _data;
  }
  _data = 0;
  _size = 0; // 注意這裡!!!!!!!!!!!!!!!!!!!!
  _dirty = false;

  return retval;
}
           

這個方法把

EEPROM::_size

清零了!

這又會導緻什麼呢,我們再看看

EEPROM::read

uint8_t EEPROMClass::read(int const address) {
  if (address < 0 || (size_t)address >= _size) { // 注意這裡!!!!!!!!!!!!!!!!!!!!
    DEBUGV("EEPROMClass::read error, address %d > %d or %d < 0\n", address, _size, address);
    return 0;
  }
  if (!_data) {
    DEBUGV("EEPROMClass::read without ::begin\n");
    return 0;
  }

  return _data[address];
}
           

address

大于

_size

的時候,讀的所有結果都會變成0!

避開Blinker庫使用的EEPROM位址

程式正常運作後,我們檢視Blinker的log會發現:

[7150] =======================================================
[7151] =========== Blinker Auto Control mode init! ===========
[7160]      EEPROM address 0-1279 is used for Auto Control!
[7168] ======= PLEASE AVOID USING THESE EEPROM ADDRESS! ======
[7177] =======================================================
           
[34120] 
===========================================================
================== Blinker Timer loaded! ==================
     EEPROM address 1536-2431 is used for Blinker Timer!
========= PLEASE AVOID USING THESE EEPROM ADDRESS! ========
===========================================================
           

可見Blinker庫使用了

0-1279

1536-2431

的EEPROM位址,我們使用的時候避開即可。

踩了整整一天的坑,生活不易,給個贊鼓勵鼓勵!

繼續閱讀