C/C++ week Anniversary - BF
80 % bodů zdarma na online výuku díky naší Narozeninové akci!
Pouze tento týden sleva až 80 % na e-learning týkající se C/C++

Diskuze: Arduino UNO r.3 ohřev bazénu

Aktivity (2)
Avatar
cinkim
Člen
Avatar
cinkim:22. března 21:50

Ahoj, už asi měsíc se snažím pochopit proč se moje Arduino nechová jak jsem si představoval.
Chci si vyrobit řízený ohřev bazénu. Vstupní hodnoty budou digitální snímač osvětlení, analogový snímač teploty vzduchu a analogový snímač teploty vody. Na plastové krabičce mám 4x led diodu. Prví se rozsvítí při dostatečné intenzitě osvětlení, druhá při min. venkovní teplotě třeba 22stupnů, třetí pokud teplota vody je menší než 28 stupňů. Teprve když budou všechny svítit, sepne relé pro oběhové čerpadlo a rozsvítí se poslední dioda. Zatím to mám bez udělané bez snímání teploty vody a už teď to nejsem schopen rozběhnout. Reaguje to na osvětlení(rozsvítí se dioda), zahřeji čidlo vzduchu, rozsvítí se dioda a sepne relé. Ale při ochlazení čidla vzduchu již přiřazená dioda nezhasne a ani relé pro ohřev se nevypne.
Můžete mi prosím poradit? Předem díky...

int led_vzduch = 5;
int led_svetlo = 3;
float predvolbavzduchu = 62;

float cidlo = A1;
float teplota;

int svetlo_cidlo = 8;
int svetlo;
int rele = 9;
int a;
int b;

void setup() {
  // put your setup code here, to run once:
  pinMode(led_vzduch, OUTPUT);
  pinMode(led_svetlo, OUTPUT);
  pinMode(svetlo_cidlo, INPUT);
  pinMode(cidlo, INPUT);
  pinMode(rele, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  teplota = analogRead(cidlo);
  svetlo = digitalRead(svetlo_cidlo);



  if (teplota >= predvolbavzduchu){
      digitalWrite(led_vzduch, HIGH);
      a = 1;
  }
  else if (teplota < predvolbavzduchu){
      digitalWrite(led_vzduch, LOW);
      a = 0;
  }

  if (svetlo == LOW){
      digitalWrite(led_svetlo, HIGH);
      b = 1;
  }
  else if (svetlo == HIGH){
      digitalWrite(led_svetlo, LOW);
      b = 0;
  }



  if ((a == 1) && (b == 1)){
      digitalWrite(rele, LOW);
      delay(180000);
  }
  else if ((a == 0) or (b == 0)){
      digitalWrite(rele, HIGH);
      delay(180000);
  }


}
 
Odpovědět
22. března 21:50
Avatar
DarkCoder
Člen
Avatar
Odpovídá na cinkim
DarkCoder:22. března 23:42

Tvé zpracování řídících příkazů if-else je dosti kostrbaté. Máš pouze dva stavy, větší nebo rovno mezní hodnotě a menší nežli mezní hodnota. Tedy žádné else if s testováním na druhou možnost.

Jednoduše:

if (vyraz_1) {
        // prikazy, kde vyraz_1 je pravdivy
}
else {
        // prikazy, kde vyraz_1 je nepravdivy
}

Testovat na rovnost není vhodné, pokud už to sám od sebe není výsledek nějakého testu.
Opět, jsou pouze dva stavy, dostatečná intenzita osvětlení a nedostatečná intenzita osvětlení.

Hrubý nástin funkčnosti programu pak může vypadat takto:
(Kód v jazyce C)

Stanovení si mezních hodnot, např.

#define MEZ_OSVETLENI 1000                      // 1000 lx
#define MEZ_TEPLOTY_VZDUCHU 30          // 30 °C
#define MEZ_TEPLOTY_VODY 20                     // 20 °C

A samotný kód:

stop = 0;
        do {
                // Ziskani dat ze sensoru
                namerena_intenzita_osvetleni = // zde data ze sensoru osvetleni
                namerena_teplota_vzduchu = // zde data ze sensoru teploty vzduchu
                namerena_teplota_vody = // zde data ze sensoru teploty vody

                // Vyhodnoceni jednotlivych sensoru
                osv = (namerena_intenzita_osvetleni >= MEZ_OSVETLENI) ? 1 : 0;
                vzd = (namerena_teplota_vzduchu >= MEZ_TEPLOTY_VZDUCHU) ? 1 : 0;
                vod = (namerena_teplota_vody >= MEZ_TEPLOTY_VODY) ? 1 : 0;

                // Celkove vyhodnoceni
                if (osv && vzd && vod) {
                        if (je_rele_vypnuto()) sepni_rele();
                }
                else {
                        if (je_rele_zapnuto()) vypni_rele();
                }

                stop = // indikace zavady
        } while (!stop);

Ternární operátor si pak uprav do podoby if-else z důvodu lepší čitelnosti, jelikož bloky budou obsahovat větší počet příkazů (vyhodnocení stavu sensoru, nastavení diod, apod).

Nahoru Odpovědět
22. března 23:42
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
cinkim
Člen
Avatar
Odpovídá na DarkCoder
cinkim:25. března 18:06

Díky moc, ale přiznám se, že jsem v koncích.
Měl jsem radost, že už mi to alespoň trochu bliká, ale tvůj kód mě naprosto zazdil. Vůbec nic z toho se nepodobá tomu, co jsem si přečetl do teď v návodech. Jsem totiž naprostý začátečník, který modul Arduino viděl poprvé na výstavě, kde blikaly dvě diody.
V návodu který jsem četl se psalo, že void loop() běží stále dokola. Z jakého důvodu mně tedy nezhasínaly diody? Nebo spíše proč si tam napsal ještě while cyklus?

Nejspíše budu muset někoho požádat, aby mě kód kompletně napsal napsal. Klidně i za úplatu.

 
Nahoru Odpovědět
25. března 18:06
Avatar
cinkim
Člen
Avatar
cinkim:25. března 19:34

Tak mě to nedalo a trochu jsem se v tom pošťoural. Upravil jsem si proměnné podle tvého kódu.

// pinů pro led diody
int led_vzduch = 5;
int led_svetlo = 3;
int led_voda = 1;
int led_rele = 2;

// piny pro vstupy a výstupy
int rele = 9;
float cidlo_vzduch = A1;
float cidlo_voda = A2;
int svetlo_cidlo = 8;

// proměnné pro načtení vstupů
float namerena_teplota_vzduchu;
float namerena_teplota_vody;
int namerena_intenzita_osvetleni;

// přednastavené hodnoty pro teploty
int MEZ_TEPLOTY_VZDUCHU = 70;
int MEZ_TEPLOTY_VODY = 90;

// proměnné pro vyhodnocené podmínky
int osv;
int vzd;
int vod;

void setup() {
  // put your setup code here, to run once:
  pinMode(led_vzduch, OUTPUT);
  pinMode(led_svetlo, OUTPUT);
  pinMode(led_voda, OUTPUT);
  pinMode(cidlo_vzduch, INPUT);
  pinMode(cidlo_voda, INPUT);
  pinMode(svetlo_cidlo, INPUT);
  pinMode(led_rele, OUTPUT);

}

void loop() {
 stop = 0;
        do {
                // Ziskani dat ze sensoru
                namerena_intenzita_osvetleni = digitalRead(svetlo_cidlo);
                namerena_teplota_vzduchu = analogRead(cidlo_vzduch);
                namerena_teplota_vody = analogRead(cidlo_voda);

                // Vyhodnoceni jednotlivych sensoru
                osv = (namerena_intenzita_osvetleni == HIGH) ? 1 : 0;
                vzd = (namerena_teplota_vzduchu >= MEZ_TEPLOTY_VZDUCHU) ? 1 : 0;
                vod = (namerena_teplota_vody >= MEZ_TEPLOTY_VODY) ? 1 : 0;

                // Celkove vyhodnoceni
                if (osv && vzd && vod) {
                        if (je_rele_vypnuto()) sepni_rele();
                }
                else {
                        if (je_rele_zapnuto()) vypni_rele();
                }

                stop = // indikace zavady
        } while (!stop);

}

píše to nějaké chybové hlášky:

itnetwork.ino: In function 'void loop()':
itnetwork.ino:40:2: error: 'stop' was not declared in this scope
itnetwork.ino:54:45: error: 'je_rele_vypnuto' was not declared in this scope
itnetwork.ino:54:59: error: 'sepni_rele' was not declared in this scope
itnetwork.ino:57:45: error: 'je_rele_zapnuto' was not declared in this scope
itnetwork.ino:57:59: error: 'vypni_rele' was not declared in this scope
itnetwork.ino:61:9: error: expected primary-expression before '}' token
itnetwork.ino:61:9: error: expected ';' before '}' token
Chyba kompilace.

Některé bych asi dokázal odstranit.
Třeba "je relé je vypnuto" atd. bych odstranil tím že bych napsal
if rele == LOW;
digitalWrite(rele, HIGH);

rozumím tomu dobře?

 
Nahoru Odpovědět
25. března 19:34
Avatar
DarkCoder
Člen
Avatar
Odpovídá na cinkim
DarkCoder:25. března 19:41

Přeci bys nechtěl přijít o ten pocit, že Ti kód funguje a to pouze jen a jen tvoji zásluhou. Je třeba se naučit nevzdávat se, když něco nejde nebo není podle představ. To hlavní je pochopit jak to má fungovat. Takže pojďme se na to podívat společně a uvidíš, že to žádná věda není.

Na kód, který jsem napsal, musíš koukat trochu jinak než na jeho vizuální podobu. Musíš z něj vyčíst princip a postup. Pak si ten postup poupravíš pro své potřeby pro jazyk který chceš pro ten daný úkol použít.

Základem je umět nabalovat jednotlivé bloky kódu do sebe. Celý proces se bude skládat z těchto částí:

  1. Získání dat ze senzorů
  2. Vyhodnocení senzorů a nastavení hodnot
  3. Celkové vyhodnocení a nastavení relé

No a to celé poběží v cyklu.

Podívej znovu na kód pohledem, jaký jsem popsal výše:

do {
        // Ziskani dat ze sensoru
        namerena_intenzita_osvetleni = // zde data ze sensoru osvetleni
        namerena_teplota_vzduchu = // zde data ze sensoru teploty vzduchu
        namerena_teplota_vody = // zde data ze sensoru teploty vody

        // Vyhodnoceni jednotlivych sensoru
        osv = (namerena_intenzita_osvetleni >= MEZ_OSVETLENI) ? 1 : 0;
        vzd = (namerena_teplota_vzduchu >= MEZ_TEPLOTY_VZDUCHU) ? 1 : 0;
        vod = (namerena_teplota_vody >= MEZ_TEPLOTY_VODY) ? 1 : 0;

        // Celkove vyhodnoceni
        if (osv && vzd && vod) {
                if (je_rele_vypnuto()) sepni_rele();
        }
        else {
                if (je_rele_zapnuto()) vypni_rele();
        }
} while (1);

Mluvil jsem o postupném nabalování dat. Postupně vše začneš přidávat. Začni cyklem a přidej do něj pouze jeden senzor.

Podívej na pseudokód:

začátek cyklu
        Ziskani dat ze sensoru osvetleni a ulozeni do promenne namerena_intenzita_osvetleni

        pokud plati: namerena_intenzita_osvetleni >= MEZ_OSVETLENI
                osv = 1
                rozsvit LED
        jinak
                osv = 0
                zhasni LES
        konec podmínky

        pokud plati: osv == 1
                pokud je_rele_vypnuto - sepni_rele
        jinak {
                pokud je_rele_zapnuto - vypni_rele
        konec podminky
konec cyklu

Pseudokód je napsán pouze pro jeden senzor, senzor osvětlení. Ale lze snadno stejným způsobem přidat další. Pokračovat v nabalování lze tehdy, až ti bude fungovat vše předtím.
Jakmile bude v okruhu více senzorů, bude celkové vyhodnocení dáno logickým součinem všech hodnot (osv && vzd && vod). Je na tobě, jaké mezní hodnoty si stanovíš. Hodnoty si musíš stanovit empiricky (vlastním testováním). Uvědom si, že testuje na dva stavy, tedy na to zda byla stanovaná mez dosažena nebo překročena a na to, zda stanovená mez ještě nebyla dosažena.

Všimni si podmínek uvnitř posledního řídícího příkazu. Mají své opodstatnění. Dávat pokyn o zapnutí zapnuté jednotce a obráceně dávat pokyn o vypnutí vypnuté jednotce, je neprofesionální.

Proto tvé vyhodnocení bude vypadat takto:

if (namerena_intenzita_osvetleni >= MEZ_OSVETLENI) {
        osv = 1
        zde prikaz pro rozsviceni LED
}
else {
        osv = 0
        zde prikaz pro zhasnuti LED
}

Nyní bys měl vědět, jak a čím začít. Samozřejmě je nutné znát syntax jazyka potřebného pro rozběhnutí kódu na Arduinu. Neboj se, uvidíš že to zvládneš.

Nahoru Odpovědět
25. března 19:41
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
DarkCoder
Člen
Avatar
Odpovídá na cinkim
DarkCoder:25. března 20:33

Je dobře, že jsi lépe pojmenoval použité proměnné v programu. Musíš uznat, že se pak v programu sám lépe vyznáš. Dále je dobré vědět, jakého typu nabývají hodnoty vrácené senzory. Z celočíselné hodnoty u senzoru osvětlení usuzuji, že vrací pouze stav menší než spínaná hodnota a stav větší nebo rovno než spínaná hodnota. Je dobrým zvykem udržovat hodnoty stejného typu při porovnání. Pokud tedy víš že senzor vzduchu a vody vrací desetinnou hodnotu, je dobré stanovit typ pro meze těchto senzorů také jako desetinný. Fungovat to bude i bez toho, jen někteří programátoři netuší, co se tam vlastně děje. Že dochází k přetypování typu a pokud na to nejsou zvyklí, pak se mohou dopouštět chyb aniž by o tom věděli. Ale to už trochu odbočuji. Takže uprav typy pro meze u senzoru vody a vzduchu na float a správně inicializuj hodnotu. Až budeš zkoušet vše, stanov si dostupnější hodnoty, pokud to ovšem nezkoušíš na rychlovarné konvici. :-D

Pokud nabývá senzor osvětlení skutečně pouze dvou stavů (LOW při nedostatku osvětlení a HIGH při dostatečném a vyšším osvětlení) pak příkaz:

osv = (namerena_intenzita_osvetleni == HIGH) ? 1 : 0;

je v pořádku. Zde je naprosto správné testovat pouze na rovnost.

void loop() nepředstavuje cyklus ale funkci která se jmenuje loop() a nevrací parametry.

Vše co se týká sekce se stop vymaž. Je to část, kterou aktuálně nemáš implementovanou a je tedy v aktuálním stavu tvého programu nadbytečná.

Můžeš také smazat vnitřní podmínky v Celkovém hodnocení. Takto by se chovaly jako funkce které nemáš implementované. Smyslem bylo ukázat co se má dělat. Na funkci vracející stav relé se musíš podívat do manuálu. Hledej podobnost v následujícím úryvku kódu. Jméno funkce pro stav relé je vymyšlené, nahraď skutečným.

if (osv && vzd && vod) {
        if (stav_rele() == 0) sepni_rele();     // if (!stav_rele()) sepni_rele();
}
else {
        if (stav_rele() == 1) vypni_rele();     // if (stav_rele()) vypni_rele();
}
Nahoru Odpovědět
25. března 20:33
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
cinkim
Člen
Avatar
cinkim:25. března 21:07

Díky, hodně mně to pomohlo. Světelný senzor vrací zapnuto/vypnuto intenzitu nastavím trimrem přímo na něm. To už mám vyzkoušený. Čidla vody mám v kodu jako float. Na výstupu z čidla to dělá asi 10mV/1stupeň celsia.
Dopsal jsem do kodu podmínky a odmazal ty Stopky.
Můžeš na to kouknout? Stále to píše nějaké chyby. Středníky mám všude a ty kudrnatý závorky...naprosto nevím jestli jsou všude a na správném místě.

void loop() {
    do {
            // Ziskani dat ze sensoru
            namerena_intenzita_osvetleni = digitalRead(svetlo_cidlo);
            namerena_teplota_vzduchu = analogRead(cidlo_vzduch);
            namerena_teplota_vody = analogRead(cidlo_voda);

            // Vyhodnoceni jednotlivych sensoru
            osv = (namerena_intenzita_osvetleni == HIGH) ? 1 : 0;
            vzd = (namerena_teplota_vzduchu >= MEZ_TEPLOTY_VZDUCHU) ? 1 : 0;
            vod = (namerena_teplota_vody >= MEZ_TEPLOTY_VODY) ? 1 : 0;

            // Celkove vyhodnoceni
            if (osv && vzd && vod) {
                    if ((rele == LOW) && (led_rele == LOW));
                        digitalWrite(rele, HIGH);
                        digitalWrite(led_rele, HIGH);
            }
            else {
                    if ((rele == HIGH) && (led_rele == LOW));
                        digitalWrite(rele, LOW);
                        digitalWrite(led_rele, LOW);
            }
    } while

}

chybové hlášky:

itnetwork.ino: In function 'void loop()':
itnetwork.ino:64:1: error: expected '(' before '}' token
itnetwork.ino:64:1: error: expected primary-expression before '}' token
itnetwork.ino:64:1: error: expected ')' before '}' token
itnetwork.ino:64:1: error: expected ';' before '}' token
Chyba kompilace.

 
Nahoru Odpovědět
25. března 21:07
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
cinkim
Člen
Avatar
cinkim:25. března 21:09

Ještě mě napadlo:
nemělo by být
if (osv && vzd && vod) == 1;

 
Nahoru Odpovědět
25. března 21:09
Avatar
DarkCoder
Člen
Avatar
Odpovídá na cinkim
DarkCoder:25. března 21:10

Pokud žádná funkce o vrácení stavu relé neexistuje, můžeš si ji nasimulovat inicializací Boolovské proměnné vyjadřující stavy V CHODU (1) a STOP (0). Pak postačí v řídícím cyklu celkového hodnocení testovat tuto proměnnou na konkrétní hodnotu a upravit stav:

// deklarace a inicializace promenne pro stav rele
int stav_rele = 0;      // vypnute rele

// Celkove hodnoceni
if (osv && vzd && vod) {
        if (!stav_rele){
                digitalWrite(rele, HIGH);
                // zde rozsviceni LED
                stav_rele = 1;
        }
}
else {
        if (stav_rele){
                digitalWrite(rele, LOW);
                // zde zhasnuti LED
                stav_rele = 0;
        }
}

Stav relé si můžeš indikovat rozsvícením nebo zhasnutím LED, tak jak to zamýšlíš, viz komentáře v úryvku kódu.

Nahoru Odpovědět
25. března 21:10
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
DarkCoder
Člen
Avatar
Odpovídá na cinkim
DarkCoder:25. března 21:26

Pokud funkce loop() opravdu provádí kód vy cyklu, pak je příkaz příkaz cyklu do-while nadbytečný a nesmyslný.

Smaž oba následující řádky:
do {

} while

Zde je navíc i chyba, za while Ti chybí výraz pro ukončení resp. pro pokračování cyklu. To je pro info.

Dále příkazy uvnitř podmínek v celkovém hodnocení musí být v bloku, tyto příkazy tvoří jednu jednotku a musí být pospolu. Takto jak to máš by se provedl pouze příkaz ihned za if nebo else. Podívej do mého příspěvku výše na kód sekce celkového hodnocení.

if (osv && vzd && vod) == 1;

Být nemusí, ale není to chyba. V profi psaných programech takovýto zápis neuvidíš, pokud ovšem není smyslem zdůraznit danou hodnotu. Což může být i tento případ. Dáváš tím jasně najevo že testuješ na TRUE.

Pro info:

if(vyraz) je totez co if(vyraz == 1)     // plati pro testovani boolovskych hodnot

a

if(!vyraz) je totez co if(vyraz == 0)     // plati pro testovani boolovskych hodnot

Pokud testuješ jiné než boolovské hodnoty, pak samozřejmě musíš uvádět variantu s rovností.

Nahoru Odpovědět
25. března 21:26
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
cinkim
Člen
Avatar
cinkim:25. března 21:46

Díky, zkompilováno bez chyby. Teď tam ještě musím dopsat podmínky na rozsvícení zelených led diod pro případ že bude dostatečné světlo, dostatečná teplota vzduchu a studená voda.
A pak vyzkoušet... :-)

 
Nahoru Odpovědět
25. března 21:46
Avatar
DarkCoder
Člen
Avatar
Odpovídá na cinkim
DarkCoder:25. března 21:49

Jinač následující řádky jsou chybné:

if ((rele == LOW) && (led_rele == LOW));

a

if ((rele == HIGH) && (led_rele == HIGH));

a to hned ve čtyř bodech:

  1. oba stavy pro rele a led_rele nastávají současně a tudíž je zbytečné testovat jejich hodnotu pomocí logického součinu. Stačí test jednoho výrazu, ideálně toho pro relé.
  2. Všechny příkazy, které se mají provést v rámci splněné podmínky musí být v bloku. Viz. můj předchozí příspěvek.
  3. Středník na konci je chybný. To co tvůj kód vytváří je prázdný příkaz. Takovéto chyby mohou být obtížně dohledatelné. Je to proto, že tento způsob zápisu je platný ale musíš vědět kdy ho použít. Zde vytvoření prázdného příkazu nemá žádný význam, proto je zápis se středníkem na konci chybný.
  4. V části else nelze mít hodnotu pro relé HIGH a led_rele LOW.

Uprav sekci celkového hodnoceni na:

// Celkove vyhodnoceni
if (osv && vzd && vod) {
        if (rele == LOW){
                digitalWrite(rele, HIGH);
                digitalWrite(led_rele, HIGH);
        }
}
else {
        if (rele == HIGH){
               digitalWrite(rele, LOW);
               digitalWrite(led_rele, LOW);
        }
}
Editováno 25. března 21:52
Nahoru Odpovědět
25. března 21:49
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
DarkCoder
Člen
Avatar
Odpovídá na cinkim
DarkCoder:25. března 22:15

Prima! Doporučuji to nevkládat do ternárních výrazů, ale přepsat to do podoby if-else. Důvodem je lepší čitelnost v kódu. Pěkně si to rozepsat tak jako u celkového hodnocení, nesplést se, při kterém stavu která LED svítí a při testování se neopařit. :-)

Nahoru Odpovědět
25. března 22:15
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 13 zpráv z 13.