Ovládání krbových kamen podle teploty

Nedaří se vám s projektem a nenašli jste vhodné místo, kde se zeptat? Napište sem.
Pravidla fóra
Tohle subfórum je určeno pro konzultaci ucelených nápadů, popřípadě řešení komplexnějších projektů, které opravdu není možné rozdělit na menší části.
Většinu problémů jde rozdělit na menší a ptát se na ně v konkrétních subfórech.
Odpovědět
Georgio
Příspěvky: 5
Registrován: 22 úno 2021, 16:52
Reputation: 0

Ovládání krbových kamen podle teploty

Příspěvek od Georgio » 22 úno 2021, 17:22

Zdravím,
chtěl bych si nechat zkontrolovat program.
Před třemi měsíci mě napadlo ovládat výkon krbových kamen. Servo bude hýbat kruhovým přívodem kamen přímo na dvířkách. Je to dost krkolomný, ale že je to důvod seznámit se s Arduinem.
Takže kromě Arduina tam mám servo, dvě led (Jedna rgb, která signalizuje teplotu. Chtěl jsem PWM, ale nevím proč mi to nefungovalo. Teď to mám rozdělený každou barvu pro 100C a čím více svítí a míň času nesvítí. druhá signalizuje podprogram 1-3.) Ještě jedno tlačítko, bzučák (upozorní na klesající teplotu) a světelný senzor, který bude koukat do kamen. Aby rgb při 100C svítila kontinuálně jsem skoro všechno předělal do millis. Nechal jsem delay na bzučáku a jedeno malí na konci loop. Nikde jsem se nedozvěděl, jestli se to nemůže zavařit, když by to jelo na 100%.
Díky za připomínky. V provozu jsem to ještě nezkoušel, takže hodnoty jsou jen asi.

Kód: Vybrat vše

/*pripojeni serva / žlutá je řídící, červená je plus a hnědá mínus*/
// knihovna - arduino IDE
#include <Servo.h>

// Termočlánek + driver MAX6675
//knihovna z adresy - https://navody.dratek.cz/docs/texty/0/13/max6675_termoclanek.zip
#include <max6675.h>

// nastavení propojovacích pinů
int pinSO  = 3;
int pinCS  = 4;
int pinSCK = 5;
// vytvoření instance termoclanek z knihovny MAX6675
MAX6675 termoclanek(pinSCK, pinCS, pinSO);

int led = 8; //pin s LED diodou
int ledrgb[] = {11, 10, 9}; //pin s LED diodou RGB

int buzz = 12; // bzucak
int tlacitko = 13;

Servo sv;
int h1; //hodnoty mereni teploty nastaví polohu serva
int val = 999; //stará hodnota h1

int teplo = 300; //pouze prozetimní hodnota
int zima = 300; //pouze prozetimní hodnota

//proměnné millis
unsigned long cas = 0;
unsigned long casTeplomer = 0;
unsigned long casTlacitka = 0;
unsigned long vypnutiSvetla = 0;
unsigned long aktualniCas = 0;
unsigned long drivYellow = 0;
unsigned long drivRGB = 0;
unsigned long casServa = 0;

//Světelný senzor
byte pot = A0;

int tlac = 0; //promenna tlacitka (ano/ne)
int cteni = 1; //hodnota počítání stlačení tlačítka

int i;
int teplota = 25; //teplota bez desetiného místa

int intervalCteni = 100; //informační led / 1-3. program ( v programu nastavení serva (klapky))
int yellow = 0;

//Blikání rgb podle teploty
int stav = LOW;
int x; //proměnná rgb
int interval; //časová proměnná pro RGB
int svetlo; //změna hodnoty interval
int tma; //změna hodnoty interval

void setup() {
  pinMode(led, OUTPUT);
  pinMode(ledrgb[0], OUTPUT);
  pinMode(ledrgb[1], OUTPUT);
  pinMode(ledrgb[2], OUTPUT);
  pinMode(buzz, OUTPUT);
  pinMode(tlacitko, INPUT);
  sv.attach(6);
  Serial.begin(9600);
}

void checkSvetla() {
  //Nastavení barvy led podle teploty a změna intervalu (světlo, tma)
  if ((unsigned long) aktualniCas - drivRGB >= interval) {
    drivRGB = aktualniCas;
    if ((teplota >= 0) && (teplota < 100)) {
      x = 0;
      svetlo = (teplota * 10);
      tma = (1000 - (teplota * 10));
    }
    else if ((teplota >= 100) && (teplota < 200)) {
      x = 2;
      svetlo = ((teplota - 99) * 10);
      tma = (1000 - (teplota - 99) * 10);
    }
    else if ((teplota >= 200) && (teplota < 300)) {
      x = 1;
      svetlo = ((teplota - 199) * 10);
      tma = (1000 - (teplota - 199) * 10);
    }

    if (stav == LOW) {
      stav = HIGH;
      interval = svetlo;
      digitalWrite(ledrgb[x], HIGH);
    } else {
      stav = LOW;
      interval = tma;
      for (i = 0; i < 3; i++) {
        digitalWrite(ledrgb[i], LOW);
      }
    }
  }

  ////informační led / 1-3. program (cteni=číslo programu)

  if (cteni == 1) {
    if ((unsigned long) aktualniCas - drivYellow >= intervalCteni) {
      drivYellow = aktualniCas;
      if  ((intervalCteni == 1200) || (intervalCteni == 300)) {

        //intervalCteni=jak dlouho svítí
        digitalWrite(led, HIGH);
        intervalCteni = 100;
      }
      else {
        //intervalCteni=jak dlouho nesvítí
        digitalWrite(led, LOW);
        intervalCteni = 1200;
      }
    }
  }
  else if (cteni == 2) {


    if ((unsigned long) aktualniCas - drivYellow >= intervalCteni) {
      drivYellow = aktualniCas;

      yellow++;

      if  ((intervalCteni == 300) || (intervalCteni == 1200)) {
        digitalWrite(led, HIGH);
        intervalCteni = 100;
      }
      else {
        digitalWrite(led, LOW);
        intervalCteni = 300;
      }
      if (yellow == 4) {
        intervalCteni = 1200;
        yellow = 0;


      }
    }
  }
  else if (cteni == 3) {


    if ((unsigned long) aktualniCas - drivYellow >= intervalCteni) {
      drivYellow = aktualniCas;

      yellow++;
      if  ((intervalCteni == 300) || (intervalCteni == 1200)) {
        digitalWrite(led, HIGH);
        intervalCteni = 100;
      }
      else {
        digitalWrite(led, LOW);
        intervalCteni = 300;
      }
      if (yellow == 6) {
        intervalCteni = 1200;
        yellow = 0;


      }

    }
  }
}


void loop() {
  aktualniCas = millis();

  //Vypnutí led. Čas běží od posledního tlačítka. IF se svítí. ELSE se led vypnou.
  if (tlac == 1) {
    vypnutiSvetla = aktualniCas;
  }
  if ((unsigned long) (aktualniCas - vypnutiSvetla) <= 300000) { //minuta je 60 000
    checkSvetla();
  }
  else {
    for (i = 0; i < 3; i++) {
      digitalWrite(ledrgb[i], LOW);
    }
    digitalWrite(led, LOW);
  }
  //////////////////


  //Měření teploty
  if ((unsigned long) (aktualniCas - casTeplomer) >=  10000) { //minuta je 60 000
    casTeplomer = aktualniCas;
    // načtení aktuální teploty termočlánku
    // do proměnné teplotaC
    float teplotaC = termoclanek.readCelsius();
    Serial.print("Teplota je: ");
    Serial.println(teplotaC);
    teplota = abs(teplotaC);


  }

  //Read tlačítka. Interval 1,2s.
  if ((unsigned long) (aktualniCas - casTlacitka) >=  1200) { //minuta je 60 000

    if (digitalRead(tlacitko) == HIGH) {
      tlac = 1;
      intervalCteni = 300;
      yellow = 0;
      casTlacitka = aktualniCas;
    }
    else {
      tlac = 0;
    }

  }
  else {
    tlac = 0;
  }

  ///////
  ///////Pokud jsou vzpnuty led, tak high. Pokud high, tak se zvýší číslo programu serva /switch/.
  if (aktualniCas >= vypnutiSvetla + 300000) { //minuta je 60 000
    cteni = cteni;
  }
  else {
    cteni = cteni + tlac;
  }

  if (cteni == 4) {
    cteni = 1;
  }


  switch (cteni) {
    case 1:
      //pokud je hodnota promenne 1, Roztápěcí režim
      if ((unsigned long) (aktualniCas - casServa) >= 60000) { //minuta je 60 000
        casServa = aktualniCas;
        h1 = constrain(teplota, 0, 200);
        h1 = map(h1, 0, 200, 0, 90);
        //Pokud rozdíl poslední polohy větší než 5, změna se neprovede.
        if ((unsigned int)(h1 - val) > 4) {
          sv.write(h1);
          val = h1;
        }
        Serial.print("-switch1,");
        Serial.print(val);
        Serial.print("/");
        Serial.println(h1);
      }
      break; //po provedeni teto casti konstrukce switch konci


    case 2:
      //pokud je hodnota promenne 2, standard topení
      if ((unsigned long) (aktualniCas - casServa) >= 60000) { //minuta je 60 000
        casServa = aktualniCas;
        h1 = constrain(teplota, 0, 160);
        h1 = map(h1, 0, 160, 0, 90);
        //Pokud rozdíl poslední polohy větší než 5, změna se neprovede.
        if ((unsigned int)(h1 - val) > 4) {
          sv.write(h1);
          val = h1;
        }
        Serial.print("-switch2,");
        Serial.print(val);
        Serial.print("/");
        Serial.println(h1);
      }
      break;


    case 3:
      //pokud je hodnota promenne 3, Noční program
      if ((unsigned long) (aktualniCas - casServa) >= 60000) { //minuta je 60 000
        casServa = aktualniCas;


        //      POKUD SVETLO NESVITI
        if (analogRead(pot) <= 100) {
          h1 = constrain(teplota, 0, 130);
          h1 = map(h1, 0, 130, 0, 90);
          //Pokud rozdíl poslední polohy větší než 5, změna se neprovede.
          if ((unsigned int)(h1 - val) > 4) {
            sv.write(h1);
            val = h1;
          }
        }
        //      POKUD SVITI
        else {
          h1 = constrain(teplota, 0, 130);
          h1 = map(h1, 0, 130, 20, 90);
          if ((unsigned int)(h1 - val) > 4) {
            sv.write(h1);
            val = h1;
          }
        }
        Serial.print("svetlo,");
        Serial.print(analogRead(pot));
        Serial.print("-switch3,");
        Serial.print(val);
        Serial.print("/");
        Serial.println(h1);
      }
      break;
  }



  teplo = zima;
  if ((unsigned long) (aktualniCas - cas) >= 300000) { //minuta je 60 000
    cas = aktualniCas;
    float teplotaC = termoclanek.readCelsius();
    zima = teplotaC;
    Serial.print("-bzucak-");
    Serial.print(zima);


    if ((teplo < 100) && (zima < teplo)) {
      Serial.print("-PíííP-");
      for (i = 0; i < 5; i++) {
        digitalWrite(buzz, HIGH);
        delay(200);
        digitalWrite(buzz, LOW);
        delay(300);
      }
      digitalWrite(buzz, HIGH);
      delay (100);
      digitalWrite(buzz, LOW);
      delay (588);
      digitalWrite(buzz, HIGH);
      delay (100);
      digitalWrite(buzz, LOW);
      delay (588);
      digitalWrite(buzz, HIGH);
      delay (688);
      digitalWrite(buzz, LOW);
      delay (8);
    }


  }
  delay (4);
}

Georgio
Příspěvky: 5
Registrován: 22 úno 2021, 16:52
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od Georgio » 11 dub 2021, 21:43

Zdravím, čekal jsem, že po tak dlouhé době nějaká reakce bude. Program jsem ještě trochu předělal, ale asi to nemá cenu to sem dávat. Nějaké nové postřehy: to PWM mi nejelo asi kvůli tomu, že knihovna serva vypíná PWM na některých pinech. Ještě řeším problém (dá se s tím ale žít). Pokud zapnu Arduino a servo nedostane žádný příkaz, tak se samo rozjede do nějaké střední pozice. Myslel jsem, že by šlo použít příkaz "servo.read()", tak ho pošlu na pozici kterou jsem "servo.read()" přečetl. Nebo je možné, že je to typem serva? Také jsem myslel, že můžu servo vypnout, manuálně s ním pohnout a když ho zapnu, načtu polohu a po jednom stupni pootočím.

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od ondraN » 12 dub 2021, 11:20

Nevím, jak si prakticky představuješ kontrolu programu. Buď ti funguje, nebo nějak nefunguje a pak tady můžeme řešit, kde je chyba. Jestli myslíš, že jakkoli zkušený programátor se mrkne na kód a hned ví, kde je chyba nebo jestli je OK, tak jsi na omylu. Číst a analyzovat cizí kód je docela náročné a zdlouhavé a nikdo to nedělá jen tak ze zábavy.
Pokud používáš modelářské serva, tak ty nemají žádnou možnost jak zjistit polohu. Do serva se pouští řídící pulzy a podle jejich šířky se servo natočí. Zpětná vazba je uvnitř serva, ale z vnějšku nedosažitelná. Funkce na zjištění polohy serva, se jenom podívá, jak široký impuls arduino generuje a jaká tomu odpovídá poloha. Ale pokud je třeba servo vypnuté nebo vadné, to nezjistí. Když potřebuješ zjistit skutečnou polohu, musíš si zapojit nějaký snímač (třeba potenciometrický) a polohu si sám změřit a vyhodnotit. Pro tento typ pohonů se často používá krokový motor a snímač dorazu jedné polohy. Pak si vždy na začátku motor dokrokuješ do polohy dorazu, až ti sepne spínač a od této polohy si počítáš už jen kroky. Kalibrace se může dělat po resetu nebo třeba po nějakém čase, když je to nutné.

Georgio
Příspěvky: 5
Registrován: 22 úno 2021, 16:52
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od Georgio » 12 dub 2021, 20:40

Asi jsem byl trochu najivní. Myslel jsem, že se někdo najde.
Ještě k vytíženosti arduina na 100%. Může to být problém, nebo jsou na to ty čipy stavěný? Pokud mi nevadí krátké dalay, mám ho tam raději dát?

Uživatelský avatar
Caster
Příspěvky: 380
Registrován: 11 zář 2019, 09:02
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od Caster » 12 dub 2021, 21:57

Nikde nepíšeš, v čem máš konkrétně problém. Souhlasím s ondraN , že zde pak bude těžko někdo zkoumat tvůj program.

Pokud ti program nefunguje, jak očekáváš, je dobré odladit hlavní části programu samostatně a tím problém odstranit. Jak víš, že ti procesor běží na 100% ?

Georgio
Příspěvky: 5
Registrován: 22 úno 2021, 16:52
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od Georgio » 12 dub 2021, 22:54

Program už neřešte. Už jsem to pochopil. To čtení polohy serva mě mrzí, ale celkově mi ten projekt funguje dobře. Takže vše je OK.
K vytíženosti procesoru. Představuji si to tak, že procesor běží programem, kontroluje millis (jestli nemá něco udělat). A čím výkonější by byl, tím rychleji by běhal. Není tomu tak? Nebo to nemá s vytížeností nic společného? Pokud bude muset více počítat než koukat na hodinky, spomalí ho to v koukání na hodinky?
Asi je to naivní, ale tak nějak si to představuji.

Uživatelský avatar
Caster
Příspěvky: 380
Registrován: 11 zář 2019, 09:02
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od Caster » 12 dub 2021, 23:30

Představa je sice pěkná, ale takhle to nefunguje ;) . Je celkem jedno, jednou rychlostí procesor běží, když kontroluješ čas. Procesor stejně nic nedělá, mimo inkrementování proměnné času a zpracování případných přerušení.

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od ondraN » 13 dub 2021, 07:17

Na to je jedna hezká programátorská hláška. "Všechny počítače provádějí delay() tou samou rychlostí."
Spíš jde o to, že při použití funkce delay() MCU jen čeká, než uplyne definovaný čas. A přitom by mohl dělat klidně něco jiného. Ne vždy je delay() špatné řešení a je bytečně démonizovaný. Pokud je situace taková, že pokud k neuběhne nějaký čas, tak nesmím udělat další krok a ani nepotřebuji dělat nic jiného, tak tam ji bez víčitek použiji. Pokud musím neustále kontrolovat příchod dat ze sériové linky, blikat diodou, krokovat motor, číst jeho polohu ze snímače, kontrolovat stisk klávesy atd. tak pro zobrazení výzvy na displeji, která tam má být 3sec a pak zmizet, nemůžu delay použít, protože se mi tím zastaví vše další na ty 3sekundy.
Takže, procesor běží stále stejně rychle, ale buď může trávit všechen svuj čas neustálým kroužením ve smyčce čekání, nebo může vykonávat spoustu dalších věcí. To je dané architekturou programu a tu vymýšlíme my.

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

Re: Ovládání krbových kamen podle teploty

Příspěvek od gilhad » 13 dub 2021, 10:35

V normalnim rezimu arduino udela svojich 16M instrukci za sekundu at dela, co dela a sezere na to asi tak stejne energie (cili zurive vypocty stoji stejne jako delay). Dalsi energii sezere na napajeni pinu (podle jejich zateze).
Rozhodne se v delay nezastavi a neceka, naopak tam cykluje a "pocita" jako vzdycky. Cili neusetri energii, neohladise, neosoupe si mit ta kolecka uvnitr. Pri dodrzeni zateze pinu proste jede naplno i v tom delay i kdekoli jinde a je na to staveny aby to vydrzel delat furt.
Ma pak zvlastni - spankove - rezimy, kde spoustu veci odpoji a nedela skoro nic a zere min, ale to s delay nesouvisi.

Rozhodne to neni jako u "velkych pocitacu", ktere pri pareni gamesy zacnou topit a pri obycejnem ukazovani desktopu a cekani, jestli uzivatel pohne mysi zase chladnou. Tak vychytrale to arduino proste neni.

Georgio
Příspěvky: 5
Registrován: 22 úno 2021, 16:52
Reputation: 0

Re: Ovládání krbových kamen podle teploty

Příspěvek od Georgio » 14 dub 2021, 22:27

Děkuji za opovědi. :)

Odpovědět

Kdo je online

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