Začátečník arduino - pomoct s tlačítky - bazén (přesunuto)

Raspberry, Arduino, Mini-PC a další

Moderátor: Moderátoři

Zpráva
Autor
Uživatelský avatar
Rellik
Příspěvky: 610
Registrován: 17 úno 2017, 01:00
Bydliště: Staré Město (UH)

Začátečník arduino - pomoct s tlačítky - bazén (přesunuto)

#1 Příspěvek od Rellik »

Zdravím vespolek. Mám v ruce své první arduino a chtěl bych si naprogramovat jednoduché hlídání bazénu viz můj dotaz v poradně ( http://www.ebastlirna.cz/modules.php?na ... ic&t=82896 ).
No i když běžně občas programuju v PHP, a myslel jsem že to nebude o moc jiné opak je pravdou.
V tom případě začínám víceméně od začátku.
Má představa programu je následující:

Stále pojede program, který dle času 2x za 24 hodin zapne postupně 2 relé. (RTC obvod je na cestě). Mezitím dle dvou teplotních čidel sepne podle nastavení další relé (nemusí spustit).
Přitom v podstatě kdykoliv mimo ty časové úseky bych chtěl v jednom případě sepnout opět ty "časové" relé ručně - jedno tlačítko(stejná doba sepnutí obou - nastavené ve funkci).
Sepnout jen jedno z těch dvou relé - druhé tlačítko.

No zatím zápasím s "blikající diodou" (hlavní program) a dvěma tlačítky (podprogramy). Hlavní program "blikání" funguje. Po stisku tlačítka ovšem další dvě diody zůstanou svítit i po puštění. To by bylo dobré, ale po dalším zmáčknutí bych chtěl aby zhasnuly. Poradí někdo jak upravit následující kód, případně řekne jestli na to jdu špatně a jak na to jít jinak?
Díky.

Kód: Vybrat vše

int G = A0; // 3x LED
int Y = A1;
int B = A2;
int zelena;
int modra;
int Tl1 = 0; // tlačítka
int Tl2 = 1;

void setup() {
    pinMode(G,OUTPUT);
    pinMode(Y,OUTPUT);
    pinMode(B,OUTPUT);
    pinMode(Tl1,INPUT_PULLUP);
    pinMode(Tl2,INPUT_PULLUP);
}

void loop() {
  zelena = digitalRead(Tl1);
  modra = digitalRead(Tl2);
  // pokud se zmáčkne Tl bude svítit modrá, pokud se pustí zhasne
  if(modra == LOW) {
          digitalWrite(B, HIGH);
          }
  // to samé jako předchozí ale jiné Tl a LED
  if(zelena == LOW) {
          digitalWrite(G, HIGH);
          }

 // hlavní program, který pojede stále 
HlavniProg(); 


}

void HlavniProg() {
    digitalWrite(Y, HIGH);
    delay(200);
    digitalWrite(Y, LOW);
    delay(200);
}
Naposledy upravil(a) Rellik dne 16 pro 2017, 08:33, celkem upraveno 1 x.

Uživatelský avatar
dreamer
Příspěvky: 380
Registrován: 22 říj 2014, 02:00

#2 Příspěvek od dreamer »

Stačí použít "else". Hezky je to popsané tady třeba:

https://programmingelectronics.com/tuto ... onditions/

Uživatelský avatar
FHonza
Příspěvky: 1443
Registrován: 20 lis 2012, 01:00
Bydliště: Praha

#3 Příspěvek od FHonza »

Kód: Vybrat vše

if(modra == LOW) { 
          digitalWrite(B, HIGH); 
          }
else
 {
    digitalWrite(B, LOW); 
  }
Každopádně bude chtít ošetřit debouncing tlačítek.

Uživatelský avatar
Rellik
Příspěvky: 610
Registrován: 17 úno 2017, 01:00
Bydliště: Staré Město (UH)

#4 Příspěvek od Rellik »

Díky vyzkouším... Zákmity tlačítek jsem včera měřil na osciloskopu (jsou celkem šílené... :) ). Mělo by stačit přidat delay po prvním kontaktu (než se Tl pustí)...

EDIT:
tak po přidání else se projeví že ty další diody svítí jen po dobu držení tlačítka. Asi by to nějak chtělo uložit stav tlačítka po zmáčknutí a ten pak dalším stlačením negovat.
Naposledy upravil(a) Rellik dne 06 pro 2017, 18:03, celkem upraveno 1 x.

Uživatelský avatar
FHonza
Příspěvky: 1443
Registrován: 20 lis 2012, 01:00
Bydliště: Praha

#5 Příspěvek od FHonza »

Sem to asi špatně pochopil. Na první zmáčknutí rozsvítit, na druhý zhasnout ?

Edit: doporučuju se vyhnout delay(), to je tak nějak cesta směrem k peklu. Lepší je použít millis()

Uživatelský avatar
Rellik
Příspěvky: 610
Registrován: 17 úno 2017, 01:00
Bydliště: Staré Město (UH)

#6 Příspěvek od Rellik »

Jo první klik rozsvítí, druhý zhasne...
Jo ten millis() jsem už někde našel...
Nicméně je zajímavé, že pokud přidám jen to "else" a nechám udělat výpis na monitor, tak každé tlačítko má jiný stav i když se nic nemačkalo (po resetu)...
EDIT: chyba byla si ve zvolených pinech pro tlačítka. (0, 1) když jsem je posunul na pin2 a 3, tak to jde. Myslím na jedno zmáčknutí - pokud se drží - svítí...
Přílohy
Screenshot_20171206_175304.png
(117.29 KiB) Staženo 248 x

Uživatelský avatar
dreamer
Příspěvky: 380
Registrován: 22 říj 2014, 02:00

#7 Příspěvek od dreamer »

Pro testování je funkce mills() použitelná, jenom je třeba mít na paměti že po 49,7 dnů dojde k přetečení a začne počítat od 0. V celku elegantně to řeší knihovna "interval" která je vysvětlena a ke stažení na:
http://www.xpablo.cz/?p=421

Uživatelský avatar
Rellik
Příspěvky: 610
Registrován: 17 úno 2017, 01:00
Bydliště: Staré Město (UH)

#8 Příspěvek od Rellik »

Dreamer:
Ty relé pak budou řízeny RTC časem, takže v podstatě ani delay ani millis nebude třeba. Max pro to hlídání prokliků na tlačítku. A jestli bude po cca 50 dnech počítat znovu od nuly je úplně jedno...

Nastíním celý program ( květen až září - jinak PWR-OFF).:
Hlavní program:
časování dvou relé brzo ráno a pozdě večer. Jedno relé sepne na cca 1 hodinu. druhé cca 20s po prvním na cca 40sekund. (filtrace a dávka chloru).Přes den hlídání dvou teplot - if(temp1 >=45 && temp2 <=24) sepne další relé (teplota soláru a teplota bazénu).

podprogramy na Tl:
Při tomto běhu programu chci dvě ovládací tlačítka, přičemž jedno bude simulovat funkci těch dvou relé (stejná funkce jen manuální - víceméně mimo ty dva automatické časy) - tady stačí jednočinné zmáčknutí - po uplynutí nastavené doby přejde opět do automatu (dávka chloru navíc).
Druhé tlačítko sepne jen jedno z těch dvou relé (s tím delším časem opět mimo nastavené časy automatu). U tohoto tlačítka je potřeba i ručního vypnutí buď stejným nebo klidně i jiným tlačítkem (vysávání).

No vlastně bude potřeba asi 3 ty tlačítka. Jedno by mělo vypnout tu "teplotní funkci pokud bude v činnosti ( pro případ vysávání pokud pojede ohřev vody).
Snad to do jara nějak splácám... :)

EDIT: zatím mi ty Tl fungují asi tak: odkaz.

Uživatelský avatar
dreamer
Příspěvky: 380
Registrován: 22 říj 2014, 02:00

#9 Příspěvek od dreamer »

To znám, taky to tak dělám :-) jenom je potřeba mít na paměti že konstrukce na nepájivém poli nejsou moc spolehlivé. Takže až něco přestane najednou fungovat nebo bude fungovat jinak než bylo zamýšleno, může být problém někde tam. U takhle jednoduchých programů řeším zákmity tlačítek pomocí "delay" 200ms. Prostě když je detekováno stisknutí tlačítka, dám 200ms pauzu pak teprve program pokračuje. Vím že to není nejčistější ale pokud to nevadí jinde tak je to nejjednoduší řešení.

Uživatelský avatar
FHonza
Příspěvky: 1443
Registrován: 20 lis 2012, 01:00
Bydliště: Praha

#10 Příspěvek od FHonza »

200ms už je hodně, neznalá obsluha si bude myslet že se nic neděje a tlačítko zmáčkne znovu.

Uživatelský avatar
fero_b
Příspěvky: 582
Registrován: 17 kvě 2004, 02:00
Bydliště: Kosice

#11 Příspěvek od fero_b »

Zabudni na snimanie v hlavnej slucke a delay, to je uplne zle. Spravne to ma byt spravene takto: pustis si prerusenie od casovaca, cca 50ms, v nom sa vzdy pozries na stav tlacidiel, ak nastane stav 0-1 tlacidlo bolo stlacene, 0-1 pustene, to ze sa na to pozeras kazdych 50ms ti osetri zakmity, stlacenie klavesy zapises do bufra FIFO (velost 6bytov staci) a hlavna slucka pozera ci je nieco v tomto bufri je, a vybavi danu klavesu..

Uživatelský avatar
fero_b
Příspěvky: 582
Registrován: 17 kvě 2004, 02:00
Bydliště: Kosice

#12 Příspěvek od fero_b »

skusim vyseknut narychlo kus kodu:

1) nadeklarujes dve premenne (2 byty, kde nacitas piny kde je navesena klavesnica, predchadzajuci stav, a sucasny stav):

uint8_t keyboard_byte_prev;
uint8_t keyboard_byte_current;

//dalej buffer a index donho:

uint8_t keyboard_buffer[KEYBOARD_BUFFER_SIZE];
uint8_t keyboard_write;

2) inicializacia - v arduine metoda "setup" (mam 4 klavesy navesene na porte H):

uint8_t key_hport = PINH & 0x78;
key_hport = key_hport<<1;
keyboard_byte_current = key_hport;
keyboard_byte_prev = keyboard_byte_current;
keyboard_write = 0x00;

3) prerusenie chodiace kazdych 60ms:

ISR (TIMER1_COMPA_vect)
{
keyboard_byte_prev = keyboard_byte_current;
uint8_t key_hport = PINH & 0x78;
key_hport = key_hport<<1;
keyboard_byte_current = key_hport;

if (((keyboard_byte_prev & 0x10) == 0x10) && ((keyboard_byte_current & 0x10) == 0)){ //button one, rising edge
//catch interrupt counter at rising edge
keyboard_byte_prev = keyboard_byte_current; //key handled
keyboard_buffer[keyboard_write] = 1; //toto je kod klavesy 1 pre stlacenie
if (keyboard_write < (KEYBOARD_BUFFER_SIZE-1)){
keyboard_write++;
}

goto label_interrupt1;
}else if (((keyboard_byte_prev & 0x10) == 0x0) && ((keyboard_byte_current & 0x10) == 0x10) ){//button one falling edge
keyboard_byte_prev = keyboard_byte_current; //short press key handled
keyboard_buffer[keyboard_write] = 2; //kod klavesy 1 pre pustenie
if (keyboard_write < (KEYBOARD_BUFFER_SIZE-1)){
keyboard_write++;
}
goto label_interrupt1;

}
...//tuna bude nasledovat dalsia klavesa (ten isty kod, len ine masky a kody klaves)



label_interrupt1: //tu pokracuje prerusenie... ak uz nic nerobi tak koniec



}

4) hlavna slucka //pre kritikov "goto" - mal som tam pekne funkcie, ale ako vidno su zakomentene, dosiel som na koniec so zasobnikom, tak som jeden-krat pouzite napastoval rovno namiesto :( - nie az tak pekne, ale ucelne a rychlejsie :)



for( ; ; ) {

uint8_t keyb_eval; //getKey();
if (keyboard_write == 0){ //keyboard_read){
keyb_eval = 0;
goto lab_01;
}
keyb_eval = keyboard_buffer[(keyboard_write -1)];
keyboard_write--;

lab_01:


if (keyb_eval == 1){ //push button1 response

}else if (keyb_eval == 2){ //release button1 response

}

//tu pride obsluha akcie pre dalsi buton... atd

... //dalsi tvoj kod hlavnej slucky


} //koniec hlavnej slucky

Uživatelský avatar
Rellik
Příspěvky: 610
Registrován: 17 úno 2017, 01:00
Bydliště: Staré Město (UH)

#13 Příspěvek od Rellik »

fero_b: Moc díky za radu. Nicméně moc moudrý jsem z toho nebyl. Začal jsem googlit ty funkce a narazil na jiné řešení těch tlačítek a to i s omezením těch zákmitů.
Dal jsem to dohromady, funguje - ale.
Dal jsem tu funkci blikání diody pod jedno tlačítko s tím, že se i rozsvítí dioda (jedna bliká druhá svítí). Pokud tlačítko opět zmáčknu, tak se neblikací dioda zhasne. Dotud je to OK. Problém je s tou blikací. Pokud to totiž vypnu když zrovna blikne, tak zůstane svítit. Jak to upravit aby to ten zavolaný podprogram ukončilo?

Kód: Vybrat vše

const int G = A0; // 3x LED
const int Y = A1;
const int B = A2;
int zelena;
int modra;
const int Tl1 = 2; // tlačítka
const int Tl2 = 3;
int ledState = LOW;
int gState = LOW;
int bState = LOW;
unsigned long previousMillis = 0;
const long interval = 800; 

// nové
int Tl1State;
int Tl2State;
int lastTl1State = LOW;
int lastTl2State = LOW;

long lastDebounceTime = 0;  
long debounceDelay = 50; 


void setup() {
    Serial.begin(9600);
    pinMode(G,OUTPUT);
    pinMode(Y,OUTPUT);
    pinMode(B,OUTPUT);
    pinMode(Tl1,INPUT_PULLUP);
    pinMode(Tl2,INPUT_PULLUP);
}

void loop() {
  zelena = digitalRead(Tl1);
  modra = digitalRead(Tl2);

// zelená dioda
   if(zelena != HIGH) { 
              zelena = LOW;
   } 
                       
   if(zelena != lastTl1State) {
              lastDebounceTime = millis();
              if (Tl1State == HIGH) {
                            gState = !gState;
                                     } 
   }
                                
   if ((millis() - lastDebounceTime) > debounceDelay) {
                 Tl1State = zelena;
 }

 //
digitalWrite(G, gState);
lastTl1State = zelena;

// modrá dioda
   if(modra != HIGH) { 
              modra = LOW;
   } 
                       
   if(modra != lastTl2State) {
              lastDebounceTime = millis();
              if (Tl2State == HIGH) {
                            bState = !bState;
                                     } 
   }
                                
   if ((millis() - lastDebounceTime) > debounceDelay) {
                 Tl2State = modra;
 }

 //
digitalWrite(B, bState);
lastTl2State = modra;

if(bState == HIGH) {
  HlavniProg(); 
}


 // hlavní program, který pojede stále 
//HlavniProg(); 


}

void HlavniProg() {
 unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    digitalWrite(Y, ledState);
  }
}

Uživatelský avatar
fero_b
Příspěvky: 582
Registrován: 17 kvě 2004, 02:00
Bydliště: Kosice

#14 Příspěvek od fero_b »

tie funkcie su z nejakeho mojho kodu, na googli to asi nenajdes, mozno ako pises nieco ine, ja riesim aj "long press" ale to som z toho co som ti napastoval dal prec aby som to velmi nezakomplikoval. Na ten kod co si poslal sa pozriem neskor:) Teoreticky by som ti cely ten handlink klavesnice mohol vyseknut z mojho projektu tak aby si to len skompiloval, ale postuduj ako sa spusti a nastavi na arduine prerusenie (ja arduino nepouzivam, pisem rovno pre procak, kde je prazdna flaska) ale urcite aj arduino nejak umoznuje nastavit vektor prerusenia, a povolit prerusenie, je to len otazka toho IDE a kompilatora co tam pouzivaju..

Uživatelský avatar
Rellik
Příspěvky: 610
Registrován: 17 úno 2017, 01:00
Bydliště: Staré Město (UH)

#15 Příspěvek od Rellik »

Kdybys na to mrkl, byl bych rád. Jinak "longpress" bych řekl, že je ok protože to můžu držet jak dlouho chci a vždy to jen buď zapne nebo vypne... Začnu zatím studovat další funkce co budu potřebovat... :)

Odpovědět

Zpět na „Miniaturní počítače (Arduino, Raspberry a další)“