Skocz do zawartości

Brak pamięci - optymalizacja kodu/bibliotek?


sitar

Pomocna odpowiedź

Dzień dobry!

Tworzę własną stację meteo na platformie Arduino. Wykorzystuję do tego kilka czujników:

  • ESP-01 - wysyłanie danych na serwer MySQL
  • DS18B20 - temperatura otoczenia
  • BMP280 - ciśnienie (tylko)
  • DHT22 - wilgotność (tylko)
  • ML8511 - UV
  • PMS3003 - zanieczyszczenie powietrza
  • FC37 - deszcz
  • MLX90614 - mierzę temperaturę gdy jest wycelowany w niebo, do informacji o zachmurzeniu.

Dane mają zostać odczytane i wysłane na serwer. Problem w tym, że nie mieszczę się z wszystkim w pamięci. Po napisaniu kodu (poniżej) dostaję komunikat: 

Cytat

Szkic używa 23066 bajtów (71%) pamięci programu. Maksimum to 32256 bajtów.
Zmienne globalne używają 1416 bajtów (69%) pamięci dynamicznej, pozostawiając 632 bajtów dla zmiennych lokalnych. Maksimum to 2048 bajtów.

Mimo, że jeszcze nie pojawia się komunikat o dużym wykorzystaniu pamięci, to kod nie działa, tzn. nie łączy się z bazą danych. Skąd teza, że to przez brak pamięci? Po usunięciu z kodu wszystkiego związanego np. z BMP280 ten sam program zajmuje już 66% pamięci programu i 66% pamięci dynamicznej, a połączenie z bazą jest nawiązane normalnie.

Warto zauważyć, że do bazy jeszcze nawet nie wpisuję zebranych danych, bo przykładowy insert dla biblioteki MySQL Connector zawiera tablice charów i funkcje dtostrf() i sprintf(), których użycie już całkowicie zajmuje miejsce i zgłasza ostrzeżenie o możliwej niestabilności programu. Również nie wiem jak to rozwiązać bardziej pamięciooszczędnie.

Zdecydowanie najwięcej pamięci zabiera część odpowiedzialna za komunikację (ESP i MySQL Connector). Może da się łatwo odchudzić biblioteki ze zbędnych funkcji, których nie wykorzystuję w kodzie, szczególnie, że w BMP i DHT nie korzystam ze wszystkich sensorów? Dodam tylko, że nigdy wcześniej nie pisałem nic w C++, więc pewnie wykorzystywanie niektórych funkcji jest w tym przypadku niezalecane.

Jest inne rozwiązanie poza przesiadką na NodeMCU?

 

Kod:

#include <WiFiEsp.h>            //ESP
#include <SoftwareSerial.h>     //ESP
#include <MySQL_Cursor.h>       //ESP, MySQL
#include <Adafruit_MLX90614.h>  //MLX
#include <Adafruit_BMP280.h>    //BMP
#include <DHT.h>                //DHT
#include <DS18B20.h>            //DS

byte sensorAddress[8] = {0x28, 0xAA, 0x55, 0xE, 0x41, 0x14, 0x1, 0xCC}; //DS adress
OneWire onewire(5);             //DS PIN
DS18B20 ds(&onewire);

int UVOUT = A1;                 //ML PINS
int REF_3V3 = A2;

Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Adafruit_BMP280 bmp;

unsigned char bufor [23];       //PMS
int PM25 = 0, PM10 = 0;
int wartoscPM25(unsigned char *thebuf);
int wartoscPM10(unsigned char *thebuf);
char sprawdzLancuch(unsigned char *thebuf, char leng);

char ssid[] = "OWN_NETWORK";      // network SSID
char pass[] = "12345#xD";         // network password
char user[] = "arduino";          // MySQL user login username
char password[] = "";             // MySQL user login password
IPAddress server_addr(192,168,43,165);

int status = WL_IDLE_STATUS;      // the Wifi radio's status
WiFiEspClient espclient;
SoftwareSerial soft(2,3);         // RX, TX
DHT dht(4, DHT22);                //DHTPIN DHTTYPE

MySQL_Connection conn((Client *)&espclient);

void setup() {
  Serial.begin(9600);             // initialize serial for debugging
  soft.begin(115200);             // initialize serial for ESP module
  soft.write("AT+UART_DEF=9600,8,1,0,0\r\n");
  soft.begin(9600);
  
  mlx.begin();
  bmp.begin();
  dht.begin();
  ds.begin();

  pinMode(UVOUT, INPUT);
  pinMode(REF_3V3, INPUT);
  
  WiFi.init(&soft);                // initialize ESP
  
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    while (true);                  // don't continue
  }
  
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
  }
}

void loop() {
  float skytemp = mlx.readObjectTempC();                                  //read skytemperature
  int pressure = bmp.readPressure()/100;                                  //read pressure
  int humidity = dht.readHumidity();                                      //read humidity
  int rain = analogRead(A2);                                              //read rain
  ds.request(sensorAddress);                                              //read temperature
  while(!ds.available());
  float temp = ds.readTemperature(sensorAddress);
  
  int uvLevel = averageAnalogRead(UVOUT);                                 //read UV
  int refLevel = averageAnalogRead(REF_3V3);
  float outputVoltage = 3.3 / refLevel * uvLevel;
  float uvIntensity = mapfloat(outputVoltage, 0.99, 2.8, 0.0, 15.0);

  if(Serial.find(0x42))                                                  //read air
    Serial.readBytes(bufor,23);
     if(bufor[0] == 0x4d){
      PM25=wartoscPM25(bufor);
      PM10=wartoscPM10(bufor); 
    }

  if (conn.connect(server_addr, 3306, user, password)) {                //connect MySQL
    delay(1000);
    MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
    cur_mem->execute("INSERT INTO weather.parameters (temperature, pressure, humidity, rain) VALUES (20, 1013, 50, 1);");
    delete cur_mem;
    Serial.println("Data recorded.");
    conn.close();
  }
  else {
    Serial.println("Connection failed.");
  }
    
  delay(180000);
}

int averageAnalogRead(int pinToRead) {
  byte numberOfReadings = 8;
  unsigned int runningValue = 0; 

  for(int x = 0 ; x < numberOfReadings ; x++)
    runningValue += analogRead(pinToRead);
  runningValue /= numberOfReadings;

  return(runningValue);  
}

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

int wartoscPM25(unsigned char *buf) {
  int PM25v;
  PM25v=((buf[11]<<8) + buf[12]);  
  return PM25v;
}

int wartoscPM10(unsigned char *buf) {
  int PM10v;
  PM10v=((buf[13]<<8) + buf[14]); 
  return PM10v;
}

 

Link do komentarza
Share on other sites

możesz przerzucić komunikację z bazą na esp, ale to wymagałoby napisania na to coś oddzielnego programu (connector działa bardzo ładnie na esp).

ogólnie lepiej zastosować do tego esp32 - będzie szybciej i taniej, niż zabawa z arduino i esp01.

  • Lubię! 2
Link do komentarza
Share on other sites

@ethanak @FlyingDutch  dzięki Panowie za odpowiedź. Czy zmieniając platformę, nie łatwiej będzie przejść na wspomniane przeze mnie NodeMCU v3? Jest tańsze i mniejsze od Waszych propozycji i ma 4MB flash. Nie wiem tylko jak to do końca wygląda z portami, obecnie wykorzystuję 5 analogowych (w tym A4, A5 do I2C), i 6 cyfrowych nie licząc ESP (w tym I2C i RX, TX do Seriala). Jeśli wyrzucę jedno złączę, to będzie akurat na styk z tymi 10x GPIO, czy są jakieś obostrzenia z nimi związane?

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

nodemcu i więcej niż jedno wejście analogowe to dodatkowe koszty. da się (robiłem to przed wejściem na rynek esp32) ale więcej nie chcę.

jaki masz problem z esp32? nie mów że koszty - bo w sumie będzie taniej niż klon mega plus coś najtańszego  do wifi...

  • Lubię! 1
Link do komentarza
Share on other sites

1 godzinę temu, ethanak napisał:

nodemcu i więcej niż jedno wejście analogowe to dodatkowe koszty. da się (robiłem to przed wejściem na rynek esp32) ale więcej nie chcę.

jaki masz problem z esp32? nie mów że koszty - bo w sumie będzie taniej niż klon mega plus coś najtańszego  do wifi...

Cześć,

zgadzam się całkowicie z kolegą @ethanak, lepiej przejść na ESP32. Jest tylko jeden problem - z bibliotekami nie wszystkie muszą poprawnie działać z ESP32. Ja np. trochę się "nawalczyłem" z biblioteką do czujnika BMP280 (nie wiadomo jak jest z innymi bibliotekami).

Pozdrawiam

 

  • Lubię! 1
Link do komentarza
Share on other sites

@ethanak no dobra, cena ESP nie jest problemem. Obecnie zależy mi na czymś, co najprościej będzie podmienić zamiast Arduino Uno i doprowadzenia do działającego stanu. A skoro zmieniać platformę, to najlepiej coś z wbudowanym ESP. Jako, że jestem początkującym użytkownikiem Arduino, to tym bardziej mam średnie rozeznanie w innych platformach 😉  

Z czym pokrótce muszę się mierzyć przy przesiadce na ESP32? Złącza analogowe wykorzystuje się jak w Arduino? Dla modułów działających na 5V wystarczy dorzucić dwukierunkowy konwerter 5V<-->3.3V? 

@FlyingDutch Liczę, że większość będzie się dało dostosować, bo to jednak popularne czujniki 😉 

Link do komentarza
Share on other sites

18 minut temu, sitar napisał:

A skoro zmieniać platformę, to najlepiej coś z wbudowanym ESP

No wiesz, ESP32 ma wbudowany ESP 😉

w 99% przypadków programujesz to tak samo jak Arduino. Do złącz analogowych wystarczy zwykły dzielnik napięcia (jeśli potrzebujesz, bo pewnie nie).

Sprawdź jakie moduły będą działać na 3.3V.

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

10 minut temu, ethanak napisał:

No wiesz, ESP32 ma wbudowany ESP 😉

@ethanak  rozumiem uszczypliwość, ale tym zdaniem raczej chciałem odrzucić Arduino Mega 😀

Na 5 V właściwie jest tylko FC37, ewentualnie chciałem dorzucić wentylator z kompa jako czujnik wiatru (12 V), ale to nie będzie problem. Tak to jeszcze PMS3003 działa na logice 3,3 V, ale potrzebuje zasilania 5 V.

Dla ścisłości pozwolę się jeszcze dopytać, bo jestem nieco zagubiony we wszystkich wersjach - może być ta wersja spod tego LINKU

Link do komentarza
Share on other sites

1 minutę temu, sitar napisał:

rozumiem uszczypliwość,

Nie przesadzaj. Zapytałeś co ma wbudowane ESP - to odpowiedziałem... a co miałem odpowiedzieć? 🙂

Poza tym nie sprawdziłeś dokładnie- np. DS18B20 działają u mnie już cztery lata na 3.3V... może dlatego, że nie powiedziałem im, że nie powinny? 😉

 

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.