Pomoc s optimalizací

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
Odpovědět
rejze69
Příspěvky: 174
Registrován: 02 dub 2018, 18:56

Pomoc s optimalizací

Příspěvek od rejze69 » 23 kvě 2018, 08:31

Zdravim. Prokousávám se prvním projektem a jsou místa,kde mne to přinutí použít globální proměnnou,ale myslím si,že by to mělo jít s lokální,jen nepřijdu na to jak. V následujícím kódu jsou režimy nastavení hodin a tlaku vody. u hodin jsem si s lokální proměnnou vystačil,neb se ukládá každá změna hned. U nastavení tlaku vody se ukládá do EEPROM a tak jsem chtěl omezit počet zápisů a tam už mi to s lokální proměnnou nešlo. V tomhle případě sice ten počet zápisů nebude problém,protože tlak vody se nastaví jednou a časem možná o desetinku změní,ale v jinym případě to tak nemusí být a radši bych věděl jak na to.
kód je zde:

Kód: Vybrat vše

//----Funkce obsluhy displeje--------------------------------------
// pb pocet zobrazovanych bloku
// setCursor: co[] znak na radku, ro[] radek displeje
// va[] zobrazovane hodnoty
void Display(byte pb, byte co[], byte ro[], String va[]) { 
  for(int i = 0; i < pb; i++) {
    LCD.setCursor(co[i],ro[i]);
    LCD.print(va[i]);
  }
}

//-------Nastavení casu------------------------------------
void timeSetup() {
bool Century=true;
bool h12;
bool PM;
byte Year = Clock.getYear();
byte Month = Clock.getMonth(Century);
byte Date = Clock.getDate();
byte DoW = Clock.getDoW();
byte Hour = Clock.getHour(h12, PM);
byte Minute = Clock.getMinute();
byte Second = Clock.getSecond();
char datum[15];
char cas[10];
//Vytvoreni zobrazovanych hodnot
snprintf(datum, sizeof(datum), "20%02d %02d.%02d.", Year, Date, Month);
snprintf(cas, sizeof(cas), "%02d:%02d:%02d", Hour, Minute, Second);
 byte col[]={4,6,5};
 byte row[]={0,1,2};
 String val[]={datum, (String)dny[DoW], cas};
 Display(3,col,row,val); //volani obsluhy displeje
 //----------------------------
  switch(Set){ //polozky nastaveni casu. 
   case 1: // Potvrzenim polozky beze zmeny,preskoci na dalsi polozku,k zapisu dat nedojde
   if(Year != Year+krok) {
    Clock.setYear(Year+krok); //Okamzite ulozeni zmeny do RTC
    krok=0;
   }
   break;
   case 2: 
   if(Date != Date+krok) {
   Clock.setDate(Date+krok);
   krok=0;
   }
   break;
   case 3:
   if(Month != Month+krok) {
    Clock.setMonth(Month+krok);
    krok=0; 
   }
   break;
   case 4:
   if(DoW != DoW+krok) {
    Clock.setDoW(DoW+krok);
    krok=0;
   }
   break;
   case 5:
   if(Hour != Hour+krok) {
    Clock.setHour(Hour+krok);
    krok=0;
   }
   break;
   case 6:
   if(Minute != Minute+krok) {
   Clock.setMinute(Minute+krok);
   //Clock.setSecond(0);
   krok=0;
   }
   break;
   default:
   Clock.setSecond(0); //vynulovani sekund pro nastaveni presneho casu.
   Set=1; // Pripravi menu nastaveni na zacatek
   mod=0; // menu nastaveni tlaku vody
   LCD.clear();
  }
  
  if (EnterFlag == true) {
    LCD.clear();
    EnterFlag=false;
  }
}
//--------------------------------------------------------------
//          Nastaveni tlaku vody
//--------------------------------------------------------------
void pressSetup() {
  byte col[]={0,0,0};
  byte row[]={0,1,2};
  String val[]={"Nastaveni spin.tlaku",(String)"Pri " + ((float)HiPress /10) + " Bar Vypne ",
  (String)"Pri " + ((float)LoPress /10) + " Bar Zapne "};
  Display(3,col,row,val);
  switch(Set) {
    case 1:
    //LoPress=EEPROM.read(10);
    HiPress=(EEPROM.read(11)+krok);
    if(HiPress > 50) {
      HiPress=50;
      krok--;
    }
    else if(HiPress < LoPress+10) {
      HiPress=(LoPress+10);
      krok++;
    }
    break;
    case 2:
    LoPress=(EEPROM.read(10)+krok);
    if(LoPress < 20) {
      LoPress=20;
      krok++;
    }
    else if(LoPress > HiPress-10) {
      LoPress=(HiPress-10);
      krok--;
    }
    break;
    default:
    EEPROM.update(11, HiPress);
    EEPROM.update(10, LoPress);
    krok=0;
    Set=1;
    mod=0;
  }
   if(EnterFlag == true) {
    krok=0;
    LCD.clear();
    EnterFlag=false;
    }
/*  byte col[]={0,0,0};
  byte row[]={0,1,2};
  String val[]={"Nastaveni cerpadla",(String)"Pri " + ((float)HiPress /10) + " Bar Vypne ",
  (String)"Pri " + ((float)LoPress /10) + " Bar Zapne "};
  //Serial.println(val[1]);
  Display(3,col,row,val);*/
  
}
Díky pokud mne nějaká dobrá duše postrčí správným směrem.

Uživatelský avatar
gilhad
Příspěvky: 851
Registrován: 07 bře 2018, 11:22

Re: Pomoc s optimalizací

Příspěvek od gilhad » 24 kvě 2018, 02:33

Jaký máš problém s globální proměnnou? A s kterou?
První, kterou vidím, je LCD, následuje (nejspíš) Clock, dny, EEPROM ... ale v tom fragmentu není úplně jasné, jak a kde máš co deklarované a s čím máš vlastně problémy ...

rejze69
Příspěvky: 174
Registrován: 02 dub 2018, 18:56

Re: Pomoc s optimalizací

Příspěvek od rejze69 » 24 kvě 2018, 12:33

Jde o promenne hiPress a LoPress, ktere jsem puvodne chtel jako lokalni, ale prinutilo mne to pouzit globalni, protoze tak jak mam napsanou funkci pressureSetup mi to nefungovalo pri zmene case se ta promenna asi smaze, a neprisel jsem jak ji ukozit do eeprom nez se tak stane.
Funguje to tak, ze po stisku ENTER se zvysi promenna Set o 1 a na jeden cyklus je promenna enterFlag true. Proto to nefunguje, protoze ke zmene case dojde po stisku enter driv nez dojde k ulozeni. Ted premyslim zda to pujde kdyz misto switch pouziju podminky if, nebo jestli dopadnu stejne. Mozna budu muset zvetsovat Set jinym zpusobem nez tlacitkem ENTER. Uz ted ale vim, ze to rozlousknout musim, protoze nastaveni zavlazovacich okruhu je prave pripad, kde nelze ani ukladat kazdou zmenu a globalni promenne by bylo velke plytvani ram.

Uživatelský avatar
gilhad
Příspěvky: 851
Registrován: 07 bře 2018, 11:22

Re: Pomoc s optimalizací

Příspěvek od gilhad » 24 kvě 2018, 13:59

A proc ty promenne HiPress a LoPress neulozis hned po zmene?

Kód: Vybrat vše


switch(Set) {
    case 1:
    //LoPress=EEPROM.read(10);
    HiPress=(EEPROM.read(11)+krok);
    if(HiPress > 50) {
      HiPress=50;
      krok--;
    }
    else if(HiPress < LoPress+10) {
      HiPress=(LoPress+10);
      krok++;
    }
    EEPROM.update(11, HiPress);  // tady
    break;
    case 2:
    LoPress=(EEPROM.read(10)+krok);
    if(LoPress < 20) {
      LoPress=20;
      krok++;
    }
    else if(LoPress > HiPress-10) {
      LoPress=(HiPress-10);
      krok--;
    }
    EEPROM.update(10, LoPress); // a tady
    break;
    default:
//    EEPROM.update(11, HiPress);
//    EEPROM.update(10, LoPress);
    krok=0;
    Set=1;
    mod=0;
  }

rejze69
Příspěvky: 174
Registrován: 02 dub 2018, 18:56

Re: Pomoc s optimalizací

Příspěvek od rejze69 » 24 kvě 2018, 15:50

Tomu jsem se chtěl původně vyhnout kvůli omezeni poctu zapisu. Vim, ze zrovna v tomhle oripade to neni kriticky a tech zapisu by ve finale tolik nebylo. Ted ale treba u okruhu lze nastavovat az 240minut zavlazovani a to uz je dost. Funkce bude postavena podobne jako ty predchozi a proto to chci resit jinak. Ted jak jsem to rozebral pro vysvetleni me napadlo, ze zkusim inkrementovat promennou Set uvnitr funkce pomosi enterFlag. To by mohlo jit.

Uživatelský avatar
gilhad
Příspěvky: 851
Registrován: 07 bře 2018, 11:22

Re: Pomoc s optimalizací

Příspěvek od gilhad » 24 kvě 2018, 20:19

Potom bys musel:
  • ty LowPress/HiPress načíst na začátku funkce z EEPROM (nikoli pred kazdou úpravou)
  • v té funkci provádět taky čtení vstupu (zda se zvyšuje/snižuje a tak) - klidně voláním nějaké obecné funkce pro práci s menu/vstupy/výstupy (pokud s menu pracuješ víc na více místech asi je dobré si takovou napsat))
  • Po skočení menu, stále ještě v té funkci, pokud se mají nové hodnoty uložit, (v menu něco jako OK, UPDATE, ...) tak je uložit pomocí EEPROM.update() (zapisuje jen pokud se hodnota opravdu mění)
  • pokud se měnit nemají (CANCEL, ..) tak ukončit tu funkci bez zápisu.

Mimochodem, pokud ti dochází RAM, používej pro VŠECHNY řetězcové konstanty PROGMEM (ostatně i pro všechny ostatní konstanty, pro které nepoužiješ #define, například pole col[], row[] ...) (a samozřejmě příslušné manipulace s nima), to ti ušetří řádově víc paměti než pár globálních proměnných.

"Nastaveni spin.tlaku" samo o sobě je 21 byte RAM, čili 10x víc, než LowPress a HiPress dohromady (vzhledem k rozsahu 20..50 a čtení/zápis do jednoho byte v EEPROM očekávám, že mají nějaký (maximálně) 8bitový typ - pokud budou lokální, tak nemá cenu "šetřit" jejich zmáčknutím do nějakého bitového pole v tom samém bytu).

rejze69
Příspěvky: 174
Registrován: 02 dub 2018, 18:56

Re: Pomoc s optimalizací

Příspěvek od rejze69 » 25 kvě 2018, 01:39

PROGMEM je dobrá věc,ale to zkusim později. Ram mi zatim nedochází,tak si to dělám přímočaře jednoduché.
Trochu popíšu co mám funkční. Začal jsem konstrukcí uživatelského menu,které sestává z několika obrazovek s údaji. Ovládá se to třemi tlačítky,protože ke čtyřem se mi nevešly popisky na display a bez "cancel" či "esc" se dá fungovat,když se to tak postaví.
Spodní řádek tedy zobrazuje popisky tlačítek podle toho co zrovna mají dělat a tři zbylé zobrazují obsah. Mám zatím tři mezi kterými se pohybuje pravým nebo levým tlačítkem.1) Čas s tlakem vody a dnem v týdnu, 2)nastavené tlaky spínání čerpadla, 3) Zavlažovací okruhy s časem sepnutí,dobou zálivky v minutách a číslem které informuje jestli č1 denně,č2 obden atd. Všechny informační obrazovky jsou součástí hlavního programu,aby se při prohlížení stále měřilo a spínalo. Z každé jde prostředním tlačítkem vstoupit do nastavení toho o čem informuje. V režimu nastavení se opustí hlavní program aby mne to při nastavování neopláchlo. Bez cancel to jde,protože prostě buď proklikám enter,kdy se bez změn nic neukládá,nebo přestanu mačkat tlačítka a po půl minutě se to odkudkoli automaticky vrátí na hlavní obrazovku s časem a zhasne podsvícení.
Pole col[] row[] val[] jsou na více místech deklarovány jako lokální a jsou v nich informace co se bude zobrazovat. Udělal jsem to abych nemusel dokola opisovat lcd. . . . a ušetřilo to několik procent flash. Jako bonus jsem pak zjistil,že je to přehledné a snadno se dělají změny.
Aktuálně píšu funkci nastavení zavlažovacích okruhů,pak přijde vlhkost půdy a pak pro tenhle základ čtení sensorů a řídící logika.
Škoda,že jsem s tím nezačal v zimě,protože to mám na tyhle záliby čas. Teď se k tomu dostanu jednou,dvakrát týdně na dvě hodiny a tak to letos už asi kropit nebude. :lol:
Každopádně moc děkuju za rady. Všechno se mi bude dříve či později hodit.

rejze69
Příspěvky: 174
Registrován: 02 dub 2018, 18:56

Re: Pomoc s optimalizací

Příspěvek od rejze69 » 26 kvě 2018, 08:47

Nakonec jsem tedy zkusil inkrementovat proměnnou Set uvnitř funkce a tlačítko enter nyní posílá pouze EnterFlag=true.
Funguje to teď s lokální proměnnou HiPress a LoPress.
Chtěl bych se ještě omluvit,že jsem úplně správně nevysvětlil o co mi šlo.
Nešlo mi o ty dvě konkrétní proměnné (byly jen vhodný příklad) , ale o to jak postupovat v takových případech a používat lokální proměnné místo globálních i když se mi zdá,že to nejde.
Přepsaný a líp okomentovaný fragment:

Kód: Vybrat vše

//----Funkce obsluhy displeje--------------------------------------
// pb pocet zobrazovanych bloku
// setCursor: co[] znak na radku, ro[] radek displeje
// va[] zobrazovane hodnoty
void Display(byte pb, byte co[], byte ro[], String va[]) { 
  for(int i = 0; i < pb; i++) {
    LCD.setCursor(co[i],ro[i]);
    LCD.print(va[i]);
  }
}

//-------Funkce Nastavení casu------------------------------------
void timeSetup() {
//--------Promenne pro RTC
bool Century=true;
bool h12;
bool PM;
byte Year = Clock.getYear();
byte Month = Clock.getMonth(Century);
byte Date = Clock.getDate();
byte DoW = Clock.getDoW();
byte Hour = Clock.getHour(h12, PM);
byte Minute = Clock.getMinute();
byte Second = Clock.getSecond();
//---------Promenne pro zobrazeni
char datum[15];
char cas[10];
//Vytvoreni zobrazovanych hodnot
snprintf(datum, sizeof(datum), "20%02d %02d.%02d.", Year, Date, Month);
snprintf(cas, sizeof(cas), "%02d:%02d:%02d", Hour, Minute, Second);
 byte col[]={4,6,5};
 byte row[]={0,1,2};
 String val[]={datum, (String)dny[DoW], cas};
 Display(3,col,row,val); //volani obsluhy displeje
 //----------------------------
  switch(Set){ //polozky nastaveni casu. 
   case 1: // Potvrzenim polozky beze zmeny,preskoci na dalsi polozku,k zapisu dat nedojde
   if(Year != Year+krok) {
    Clock.setYear(Year+krok); //Okamzite ulozeni zmeny do RTC
    krok=0;
   }
    if (EnterFlag == true) { //po stisku enter
      Set++;                 // prejdi na dalsi polozku
    }
   break;
   case 2: 
   if(Date != Date+krok) {
    Clock.setDate(Date+krok);
    krok=0;
   }
   if (EnterFlag == true) {
      Set++;
    }
   break;
   case 3:
   if(Month != Month+krok) {
    Clock.setMonth(Month+krok);
    krok=0; 
   }
   if (EnterFlag == true) {
      Set++;
    }
   break;
   case 4:
   if(DoW != DoW+krok) {
    Clock.setDoW(DoW+krok);
    krok=0;
   }
   if (EnterFlag == true) {
      Set++;
    }
   break;
   case 5:
   if(Hour != Hour+krok) {
    Clock.setHour(Hour+krok);
    krok=0;
   }
   if (EnterFlag == true) {
      Set++;
    }
   break;
   case 6:
   if(Minute != Minute+krok) {
   Clock.setMinute(Minute+krok);
   krok=0;
   }
   if (EnterFlag == true) {
      Set++;
    }
   break;
   default:
   Clock.setSecond(0); //vynulovani sekund pro nastaveni presneho casu.
   Set=1; // Pripravi menu nastaveni na zacatek
   mod=0; // navrat do hlavniho programu
   LCD.clear();
  }
  
  if (EnterFlag == true) { // po stisku enter
    LCD.clear();           // smaz display
    EnterFlag=false;
  }
}
//--------------------------------------------------------------
//          Nastaveni tlaku vody
//--------------------------------------------------------------
void pressSetup() {
  byte HiPress=EEPROM.read(11); //promenne pro nastaveni tlaku
  byte LoPress=EEPROM.read(10);
  switch(Set) {
    case 1:
    HiPress=(EEPROM.read(11)+krok); //Inkrementace od puvodni hodnoty
    if(HiPress > 50) { //nastaveni horni meze
      HiPress=50;
      krok--;
    }
    else if(HiPress < LoPress+10) { // vymezeni minimalni hystereze 1 bar
      HiPress=(LoPress+10);
      krok++;
    }
    if (EnterFlag == true) {      //po stisku enter
      EEPROM.update(11, HiPress); // uloz hodnotu
      Set++;                      //prejdi na dalsi polozku
    }
    break;
    case 2:
    LoPress=(EEPROM.read(10)+krok); //inkrementace puvodni hodnoty
    if(LoPress < 20) { //nastaveni spodni meze
      LoPress=20;
      krok++;
    }
    else if(LoPress > HiPress-10) { // minimalni hystereze 1 bar
      LoPress=(HiPress-10);
      krok--;
    }
    if (EnterFlag == true) { //po stisku enter
      EEPROM.update(10, LoPress); //uloz hodnotu
      Set++; //prejdi na default
    }
    break;
    default: // vynulovani pro dalsi cyklus nastaveni
    krok=0;
    Set=1;
    mod=0; // a navrat do hlavniho programu
  }
//-----nacteni dat pro display
  byte col[]={0,0,0};
  byte row[]={0,1,2};
  String val[]={"Nastaveni spin.tlaku",(String)"Pri " + ((float)HiPress /10) + " Bar Vypne ",
  (String)"Pri " + ((float)LoPress /10) + " Bar Zapne "};
//-----
  Display(3,col,row,val); //volani zobrazeni
  
     if(EnterFlag == true) { //po stisku enter
    krok=0; //vynuluj inkrementaci v tomto cyklu nastaveni
    LCD.clear();
    EnterFlag=false;
    }
}
//-----------------------------------------------------------------
//----------Nastaveni spinacich okruhu
//-----------------------------------------------------------------

void circuitSet() {
  byte h[3]= {EEPROM.read(21),EEPROM.read(22),EEPROM.read(23)};
  byte m[3]= {EEPROM.read(31),EEPROM.read(32),EEPROM.read(33)};
  byte d[3]= {EEPROM.read(41),EEPROM.read(42),EEPROM.read(43)};
  byte dz[3]={EEPROM.read(51),EEPROM.read(52),EEPROM.read(53)};
  char nastaveni [22];
  snprintf(nastaveni, sizeof(nastaveni), "%02d:%02d kazdy %d %dmin", h[Set-1], m[Set=1], d[Set-1], dz[Set=1]);
  byte col[]={0,7,0};
  byte row[]={0,1,2};
  String val[]={"Nastaveni zavl. okr.",(String)"Okr "+Set,nastaveni};
  Display(3,col,row,val);
}

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 3 hosti