Посоветуйте способ найти проблему с памятью при работе с датчиками по i2c

Привет.
Самостоятельно потратил уже около двух недель на поиск бага - не могу ничего сам решить… спасайте :slight_smile:
Бы ла у меня программа, которая собирала данные с UART и 3х датчиков по i2c и с борта ESP8266 отправляла данные в “народный мониторинг”. OK.

Около 2х лет это работало, но вот я решил что-то доработать в программе и она посыпалась. Я взял скетч за 2021г - компилирую новой IDE - не работает. Переношу код на другую ESP8266 - не работает. Переношу на Arduino nano - не работает.

Физически все датчики подключены. i2c тестер проходят всегда. Осцилофограмма красивая. Адреса казаны правильно.

Думаю, что все дело в программе. Начинаю делить и получаю такой результат:
BME680 - самостоятельно работает
CCS811 - самостоятельно работает
HDC1080 - самостоятельно работает

BME680 + HDC1080 - вместе работает

только подключаю опрос CCS811 - програма крашится. В лучшем случае плюется мусором в порт но может и зависнуть.

Начинаю думать, что или библиотеки конфликтуют или оперативной памяти не хватает.
Но как локализовать проблему и/или ее решить?

void setup() {
  pinMode(13,OUTPUT);
  Serial.begin(115200);

  MyI2Csetup();

  Testi2c();

//  Serial.println("BME680 test"); Serial.flush(); MyBME680setup();
//  Serial.println("CCS811 test"); Serial.flush(); CCS811setup();
  Serial.println("HDC1080 test"); Serial.flush(); StartHDC1080();
}

void loop() {
  digitalWrite(13, !digitalRead(13));
  
//  TestBME680(); delay(1000);
//  CCS811read(); delay(1000);
  ReadHDC1080(); delay(1000);
}

Для начала выложите полный код.
А также приведите сообщения об ошибках. И опишите подробнее, чтьо означает “программа не работает”

Полный код состоит из файлов соотвествующих библиотек + “мои файлы” - это код типа Serialprintln(readDatchik()); Причем “мой” код основан на примерах из интернета.
Всего около 15 файлов.

Скетч компилируется и ошибок не выдает. В программе тоже ошибок как таковых нет.

Если программа работает - это опрос датчика один раз в несколько секунд и в терминал выплевывается стандартная "температура = 23 влажность =40 ". Дуешь на датчик - значения меняются.

Если в моем примере расскоментировать только 1 датчик - данные идут непрерывно и логично.

Если расскоментировать датчик CCS811 и еще один, но вместо данных CCS811 начинает идти мусор. Как будто терминал глотает какие то символы. При этом еще один датчик показывает логичные данные.

Если расскоментировать все датчики - программа может зависнуть. Т.е. в терминале видно, что прошла иннициализация i2c, прочитались все адреса, и все. НИЧЕГО нет. Данные в терминал не идут. Светодиод на плате не моргает.

BME680 один отдает данные:

Датчик CC811 один отдает данные:

Датчик HDC1080 один отдает данные:

Датчик HDC1080 и BME680 вместе отдают данные

Датчик CC811 и BME680 вместе работают:

Зависание программы, когда все три датчика раскоментированы.
Прошел мусор с CC811 и программа зависла:
(когда датчик один - работает стабильно)

@Veoramid
Без полного кода я не вижу ни малейшего шанса как-то вам помочь. Может кто-то другой сможет…

Удачи в ваших проектах.

На сторонние ресурсы здесь не ходят.

Основной скетч

#include "MyI2C.h"
#include "MyHDC1080.h"
#include "MyBME680.h"
#include "MyCCS811.h"
#include <avr/wdt.h>


// Переменные, создаваемые процессом сборки,     // http://microsin.net/programming/avr/arduino-determining-amount-free-and-used-ram.html
// когда компилируется скетч
extern int __bss_end;
extern void *__brkval;
 
// Функция, возвращающая количество свободного ОЗУ (RAM)
int memoryFree()
{
   int freeValue;
   if((int)__brkval == 0)
      freeValue = ((int)&freeValue) - ((int)&__bss_end);
   else
      freeValue = ((int)&freeValue) - ((int)__brkval);
   return freeValue;
}

void setup() {
  pinMode(13,OUTPUT);
  Serial.begin(115200);

  MyI2Csetup();

  Testi2c();
  
  wdt_reset();
  Serial.println("BME680 test"); Serial.flush(); MyBME680setup(); Serial.print(F("memoryFree1()=")); Serial.println( memoryFree() );
  wdt_reset();  
  Serial.println("HDC1080 test"); Serial.flush(); StartHDC1080(); Serial.print(F("memoryFree2()=")); Serial.println( memoryFree() );
  wdt_reset();
  Serial.println("CCS811 test"); Serial.flush(); CCS811setup();   Serial.print(F("memoryFree3()=")); Serial.println( memoryFree() );
  
}

void loop() {
  digitalWrite(13, !digitalRead(13));
  
  TestBME680(); delay(1000);  Serial.print(F("memoryFree4()=")); Serial.println( memoryFree() );
  
  ReadHDC1080(); delay(1000); Serial.print(F("memoryFree5()=")); Serial.println( memoryFree() );
  
  CCS811read(); delay(1000);  Serial.print(F("memoryFree6()=")); Serial.println( memoryFree() );  

  delay(1);
}

My!2C.h


#include <Wire.h>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MyI2Csetup(void) {

  Wire.begin();
  //Wire.begin(cSDA, cSCL); /* задаем i2c мост через контакты SCL=D1 и SDA=D2 на NodeMCU */
  //Wire.begin(SCL, SDA); /* задаем i2c мост через контакты SDA=D1 и SCL=D2 на NodeMCU */
  delay(500);

}  




// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Testi2cDevice(byte adress) {
  Wire.beginTransmission(adress);
  byte n = 1; 
  byte d; 
  
  //Wire.Write(i);
  //error = Wire.endTransmission();

  for (byte i = 0; i <= 10; i++)
  {
   Wire.requestFrom(adress, n);
   if ( Wire.available() ) { d = Wire.read(); Serial.print(d,HEX); }
   else return;
  }
  
  
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Testi2c(void)
 {
  byte error, address;
  int nDevices;
  
  Serial.println(F("\nI2C Scanner"));
 
  Serial.println(F("Scanning..."));
 
  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
 
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print(F("I2C device found at address 0x"));
      if (address<16) Serial.print(F("0")); Serial.print(address,HEX);
      
      switch (address)
      {
        case 0x77: Serial.print(F(" BME680"));  break;
        case 0x40: Serial.print(F(" HDC1080")); break;
        case 0x5A: Serial.print(F(" CCS811"));  break;
      }
      
      Serial.print("  !   "); Testi2cDevice(address); Serial.println();
 
      nDevices++;

      
      
    }
    else if (error == 4) 
    {
      Serial.print(F("Unknow error at address 0x")); if (address<16) Serial.print(F("0")); Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0) Serial.println(F("No I2C devices found\n"));  
  else               Serial.println(F("done\n"));


  Wire.endTransmission();  
 
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

MyBME680.h

/*
 * https://arduino.ua/ru/prod4512-modyl-datchika-kachestva-vozdyha-bme680-i2c5v
 */



#define cBME680_adress 0x77



// - - - - - - - - - - - - - - - - - - - 
// Датчик качества воздуха #1
//

#include <Adafruit_Sensor.h>
#include <Adafruit_BME680.h>                  // Библиотека BME680

#define SEALEVELPRESSURE_HPA (1014.58)        // Высота над уровне моря

Adafruit_BME680 bme680; //i2C                 // Объект




// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

struct struct_BME680                            // Структура данных
{
  boolean BME680ok = false;
    float Temp;                                 // Температура
    float Humi;                                 // Влажность
    float Alti;                                 // Высота
    float pkPa;                                 // Давление кПа
    float pmmH;                                 // Давление mmH
    
    float Ohms;                                 // VOC [Ом]
    
    float KOhm;                                 // VOC [КОм]
    float VOC0100;                              // VOC [%]
    unsigned long PWM1023;                      // VOC [AO%]
    
} var_struct_BME680;                          // Переменная труктурная


void MyBME680setup(void);
void TestBME680(void);
void OutText(void);




// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

void MyBME680setup(void) {

  // - - - - - - - - - - - - - - - - - 
  //Serial.println(F("BME680 test"));
  Serial.println(F("BME680: init Begin 1")); Serial.flush();


 //   var_struct_BME680.BME680ok = bme680.begin(BME680_adress,true);
      var_struct_BME680.BME680ok = bme680.begin(cBME680_adress);

  Serial.println(F("BME680: init Begin 2"));      
  
  if (!var_struct_BME680.BME680ok) {
    Serial.println(F("BME680: Could not find a valid BME680 sensor, check wiring!"));
    // var_struct_BME680.BME680ok = bme680.begin(BME680_adress,true);
    //while (1);                                                                          // зависание
    Serial.println(F("BME680: init fiasko"));
    return;
  }

  if (var_struct_BME680.BME680ok) 
   {
    // Set up oversampling and filter initialization
    bme680.setTemperatureOversampling(BME680_OS_8X);
    bme680.setHumidityOversampling(BME680_OS_2X);
    bme680.setPressureOversampling(BME680_OS_4X);
    bme680.setIIRFilterSize(BME680_FILTER_SIZE_3);
    bme680.setGasHeater(320, 150); // 320*C for 150 ms
   }
   
 Serial.println(F("BME680: init End"));
}   







// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TestBME680(void){
  static unsigned long OldMillisBME;
         unsigned long NewMillisBME = millis();

  if ( ((NewMillisBME - OldMillisBME) > 4999) )
   {
    OldMillisBME = NewMillisBME;

    

if (! bme680.performReading() ) {
    Serial.println(F("BME680: Failed to perform reading :("));

    var_struct_BME680.Temp  = -9.9;
    var_struct_BME680.Humi  = -9.9;
    var_struct_BME680.pkPa  = -9.9;
    var_struct_BME680.KOhm  = -9.9;
    var_struct_BME680.Alti  = -9.9;
    
    return;
  }

    var_struct_BME680.Temp  = bme680.temperature;                        //Serial.print("Temperature = ");        Serial.print(bme.temperature); Serial.println(" *C");
    var_struct_BME680.Humi  = bme680.humidity;                           //Serial.print("Humidity = ");           Serial.print(bme.humidity);Serial.println(" %");
    
    var_struct_BME680.pkPa  = (bme680.pressure / 100.0);///1000.0;          //Serial.print("Pressure = ");           Serial.print(bme.pressure / 100.0); Serial.println(" hPa");
    var_struct_BME680.Ohms  = bme680.gas_resistance;                     //Serial.print("Gas = ");                Serial.print(bme.gas_resistance / 1000.0);Serial.println(" KOhms");
    var_struct_BME680.Alti  = bme680.readAltitude(SEALEVELPRESSURE_HPA); //Serial.print("Approx. Altitude = ");   Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));Serial.println(" m"); Serial.println();

    //var_struct_BME680.pmmH  = (var_struct_BME680.pkPa * 760.0) / 101.325; // mmH ????

    var_struct_BME680.pmmH  = var_struct_BME680.pkPa * 0.75006375541921; // mmH
    var_struct_BME680.KOhm  = var_struct_BME680.Ohms / 1000.0;        //Serial.print("Gas = ");                Serial.print(bme.gas_resistance / 1000.0);Serial.println(" KOhms");

    var_struct_BME680.VOC0100 = map(var_struct_BME680.Ohms, 0, 300000, 100, 0 );     // Пересчет в проценты 100...0
    var_struct_BME680.PWM1023 = map(var_struct_BME680.Ohms, 0, 110000, 0, 1023);     // Пересчет в проценты 0...1023


//    OutGraph(&var_struct_All);
     OutText();

  //Serial.println();
  
 }
}




// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OutText(void){

   Serial.print(F("BME680: "));
   Serial.print(F("Temperature = "));        Serial.print(var_struct_BME680.Temp); Serial.print(" *C ");
   Serial.print(F("Humidity = "));           Serial.print(var_struct_BME680.Humi); Serial.print(" % ");
   Serial.print(F("Pressure = "));           Serial.print(var_struct_BME680.pkPa); Serial.print(" hPa ");
   Serial.print(F("Gas = "));                Serial.print(var_struct_BME680.KOhm);  Serial.print(" KOhms ");
   Serial.print(F("Approx. Altitude = "));   Serial.print(var_struct_BME680.Alti); Serial.print(" m "); 
   
   Serial.println();
  
}



// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OutText(struct_BME680 *BME680){

   Serial.print(F("Temperature = "));        Serial.print(BME680->Temp); Serial.println(" *C");
   Serial.print(F("Humidity = "));           Serial.print(BME680->Humi); Serial.println(" %");
   Serial.print(F("Pressure = "));           Serial.print(BME680->pkPa); Serial.println(" hPa");
   Serial.print(F("Gas = "));                Serial.print(BME680->KOhm);  Serial.println(" KOhms");
   Serial.print(F("Approx. Altitude = "));   Serial.print(BME680->Alti); Serial.println(" m"); 
   
   Serial.println();
  
}

MyCC811.h

#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;


void CCS811setup(void);
void CCS811read(void);



void CCS811setup(void){

 Serial.println("CCS811: Begin Setup 1"); Serial.flush(); 

  if(!ccs.begin(0x5A)){
    Serial.println("CCS811: Failed to start sensor! Please check your wiring."); Serial.flush();
//    ESP.restart();
    while(0);
  }

  Serial.println("CCS811: Begin Setup 2"); Serial.flush(); 

  // Wait for the sensor to be ready
  while(!ccs.available());


}  






void CCS811read(void){
  
  Serial.println(F("CCS811: Begin")); Serial.flush();
  
  if(ccs.available()){

    Serial.println(F("CCS811: Датчик есть ")); Serial.flush();
    
    if(!ccs.readData()){

      Serial.println(F("CCS811: ДА прочитали данные ")); Serial.flush();

      word vCO2 = ccs.geteCO2();
      word vVOC = ccs.getTVOC();

      Serial.print(F("CCS811: CO2: ")); Serial.print(vCO2); Serial.print(F("ppm, TVOC: ")); Serial.println(vVOC); Serial.flush();
    }
    else{
      Serial.println(F("CCS811: ERROR!")); Serial.flush();
      return;
      //while(1);
    }
  }
  else {Serial.println(F("СС811: Датчик не готов")); Serial.flush();}
  
  Serial.println(F("CCS811: End")); Serial.flush();

}  

MyHDC1080.h

// - - - - - - - - - 
// https://www.youtube.com/watch?v=t1vCKlzr2W8
#include "ClosedCube_HDC1080.h"

#define hdc1080_adress 0x40

ClosedCube_HDC1080 hdc1080;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct struct_HDC1080                         // Структура данных
{
  boolean HDC1080ok = false;
    float Temp = -9.99;                       // Температура
    float Humi = -9.99;                       // Влажность

} var_struct_HDC1080;                         // Переменная труктурная


void printSerialNumber(void);
void StartHDC1080(void);
void ReadHDC1080(void);


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StartHDC1080(void)
{

  // Default settings: 
  //  - Heater off
  //  - 14 bit Temperature and Humidity Measurement Resolutions
  hdc1080.begin(hdc1080_adress);

  word m_id = hdc1080.readManufacturerId();
  word d_id = hdc1080.readDeviceId();

  Serial.println(F("HDC1080: "));
  Serial.print(F("Manufacturer ID=0x"));   Serial.println(m_id, HEX); // 0x5449 ID of Texas Instruments
  Serial.print(F("Device ID=0x"));         Serial.println(d_id, HEX); // 0x1050 ID of the device

  if (m_id == 0x5449) { var_struct_HDC1080.HDC1080ok = true; }
  else   Serial.println(F("HDC1080: No Code!!"));
  
  printSerialNumber();  

  Serial.println(); Serial.flush();
  
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ReadHDC1080(void)
{
 static long OldTime = 0;
        long NewTime = millis();

 if ( (NewTime - OldTime) < 5000 ) return; OldTime = NewTime;

  Serial.println(F("HDC1080: Begin"));  Serial.flush();

 if (!var_struct_HDC1080.HDC1080ok) 
  {
    StartHDC1080();
    return;
  }

 var_struct_HDC1080.Temp = hdc1080.readTemperature();
 var_struct_HDC1080.Humi = hdc1080.readHumidity();

  
  Serial.print(F("HDC1080: ")); Serial.print(F("T=")); Serial.print(var_struct_HDC1080.Temp); Serial.print(F(" C, RH=")); Serial.print(var_struct_HDC1080.Humi);  Serial.println(F("%")); Serial.flush();
  /**/

  Serial.println("HDC1080: End"); Serial.flush();
  
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void printSerialNumber(void) {
  Serial.print(F("HDC1080: Device Serial Number=")); Serial.flush();
  HDC1080_SerialNumber sernum = hdc1080.readSerialNumber();
  char format[12];
  sprintf(format, "%02X-%04X-%04X", sernum.serialFirst, sernum.serialMid, sernum.serialLast); Serial.println(format); Serial.flush();
}
  char format[12];
  sprintf(format, "%02X-%04X-%04X", sernum.serialFirst, sernum.serialMid, sernum.serialLast); 

Скоко символов в строке ?

3 лайка

СПАСИБО!!!

Похоже это оно :frowning:
Глаз видел, но мозг не зацепил.
Пример взят 1:1 из примера и на Гитхабе он так (с ошибкой) и висит…

Интересная конструкция…

Почти после каждой печати:

Зачем?

Таймеры должны быть unsigned long

В “оригинальных” примерах было while(1) . Это они так останавливали программу.

Я пытался найти где программа крашится. По описанию flush() это “Функция ожидает завершения процесса отправки всех исходящих данных по последовательному интерфейсу.”
Не помогло.

Спасибо. Недосмотрел.