Stránka 1 z 1

Co místo String? ESP8266

Napsal: 19 srp 2019, 21:18
od NCPlyn
Ahoj, mám program na NodeMCU ESP8266, který každou minutu přečte z spiffs až 750 bajtů a dá je do stringu.

Kód: Vybrat vše

File file = SPIFFS.open("/times.txt", "r");
  while (file.available()) {
    String line = file.readStringUntil('n');
    Serial.print(line);
    if(line.indexOf(nowtime) >= 0) {
      file.close();
      digitalWrite(5, LOW);
      delay(60000);
      digitalWrite(5, HIGH);
    } else {
      file.close();
    }
  }
Jelikož jsem někde zaslechl, že String není dobrá volba pro používání, protože zabírá vždy novou část paměti a místo přepsání. Chtěl bych teda na toto použít něco jiného... kam se to vejde, nemusím určovat specifickou velikost protože se může obsah měnit a můžu v tom najít jiný string (line.indexOf(nowtime)).

Nevím jestli něco takového by se dalo udělat, napadl mě char nebo EEPROM, ale ani s jedním nemám nějaké dobré zkušenosti.

Re: Co místo String? ESP8266

Napsal: 20 srp 2019, 06:13
od pavel1tu
1) EEPROM - pokud si v manuálu přečteš, kolikrát jde přepsat - jistě pochopíš, že častým přepisováním ji odepíšeš
2) CHAR - ukládá jen jeden znak, musel by jsi použít pole znaků CHAR[] - pokud použiješ třeba CHAR[10] pro 10 znaků, asi na tom vyděláš při vícenásobném použití proti STRINGu.
3) STRING - způsob použití, místo kde jej deklaruješ se mi zdá nevýhodné, pokud ti mizí paměť, může to být tím, že "String line" znovu a znovu deklaruješ za běhu programu. Nevím jak to pak funguje doopravdy, ale já bych tu deklaraci dal na začátek kam patří.

Ale z C++ vím, že STRING obsadí jen 256 bajtů, pokud do něj pošleš delší text, nepřeteče, nic se nestane. CPU za tebe spravuje paměť.
Pokud použiješ CHAR[] neboli pole znaků, při poslání delšího textu než je deklarace pole, data přetečou do dalších paměťových buněk, způsobí t neplechu - v poli jsi zodpovědný za svá data sám.

Je to popsáno již v základních příručkách, ale nevím co platí u CPU ATmega a dalších.

Re: Co místo String? ESP8266

Napsal: 20 srp 2019, 09:11
od pavel1tu
Já dost věcí čerpám z těchto stránek, i když moc neumím anglicky.

lekce String/char
https://www.tweaking4all.com/hardware/a ... ng-part-7/

Ještě doplním ...
Problém je v tom, že operace String přidělují paměť dynamicky a způsobem, který je těžké předvídat, když jsou vstupy do programu proměnné, v kombinaci se skutečností, že Arduinos mají velmi omezené množství paměti RAM (2 kB na Arduino Uno). Dynamické přidělování paměti obvykle způsobuje fragmentaci paměti. To znamená, že váš program může pracovat správně pro některé vstupy nebo na krátkou dobu, ale dojde k selhání s jinými vstupy nebo po delší době v důsledku vyčerpání paměti.
Pokud tedy ukládáš do String různě dlouhé "data", ATMega si musí tyto nové pole uložit v paměti na jiné místo a paměť se mu začíná "fragmentovat".
Já o tom někde četl (a opustil jsem pro daný projekt klasické ATMega CPU)
https://critical.eschertech.com/2010/07 ... d-systems/

Já začal používat pole, ale stejně jsem dojel na množství paměti + nebezpečí "přetečení", které za tebe CPU ani kompilátor asi nehlídá.
Máš char[100] - pole 100 znaků a na pozici char[95] uložíš text "Nove data z mereni" - je jasné, že už "data z mereni" přetečou v paměti někam neznámo kam. Osobně to nemohu prokázat, nevím jestli mi ATMega dojela na nedostatek paměti nebo tím přetečením - vždy se kousla.

Re: Co místo String? ESP8266

Napsal: 20 srp 2019, 09:27
od KarelBrno
NCPlyn:
Tak jak máš ten program napsaný, tak to skutečně bude žrát zbytečně moc paměti - s každým novým řádkem v souboru se alokuje v paměti další nová instance Stringu + k ní paměť se samotným textovým řetězcem, takže při dostatečném množství řádků může paměť dojít. Deklaruj ten String ještě před cyklem, tak bude paměť zabírat jen jeden String + text aktuálního řádku.

Jinak obecně se Stringy je problém hlavně na Arduinech, ty mají jen 2kB RAM a když si to člověk nehlídá, tak může dojít hodně rychle. ESP8266 má řádově více RAM (desítky kB), takže tam to tak horké není.

Kdyžtak v tvém případě, pokud skutečně čteš vždy max. 750 bajtů, tak místo stringu možná můžeš použít char[751] (ten jeden znak navíc tam asi bude potřeba pro ukončovací znak 0).