Global variables taking up too much dynamic memory

Hello,

I am new to user to Arduino. I am currently creating a sketch for 5 air pollution sensors which will be used in a device with an Arduino Nano microcontroller, but am receiving the following error:

Global variables use 3082 bytes (150%) of dynamic memory, leaving -1034 bytes for local variables. Maximum is 2048 bytes.
Not enough memory

I would appreciate any tips on how to reduce the memory or if I should try using a Mega instead. The sketch is not yet complete. Thanks!

// MQ 131 libraries and definitions
#include <MQUnifiedsensor.h>

#define placa "Arduino UNO"
#define Voltage_Resolution 5
#define pin A0 //Analog input 0 of your arduino
#define type "MQ-131" //MQ131
#define ADC_Bit_Resolution 10 // For arduino UNO/MEGA/NANO
#define RatioMQ131CleanAir 15 //RS / R0 = 15 ppm
//#define calibration_button 13 //Pin to calibrate your sensor

MQUnifiedsensor MQ131(placa, Voltage_Resolution, ADC_Bit_Resolution, pin, type);

#define EXE_INTERVAL_131 500
unsigned long lastExecutedMillis_131 = 0; // vairable to save the last executed time for MQ 131

// PM2.5 libraries and variables
#define EXE_INTERVAL_25 100
unsigned long lastExecutedMillis_25 = 0; // vairable to save the last executed time for PM2.5 setup

#define EXE_INTERVAL_25_2 5000
unsigned long lastExecutedMillis_25_2 = 0; // vairable to save the last executed time for PM2.5 loop

#include <Tomoto_HM330X.h>

Tomoto_HM330X sensor;
// Tomoto_HM330X sensor(Wire1); // to use the alternative wire

void printValue(const char* label, int value) {
  Serial.print(label);
  Serial.print(": ");
  Serial.println(value);
}

// Multichannel grove libraries and variables
#include <Wire.h>
#include "MutichannelGasSensor.h"
#define SENSOR_ADDR     0X04        // default to 0x04
#define PRE_HEAT_TIME   30           // pre-heat time, 10-30 minutes is recommended

#define EXE_INTERVAL_multi 1000
unsigned long lastExecutedMillis_multi = 0; // vairable to save the last executed time for multichannel sensor

// AM2320 libraries and variables
#include "AM232X.h"

AM232X AM2320;

#define EXE_INTERVAL_2320 2000
unsigned long lastExecutedMillis_2320 = 0; // vairable to save the last executed time for AM2320 setup

#define EXE_INTERVAL_2320_2 2000
unsigned long lastExecutedMillis_2320_2 = 0; // vairable to save the last executed time for AM2320 loop

// MQ 135 variables
#define EXE_INTERVAL_135 20
unsigned long lastExecutedMillis_135 = 0; // vairable to save the last executed time for MQ 135


void setup() {
  // MQ 131 setup
  //Init the serial port communication - to debug the library
  Serial.begin(9600); //Init serial port

  //Set math model to calculate the PPM concentration and the value of constants
  MQ131.setRegressionMethod(1); //_PPM =  a*ratio^b
  MQ131.setA(23.943); MQ131.setB(-1.11); // Configurate the ecuation values to get O3 concentration

  MQ131.init();

  Serial.print("Calibrating please wait.");
  float calcR0 = 0;
  for (int i = 1; i <= 10; i ++)
  {
    MQ131.update(); // Update data, the arduino will be read the voltage on the analog pin
    calcR0 += MQ131.calibrate(RatioMQ131CleanAir);
    Serial.print(".");
  }
  MQ131.setR0(calcR0 / 10);
  Serial.println("  done!.");

  if (isinf(calcR0)) {
    Serial.println("Warning: Conection issue founded, R0 is infite (Open circuit detected) please check your wiring and supply");
    while (1);
  }
  if (calcR0 == 0) {
    Serial.println("Warning: Conection issue founded, R0 is zero (Analog pin with short circuit to ground) please check your wiring and supply");
    while (1);
  }
  /*****************************  MQ CAlibration ********************************************/
  MQ131.serialDebug(true);

  // MQ 135 setup
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);

  // PM2.5 setup
  unsigned long currentMillis = millis();

  if (currentMillis - lastExecutedMillis_25 >= EXE_INTERVAL_25) {
    lastExecutedMillis_25 = currentMillis; // save the last executed time

    Serial.begin(115200);
    // Wire.begin(25, 21); // to specify the I2C pins

    if (!sensor.begin()) {
      Serial.println("Failed to initialize HM330X");
      while (1)
        ;
    }

    Serial.println("HM330X initialized");
    Serial.println();
  }

  // Multichannel grove setup
  if (currentMillis - lastExecutedMillis_multi >= EXE_INTERVAL_multi) {
    lastExecutedMillis_multi = currentMillis; // save the last executed time

    Serial.begin(115200);
    gas.begin(SENSOR_ADDR);   //
    Serial.println("power on, and pre-heat");
    for (int i = 60 * PRE_HEAT_TIME; i >= 0; i--)  {
      Serial.print(i / 60);
      Serial.print(":");
      Serial.println(i % 60);
    }
    Serial.println("Begin to calibrate...");
    gas.doCalibrate();
    Serial.println("Calibration ok");
    gas.display_eeprom();
  }

  // AM 2320 setup
  if (currentMillis - lastExecutedMillis_2320 >= EXE_INTERVAL_2320) {
    lastExecutedMillis_2320 = currentMillis; // save the last executed time

    Serial.begin(115200);
    Serial.println(__FILE__);
    Serial.print("LIBRARY VERSION: ");
    Serial.println(AM232X_LIB_VERSION);
    Serial.println();

    if (! AM2320.begin() )
    {
      Serial.println("Sensor not found");
      while (1);
    }
    AM2320.wakeUp();

    // sensor only returns one decimal.
    Serial.println();
    Serial.println("Read:\t");

    int status = AM2320.read();
    switch (status)
    {
      case AM232X_OK:
        Serial.println("OK");
        break;
      default:
        Serial.println(status);
        break;
    }
    Serial.print("Temperature:\t");
    Serial.println(AM2320.getTemperature(), 1);
    Serial.print("   Humidity:\t");
    Serial.println(AM2320.getHumidity(), 1);

    Serial.println();
    Serial.println("GET SENSOR INFO (experimental)");
    Serial.print("  Model:\t");
    Serial.println(AM2320.getModel());
    Serial.print("Version:\t");
    Serial.println(AM2320.getVersion());
    Serial.print("  DevId:\t");
    Serial.println(AM2320.getDeviceID());

    Serial.println();
    Serial.println("GET REGISTERS (experimental)");
    Serial.print(" Status:\t");
    Serial.println(AM2320.getStatus());
    Serial.print("  UserA:\t");
    Serial.println(AM2320.getUserRegisterA());
    Serial.print("  UserB:\t");
    Serial.println(AM2320.getUserRegisterB());

    Serial.println();
    Serial.println("SET REGISTERS (experimental)");
    AM2320.setStatus(42);
    Serial.print("Status   42  ==> ");
    Serial.println(AM2320.getStatus());
    AM2320.setUserRegisterA(1234);
    Serial.print("UserA   1234 ==> ");
    Serial.println(AM2320.getUserRegisterA());
    AM2320.setUserRegisterB(5678);
    Serial.print("UserB   5678 ==> ");
    Serial.println(AM2320.getUserRegisterB());

    Serial.println("done...\n");
  }

}

void loop() {
  // MQ 131 loop
  unsigned long currentMillis = millis();

  if (currentMillis - lastExecutedMillis_131 >= EXE_INTERVAL_131) {
    lastExecutedMillis_131 = currentMillis; // save the last executed time

    MQ131.update(); // Update data, the arduino will be read the voltage on the analog pin
    MQ131.readSensor(); // Sensor will read PPM concentration using the model and a and b values setted before or in the setup
    MQ131.serialDebug(); // Will print the table on the serial port

  }

  // MQ 135 loop
  if (currentMillis - lastExecutedMillis_135 >= EXE_INTERVAL_135) {
    lastExecutedMillis_135 = currentMillis; // save the last executed time

    // read the input on analog pin 1:
    int sensorValue = analogRead(A1);
    // print out the value you read:
    Serial.println(sensorValue);
  }

  // PM2.5 loop
  if (currentMillis - lastExecutedMillis_25_2 >= EXE_INTERVAL_25_2) {
    lastExecutedMillis_25_2 = currentMillis; // save the last executed time

    if (!sensor.readSensor()) {
      Serial.println("Failed to read HM330X");
    } else {
      printValue("Sensor number", sensor.getSensorNumber());

      Serial.println("Concentration based on CF=1 standard particlate matter (ug/m^3) --");
      printValue("PM1.0", sensor.std.getPM1());
      printValue("PM2.5", sensor.std.getPM2_5());
      printValue("PM10", sensor.std.getPM10());

      Serial.println("Concentration based on atmospheric environment (ug/m^3) --");
      printValue("PM1.0", sensor.atm.getPM1());
      printValue("PM2.5", sensor.atm.getPM2_5());
      printValue("PM10", sensor.atm.getPM10());

      // Maybe supported or not, depending on the sensor model
      Serial.println("Number of particles with diameter of (/0.1L) --");
      printValue(">=0.3um", sensor.count.get0_3());
      printValue(">=0.5um", sensor.count.get0_5());
      printValue(">=1.0um", sensor.count.get1());
      printValue(">=2.5um", sensor.count.get2_5());
      printValue(">=5.0um", sensor.count.get5());
      printValue(">=10um", sensor.count.get10());

      Serial.println();
    }

    // AM 2320 loop
    if (currentMillis - lastExecutedMillis_2320_2 >= EXE_INTERVAL_2320_2) {
      lastExecutedMillis_2320_2 = currentMillis; // save the last executed time

      int status = AM2320.read();
      switch (status)
      {
        case AM232X_OK:
          Serial.println("OK");
          break;
        default:
          Serial.println(status);
          break;
      }
      Serial.print("Temp:\t");
      Serial.println(AM2320.getTemperature(), 1);
      Serial.print("Hum:\t");
      Serial.println(AM2320.getHumidity(), 1);
    }

  }
}

Only use globals for what needs to be global. Pass values to subs that use local vars instead. It's a different coding approach than BASIC where most everything is global.

post your code in code tags, please.

In this case, it's likely this advice has to pass to the included library author.

Use the F macro for string literals. https://www.baldengineer.com/arduino-f-macro.html

Use PROGMEM and const to store constants in flash.

I, as well as many members, will not download code. Read the forum guidelines to see how to properly post code and some information on how to get the most from this forum.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

3 Likes

I edited my original post to include the code in tags.

Thank you everyone for the feedback! Will update once I have had the chance to try these suggestions.

Didn't you guess that things were about to go tango uniform after just two sensors?

You could use external memory, volatile or non volatile, communication by either SPI\ or I2C. I use FRAM module that is 32Kx8 and only costs a few dollars. groundFungus recommends using the "F" macro, it works great I use it almost all the time. Serial.print(F("F-Macro"));, not a lot different then the standard print function. Try it you will like it!

My guess would be that one of the libraries you included is using a MASSIVE amount of RAM. I recommend you compile one example sketch from each library to see how much RAM each uses. If you find one that is causing most of the problems, look for an alternative library for the same device.

Alternatively, use a different Arduino with more RAM. An Arduino Mega would be the most software compatible. A third-party board like a "Teensy", "ESP8266", or "ESP32" would be more capable.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.