Dělička události pomocí for()

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
Reputation: 0

Dělička události pomocí for()

Příspěvek od rejze69 » 12 čer 2018, 02:55

Zdravim. Rád bych se zeptal zda mi bude fungovat tento časový spínač.

Kód: Vybrat vše

void timeSwitch(){ //casovy spinac okruhu
  bool h12;
  bool PM;
  for(int i=1; i<4; i++) { //smycka pro vyhodnoceni casu sepnuti pro tri okruhy
    if(Clock.getHour(h12, PM)== EEPROM.read(20+i)&& Clock.getMinute()== EEPROM.read(30+i)
    && EEPROM.read(40+i)>0) { //pokud EEPROM.read = 0 okruh je vypnuty
      Ok[i] = true; //povoli sepnuti v nastaveny cas
    }
  }
  if(Ok1==true) { //paklize nadesel cas sepnuti okruhu1
    for(int o1=EEPROM.read(41); o1>0; o1--) { //delicka dnu sepnuti(denne,obden atd)
      if(o1!=1) { //dokud nebude o1 = 1 
       Ok1=false; //sepnuti okruhu 1 bude zakazano
      }
      break; //preruseni smycky do dalsiho casoveho okna
    }
  }
  if(Ok2==true) {
    for(int o2=EEPROM.read(42); o2>0; o2--) {
      if(o2!=1) {
       Ok2=false; 
      }
      break;
    }
  }
  if(Ok3==true) {
    for(int o3=EEPROM.read(43); o3>0; o3--) {
      if(o3!=1) {
       Ok3=false; 
      }
      break;
    }
  }    
}
Jde o to,že podle nastavení může spínat denně,nebo obden nebo až jednou týdně. Smyčkou for s příkazem break; doufám,že toho dosáhnu.na praktické testování pokus omyl je to ale příliš dlouhý interval a tak prosím někoho kdo ví o radu zda to opravdu udělá co čekám.

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

Re: Dělička události pomocí for()

Příspěvek od rejze69 » 12 čer 2018, 13:22

Asi uz vidim chybu. Break; by mělo být pod podmínkou if(o1! =1) aby v případě že bude dosaženo cíle cyklus for() doběhl a mohl začít znovu?

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

Re: Dělička události pomocí for()

Příspěvek od rejze69 » 13 čer 2018, 21:51

Asi je špatně celá myšlenka.

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

Re: Dělička události pomocí for()

Příspěvek od rejze69 » 14 čer 2018, 02:30

Tak jsem to přepsal a púvodní problém je vyřešen. jenže nastal další.
Potřebuji od sepnutí relé prodlevu která je uložená v eeprom a nechce mi to porovnávat millis s hodnotou z eeprom.
kód:

Kód: Vybrat vše

void timeSwitch(){ //casovy spinac okruhu
  bool h12;
  bool PM;
  if ((unsigned long)(millis() - readingTswitch >= 61000)) { //cas 1min 1sec do dalsiho porovnani po shodě
  for(int i=1; i<4; i++) { //smycka pro vyhodnoceni casu sepnuti pro tri okruhy
    if(Clock.getHour(h12, PM)== EEPROM.read(20+i)&& Clock.getMinute()== EEPROM.read(30+i)
    && EEPROM.read(40+i)>0) { //pokud EEPROM.read = 0 okruh je vypnuty
      Ok[i] = true; //povoli sepnuti v nastaveny cas
      readingTswitch = millis();    
    }
  }
  }
  if(Ok[1]==true && o1>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o1--; //odecti den
      Ok[1]=false; //zakaz zalivku
  }
  if(Ok[2]==true && o2>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o2--; //odecti den
      Ok[2]=false; //zakaz zalivku
}
  if(Ok[3]==true && o3>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o3--; //odecti den
      Ok[3]=false; //zakaz zalivku
}
if(Ok[1]==true) {
  digitalWrite(Okr1,HIGH);
   Okr1Timeout=millis();
   Ok[1]=false;
   o1=EEPROM.read(41);     
}
   if (millis() >= ((unsigned long)(6000*EEPROM.read(51)+Okr1Timeout))) { //TADY JE PROBLÉM
   digitalWrite(Okr1,LOW);
   
   }
}
Tam co je napsáno TADY PROBLÉM
Pokud tam dám jen 6000+Okr1Timeout,funguje to. Když to ale vynásobim EEPROM.read,tak to nefunguje. Podmínka je tedy splněna a relé zůstane LOW.
Co v tom nevidim,nebo spíš nevim? Díky za radu.

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

Re: Dělička události pomocí for()

Příspěvek od rejze69 » 14 čer 2018, 16:21

Teď jsem zkusil uložit násobek EEPROM.read*6000 do unsigned long proměnné. EEPROM obsahuje číslo 10,takže by tam mělo být 60000,ale je tam těch 4294967295 co se vejde do unsigned long. Kde dělám chybu?

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

Re: Dělička události pomocí for()

Příspěvek od gilhad » 14 čer 2018, 16:25

Nevim, ale u podobnych radovanek jsem narazil na to, ze uvnitr zavorek se mi to pretypovalo nejak, neco nejak se spocetlo a pak se pretypoval az cely vysledek. Pro zacatek bych teda na ty unsigned long pretypoval i kazdou hodnotu v te zavorce i celou zavorku. ten EEPROM.read je napriklad byte, 6000 je signed int (-32k ... +32k) , takze bych se vubec nedivil kdyby ten soucin treba pro hodnotu 10 v EEPROM vysel zaporny (60k>32K, jde tedy o preteceni a je otazkou, jak se k tomu prekladac postavi, nejspis to zignoruje a vyjde mu zaporne cislo) a odecetl se ti. nebo udelal libovolnou jinou zajimavou zlotrilost.

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

Re: Dělička události pomocí for()

Příspěvek od rejze69 » 14 čer 2018, 16:33

Zkusil jsem ještě úplně vynechat cokoli neprůhledného a zadeklaroval unsigned long Epr1=10*6000. Prostá čísla kde bych nečekal žádnou zradu a přesto je v té proměnné 4294967295. To už přece s datovými typy nemůže mít nic do činění.
Aha teď jsem si ještě jednou přečetl Tvůj příspěvek a i prostá čísla v programu překladač natypuje podle velikosti?

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

Re: Dělička události pomocí for()

Příspěvek od gilhad » 14 čer 2018, 20:41

Ano, pokud nejsou natypovana jinak. Schvalne zkus

Kód: Vybrat vše

unsigned long Epr1=10UL * 6000UL;
(tam ti to neprevede automaticky)

pekne je to popsano v prvni odpovedi tady

https://stackoverflow.com/questions/131 ... ong-values

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

Re: Dělička události pomocí for()

Příspěvek od rejze69 » 15 čer 2018, 08:31

Díky. To bylo ono. Teď už to funguje jak má. Jen se ještě zeptám jestli je rozumné řešit časový interval až 240 minut pomocí millis() tak jak to tam mám napsané s ohledem na přetečení,protože tam neporovnávám s rozdílem,ale se součtem.
To místo označené TADY PROBLÉM
Díky.
kód:

Kód: Vybrat vše

void timeSwitch(){ //casovy spinac okruhu
  bool h12;
  bool PM;
  unsigned long Epr1=((unsigned long)EEPROM.read(51)*6000UL);
  if ((unsigned long)(millis() - readingTswitch >= 61000)) { //cas 1min 1sec do dalsiho porovnani po shodě
  for(int i=1; i<4; i++) { //smycka pro vyhodnoceni casu sepnuti pro tri okruhy
    if(Clock.getHour(h12, PM)== EEPROM.read(20+i)&& Clock.getMinute()== EEPROM.read(30+i)
    && EEPROM.read(40+i)>0) { //pokud EEPROM.read = 0 okruh je vypnuty
      Ok[i] = true; //povoli sepnuti v nastaveny cas
      readingTswitch = millis();    
    }
  }
  }
  if(Ok[1]==true && o1>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o1--; //odecti den
      Ok[1]=false; //zakaz zalivku
  }
  if(Ok[2]==true && o2>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o2--; //odecti den
      Ok[2]=false; //zakaz zalivku
}
  if(Ok[3]==true && o3>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o3--; //odecti den
      Ok[3]=false; //zakaz zalivku
}
if(Ok[1]==true) {
  digitalWrite(Okr1,HIGH);
   Okr1Timeout=millis();
   Ok[1]=false;
   o1=EEPROM.read(41);
} 
if(digitalRead (Okr1)) {  
   if ((unsigned long)millis() >= Epr1+Okr1Timeout) { //TADY JE PROBLÉM
   digitalWrite(Okr1,LOW);
   Serial.println(Epr1);
   }  
}

}
Až budu mít dokončenou alespoň základní porovnávací logiku,dám to do projektů a postupně to budu dokončovat.

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

Re: Dělička události pomocí for()

Příspěvek od rejze69 » 17 čer 2018, 01:19

Nakonec jsem se rozhodl to napsat bez millis() raději s RTC. První co mne napadlo bylo převést nastavené minuty na hodiny a minuty a sečíst to do proměnné s aktuálním časem.Tu potom porovnat a po dosažení shody ukončit zálivku. Jenže se mi to zdálo zbytečně složitý a plán ukončil tím převodem. Ten je sám o sobě jednoduchej a kdyby to někdo potřeboval:

Kód: Vybrat vše

if(minuty<60) {
  minu=minuty;
}
else {
for(int i=minuty; i>=60; i=i-60) {
  hod++;
  minu=i-60;
}
}
Doufám že jsem tam nic nespletl,protože jsem to vyzkoušený smazal.

Nakonec jsem to vyřešil odpočtem rovnou těch minut podle RTC. Je to tam okomentovaný,funguje to a je to jednodušší než obě předchozí řešení.

Kód: Vybrat vše

void timeSwitch(){ //casovy spinac okruhu
  bool h12;
  bool PM;
  if ((unsigned long)(millis() - readingTswitch >= 61000)) { //cas 1min 1sec do dalsiho porovnani po shodě
  for(int i=1; i<4; i++) { //smycka pro vyhodnoceni casu sepnuti pro tri okruhy
    if(Clock.getHour(h12, PM)== EEPROM.read(20+i)&& Clock.getMinute()== EEPROM.read(30+i)
    && EEPROM.read(40+i)>0) { //pokud EEPROM.read = 0 okruh je vypnuty
      Ok[i] = true; //povoli sepnuti v nastaveny cas
      readingTswitch = millis(); //povoleni dalsiho porovnani   
    }
  }
  }
  if(Ok[1]==true && o1>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o1--; //odecti den
      Ok[1]=false; //zakaz zalivku
  }
  if(Ok[2]==true && o2>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o2--; //odecti den
      Ok[2]=false; //zakaz zalivku
}
  if(Ok[3]==true && o3>1) { //paklize nadesel cas sepnuti okruhu1 a neuplynuly dny mezi zalivkami
      o3--; //odecti den
      Ok[3]=false; //zakaz zalivku
}
if(Ok[1]==true) { //Po predchozich porovnanich trva stav true
  digitalWrite(Okr1,HIGH); //Sepni zavlazovani okruhu 
   mPrev[1]=Clock.getMinute(); //ulozeni aktualni minuty
   m[1]=EEPROM.read(51); //Nacteni nastavene doby zalivky v minutach
   Ok[1]=false;          //vynulovani okruhu pro pristi cyklus
   o1=EEPROM.read(41);   //nacteni prednastavene frkvence dnu zalivky pro pristi cyklus
} 
if(digitalRead (Okr1)) {  //pokud je sepnuto rele okruhu 
   if (mPrev[1] != Clock.getMinute()) { //kdyz se neshoduji aktualni minuty s predchozimi,uplynula minuta
  m[1]--;                               //sniz pocet minut do konce zalivky
  mPrev[1]=Clock.getMinute();           //znovu uloz aktualni minutu pro dalsi porovnani
   }  
   if(m[1]<=0) {                        //kdyz dosahne pocet minut do konce zalivky nuly
   	digitalWrite(Okr1,LOW);             //Vypni rele (ukonci zalivku okruhu )
   }	
}
if(Ok[2]==true) {
  digitalWrite(Okr2,HIGH);
   mPrev[2]=Clock.getMinute();
   m[2]=EEPROM.read(52);
   Ok[2]=false;
   o1=EEPROM.read(42);
} 
if(digitalRead (Okr2)) { 
   if (mPrev[2] != Clock.getMinute()) {
  m[2]--;
  mPrev[2]=Clock.getMinute();
   }  
   if(m[2]<=0) {
     digitalWrite(Okr2,LOW);
   }  
}
if(Ok[3]==true) {
  digitalWrite(Okr3,HIGH);
   mPrev[3]=Clock.getMinute();
   m[3]=EEPROM.read(53);
   Ok[3]=false;
   o3=EEPROM.read(43);
} 
if(digitalRead (Okr3)) { 
   if (mPrev[3] != Clock.getMinute()) {
  m[3]--;
  mPrev[3]=Clock.getMinute();
   }  
   if(m[3]<=0) {
     digitalWrite(Okr3,LOW);
   }  
}
}

Odpovědět

Kdo je online

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