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


DarkCoder:22.3.2020 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).
cinkim:25.3.2020 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.
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?
DarkCoder:25.3.2020 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í:
- Získání dat ze senzorů
- Vyhodnocení senzorů a nastavení hodnot
- 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š.
DarkCoder:25.3.2020 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.
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();
}
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.
DarkCoder:25.3.2020 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.
DarkCoder:25.3.2020 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í.
DarkCoder:25.3.2020 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:
- 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é.
- 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.
- 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ý.
- 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);
}
}
DarkCoder:25.3.2020 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.
Zobrazeno 13 zpráv z 13.