Close

Přerušení

Úvodní stránka Fórum Vaše projekty Arduino Přerušení

  • Toto téma obsahuje celkem 18 odpovědí. Do diskuze (3 diskutující) se naposledy zapojil uživatel posjirka a poslední změna proběhla před 7 roky a 6 měsíci.
Aktuálně je na stránce zobrazeno 15 příspěvků - 1. až 15. (celkem z 19)
  • Autor
    Příspěvky
  • #8198
    Dupla
    Účastník

    Zdravím,

    pomocí Arduino Uno chci ovládat 4 pneumatické ventily. Mám je připojené přes 4 cívky (DPS pro Arduino), každá spíná jeden ventil. Jsou připojené na piny 2, 3, 4, 5. Dozvěděl jsem se v dokumentaci, že piny 2 a 3 mají integrované přerušení. Ventily na ně připojené fungují správně i v návaznosti na sebe. Jenže zbylé dva k nim nemůžu navázat, protože blbnou. V kódu mám podmínku na koncové snímače (každý ventil má 2, pro zasunutí a vysunutí) a mezi vysunutím a zasunutím ventilu jsem použil funkci delay();, ale ta nejspíš dělá nepořádek, protože nedochází k přerušení v Arduinu. Jak tedy realizovat toto přerušení softwarově? Díky.

    #8207
    Zbyšek Voda
    Správce

    Dobrý den, můžete sem prosím nasdílet váš program? Děkuji

    #8220
    Dupla
    Účastník

    Zde je můj kód. První dvě podmínky po zakomentování zbytku fungují správně. Když připojím třetí podmínku, tak se vše rozhodí.

    // Konstanty pro pneumatické válce
       const int dvere = 2;
       const int davkovani = 3;
       const int lisovani = 4;
       const int vyhazovani = 5;
    // ----------------------------------------
    // Konstanty pro snímače
       const int vyhazovaniZasunute = 6;
       const int vyhazovaniVysunute = 7;
       const int lisovaniVysunute = 8;
       const int lisovaniZasunute = 9;
       const int dvereZasunute = 10;
       const int dvereVysunute = 11;
       const int davkovaniVysunute = 12;
       const int davkovaniZasunute = 13;
    
    void setup() {
      // Pneumatické válce nastaveny jako výstupy
      pinMode(dvere, OUTPUT);    
      pinMode(davkovani, OUTPUT);   
      pinMode(lisovani, OUTPUT);
      pinMode(vyhazovani, OUTPUT); 
    
      // Snímače nastaveny jako vstupy
      pinMode(vyhazovaniZasunute, INPUT);   //  Snímač - vyhazování zasunuté 
      pinMode(vyhazovaniVysunute, INPUT);   //  Snímač - vyhazování vysunuté
      pinMode(lisovaniVysunute, INPUT);   //  Snímač - lisování vysunuté
      pinMode(lisovaniZasunute, INPUT);   //  Snímač - lisování zasunuté
      pinMode(dvereZasunute, INPUT);  //  Snímač - dveře výstup zasunuté (otevřené)
      pinMode(dvereVysunute, INPUT);  //  Snímač - dvěře výstup vysunuté (zavřené)
      pinMode(davkovaniVysunute, INPUT);  //  Snímač - dávkování vysunuté
      pinMode(davkovaniZasunute, INPUT);  //  Snímač - dávkování zasunuté
    
      // Nastavení pneumatických válců do výchozí polohy - vše zasunuto
      digitalWrite(dvere, HIGH);
      digitalWrite(davkovani, HIGH);
      digitalWrite(lisovani, HIGH);
      digitalWrite(vyhazovani, HIGH);
    }
    
    void loop() {
      
      if(digitalRead(dvereZasunute) == HIGH)
      {
          digitalWrite(dvere, LOW);      // pokud svítí senzor, že je válec zasunutý, vysuň ho
      }
      
      if(digitalRead(dvereVysunute) == HIGH && digitalRead(davkovaniZasunute) == HIGH)
      {
          digitalWrite(davkovani, LOW);      // pokud svítí senzor, že jsou dveře zasunuté a senzor dávkování svítí pro zasunutí, vysuň dávkování, počkej 
          delay(4000);
          digitalWrite(davkovani, HIGH);    // a pak ho zase zasuň
      }
      // po sem kód funguje, pokud připojím následující, tak se to celé rozhodí
      if(digitalRead(dvereVysunute) == HIGH && digitalRead(davkovaniZasunute) == HIGH && digitalRead(lisovaniZasunute) == HIGH)
      {
          digitalWrite(lisovani, LOW); 
          delay(3000);
          digitalWrite(lisovani, HIGH); 
      }
      
      if(digitalRead(dvereVysunute) == HIGH && digitalRead(davkovaniZasunute) == HIGH && digitalRead(lisovaniZasunute) == HIGH)
      {
          digitalWrite(dvere, HIGH);      
      }
    
      if(digitalRead(dvereZasunute) == HIGH && digitalRead(davkovaniZasunute) == HIGH && digitalRead(lisovaniZasunute) == HIGH && digitalRead(vyhazovaniZasunute) == HIGH)
      {
          digitalWrite(vyhazovani, LOW);
      }
      
      if(digitalRead(dvereZasunute) == HIGH && digitalRead(davkovaniZasunute) == HIGH && digitalRead(lisovaniZasunute) == HIGH&& digitalRead(vyhazovaniVysunute) == HIGH)
      {
          digitalWrite(vyhazovani, HIGH);    
      }
    
      // snímače - HIGH - svítí, LOW - nesvítí,
      // pneumatické válce - HIGH - zasunutý, LOW - vysunutý.
    }
    
    #8231
    Zbyšek Voda
    Správce

    Problém bude v nesprávné interpretaci „přerušení“ 🙂
    K přerušení dojde, když program v reakci na nějakou událost „odskočí“ na chvilku ze standardního běhu a rychle se provede něco jiného. Přerušení může být vyvolané například vnitřním časovačem, nebo také změnou napětí na pinu – to vás asi zmátlo. Obsloužení přerušení probíhá tak, že pomocí funkce attachInterrupt() řeknete, co se má stát v reakci na jakou událost. Více o přerušeních na https://www.arduino.cc/en/Reference/AttachInterrupt a https://www.arduino.cc/en/Reference/Interrupts.

    Vy ale vlastně ani přerušení nepotřebujete. Problém v programu je ten, že pokud použijete funkci delay(), dojde k čekání programu po určitou dobu. V té době program nereaguje na koncové spínače, ani neobsluhuje posun motorů.

    Navrhuji místo tohoto „pasivního“ čekání použít funkci millis(), která vrací dobu v milisekundách od začátku běhu programu. Tento problém je popsaný v https://bastlirna.hwkitchen.cz/arduino-zaklady-blikani-bez-funkce-delay/.

    Jestli to dobře chápu, používáte delay kvůli tomu, že ventil musí určitou dobu běžet, než je zasunutý/vysunutý. Pokud ale stačí pro každý ventil mít jenom dva stavy – vysunutý/zasunutý a nepotřebujete nic mezi, to čekání vlastně vůbec nepotřebujete.
    Stačí vytvořit podmínku ve stylu: pokud je koncový vypínač 1 rozepnutý, nech ventil zapnutý, jakmile se k. vypínač sepne, vypni ventil. Chápeme se? 🙂

    #8236
    Dupla
    Účastník

    Ano, s přerušením souhlasím. Také jsem ho vyzkoušel pomocí funkce attachInterrupt(); na pinech 4 a 5, které přerušení neobsahují, ale bez výsledku. Na piny 2 a 3 jsem to nezkoušel, protože přerušení obsahují.
    Zpoždění zde mám z důvodu, protože chci, aby ventil zůstal vysunutý po nějakou dobu. Funkci millis() jsem také zkoušel a bez výsledku.
    Zkoušel jsem to i rozepsat stylem: pokud jeden snímač je zhasnutý, tak vysuň ventil, až se rozsvítí, tak ho zasuň…taky to moc nefungovalo.

    #8238
    Zbyšek Voda
    Správce

    To, že pin „obsahuje“ přerušení znamená, že umí přerušení vyvolat – že řekne programu „teď se zastav a dělej něco úplně jiného“.
    Piny 2 a 3 jsou tedy piny, které mohou způsobit vyvolání hardwarového přerušení. Obslužná funkce tohoto přerušení se na ně připojuje pomocí funkce attachInterrupt().

    Na pinech 4 a 5 přerušení nevyvoláte (ve smyslu toho hardwarového přerušení).

    Ve vašem programu ale pravděpodobně hardwarové přerušení vůbec nechcete. Vy jenom chcete například reagovat na koncový spínač apod. Tomu sice asi říkáte „přerušení“, ale s přerušením ve smyslu interrupt toto vůbec nesouvisí.

    #8239
    Dupla
    Účastník

    Jak jsem již psal výše, první dvě podmínky fungují (tzn. ovládání pneumatických válců, které jsou připojeny přes cívky na piny 2 a 3). Reagují na koncové spínače a i funkce delay(); funguje správně.

    To samé bych potřeboval realizovat i s piny 4 a 5 (tzn. reagovat na koncový spínač a při vysunutí válce nějakou chvíli počkat a pak ho zase zasunout).

    Ano, vím co přerušení znamená. Mám ale podezření, že je potřeba ho realizovat i na pinech 4 a 5, aby byla funkce programu správná, protože v tomto případě, tak jak jsem Vám kód poslal si program dělá co chce. Vysunout se všechny čtyři pneumatické válce naráz. Pokud nechám jen první dvě podmínky, které ovládají válce na pinech 2 a 3 a zbytek programu zakomentuji, program funguje správně, ale jen se dvěmi válci.
    Možná přerušení nechci, ale chtěl bych tam, aby válec po vyjetí nějakou dobu počkal a to se mi nedaří realizovat. Jak to tedy udělat?

    #8278
    posjirka
    Účastník

    zkusím se do toho vložit.
    Přerušení je proces, kdy dojde k dočasnému přerušení hlavní smyčky programu, provede se nějáká událost a po její ukončení pokračuje dále.
    Přerušení je více typů a je třeba s nim jednat opatrně. Může být nejen od pinů, ale i od přetečení registru, příchodu seriové komunikace na UART nebo I2C sběrnici, …
    Arduino má v základu nastavené pro UNO pouze 2 piny na přerušení, ale můžeš si je změnit, nebo detekovat celý 1 port (A, B, C nebo D). Rozhodně to není nic pro začátk.V tomto případě je to funkce řekl bych zbytečná.
    Mnohem užitečnější bude nezdržovat smyčku funkci delay a radši pracovat s rychlou smyčkou.

    Delay je totiž jen symčka plná „NOP“ takže procesor vlastně jen počítá jak dlouho dělá/nedělá nic.

    Rádi ti pomůžeme ale pojdmě na vše popořádku:
    1, napiš nám prosím co má program přesně dělat (trochu podrobněji)
    2, je třeba to zjednodušit a trochu si vypomoct pomocnými proměnými (např. si definuj proměnou „vysun_pist_1“, kde její hodnoty 1 např.znamena vysuń, hodnota 0 nic nedělej, 2 zasuň.) dá se pak mnohem lépe reagovat na podmínky.
    3. zbytečně si dubluješ stejné podmínky např. „digitalRead(dvereVysunute) == HIGH “ Vykašli se na to a použij vnořené podmínky:
    if (……){
    if (….) {
    } else {
    }
    }
    prostě se snaž si 1 podmínku vkládat pouze 1x a neopakovat.
    4. není špatné si to nakreslit na papír do jednoduchého vývojového diagramu, pak ti spoustu věcí dojde za pochodu.

    Co ty na to?

    #8279
    posjirka
    Účastník

    no možná ještě jeden bod:
    5. když to te´d sjíždím ten tvůj kod tak ty se snažíš „krokovat“ na základě nějákých opakujících se podmínek. šlo by napsat popis funkce toho stroje ně jednotlivých kroků?
    např. krok č.1 – kontrola že všechny písty jsou vysunuté, pokud ne všechny vsuň.
    krok č.2 – dávkování == 1
    krok č.3 ….

    a pak si jen uděláme proměnnou „krok“ a na základně aktuálního stavu budeme postupně celý proces krokovat ….

    #8280
    Dupla
    Účastník

    Vyzkoušel jsem už několik různých variací kódu ať už s přerušením, bez něj, s vnořenými podmínkami, nebo zvlášť. Nic z toho nefungovalo správně.
    Jak říkám, první dvě podmínky v kódu, který uvádím výše fungují správně, jakmile připojím tu třetí podmínku, tak se to celé rozhodí. Z důvodu, že v prvních dvou podmínkách používám válce připojené na piny 2 a 3, což jsou piny obsahující přerušení, tak mám podezření, že to bude tím.

    K tomu, co by měl program dělat.
    Každý ze 4 pneumatických válců má 2 koncové snímače polohy. Na začátku kontroluji, jestli je vysunutý válec „dvere“, pokud není, měl by se zasunout, když se zasune, měl by zůstat v té poloze. Na něj by měl navázat válec „davkovani“, vysunout se, počkat ve vysunuté poloze např. ty 4 vtěřiny a pak se zasunout. Po jeho zasunutí by se měl vysunout válec „lisovani“, zase nějakou dobu např. 3 vteřiny setrvat ve vysunuté poloze a poté se zasunout. Následovat by mělo zasunutí prvního válce „dvere“ a poté vysunutí a hned zasunutí válce „vyhazovani“. A tak by to mělo jet pořád dokola.

    #8283
    posjirka
    Účastník

    Přerušení to pravděpodobně neovlivňuje.
    Spíš bych to viděl na nevhodně strukturovaný program.
    celá tato logika je postavena na principu, že všechno jde přesně po sobě.
    To bohužel není pravda a v reálném světě je tu spousta zpoždění, zákmitů a vůlí, které to narušují.
    Nakreslil jsem do hrubého diagramu jak chápu tvůj požadavek.
    prosím podívej se na to a pokud to souhlasí tak bych zkusil navrhnou jiný program a můžeme to odzkoušet.
    Je to jen opis toho co jsi mi poslal, logika programu bude potom jiná.
    Určitě budu na začátku definovat výchozí stav (vysuň všechny válce), průběžněš kontrolovat celkový stav zařízení a vyhodnocovat případnou odchylku od požadovaného stavu (porucha).

    Ještě mě napadá jaké používáš čidla detekce koncových stavů válců? podle popisu mi to připadá jako kontrola svítí/nesvití signálka automatu.
    Máš tam i nějáké „STOP“ tlačítko? Pamatuj na bezpečnost ….

    #8285
    Dupla
    Účastník

    Když myslíš. No, uvidíme.
    V příloze posílám poupravený tvůj diagram.
    Na začátku bych spíš definoval ZASUŇ všechny válce, jsou totiž v podstatě kolmo na sebe a mohli by se zkřížit tak, jak se mi to děje u připojení mojí třetí podmínky v mém kódu. Jinak pozor, u válců je obrácená logika: LOW – vysuň, HIGH – zasuň, u snímačů je to normálně.
    Ano je to magnetický snímač – svítí/nesvítí.
    Stop tlačítko tam není.

    #8293
    posjirka
    Účastník

    co bys řekl na toto:

    // ovladani 4 paneumatickzch valcu
    // v01
    // DUPLA & by JP 2016
    
    // Konstanty pro pneumatické válce
    #define dvere 2
    #define davkovani 3
    #define lisovani 4
    #define vyhazovani 5
    // ----------------------------------------
    // Konstanty pro snímače
    #define vyhazovaniZasunute 6
    #define vyhazovaniVysunute 7
    #define lisovaniVysunute 8
    #define lisovaniZasunute 9
    #define dvereZasunute 10
    #define dvereVysunute 11
    #define davkovaniVysunute 12
    #define davkovaniZasunute 13
    // ----------------------------------------
    // pomocne promenne
    
    void setup() {
    	// Pneumatické válce nastaveny jako výstupy
    	pinMode(dvere, OUTPUT);    
    	pinMode(davkovani, OUTPUT);   
    	pinMode(lisovani, OUTPUT);
    	pinMode(vyhazovani, OUTPUT); 
    	
    	// Snímače nastaveny jako vstupy
    	pinMode(vyhazovaniZasunute, INPUT);   //  Snímač - vyhazování zasunuté 
    	pinMode(vyhazovaniVysunute, INPUT);   //  Snímač - vyhazování vysunuté
    	pinMode(lisovaniVysunute, INPUT);   //  Snímač - lisování vysunuté
    	pinMode(lisovaniZasunute, INPUT);   //  Snímač - lisování zasunuté
    	pinMode(dvereZasunute, INPUT);  //  Snímač - dveře výstup zasunuté (otevřené)
    	pinMode(dvereVysunute, INPUT);  //  Snímač - dvěře výstup vysunuté (zavřené)
    	pinMode(davkovaniVysunute, INPUT);  //  Snímač - dávkování vysunuté
    	pinMode(davkovaniZasunute, INPUT);  //  Snímač - dávkování zasunuté
    	
    	// inicializace seriove komunikace
    	Serial.begin(9600);
    }
    
    void loop() {
    	Serial.println("krok 1 ... nastaveni vychozi stav");
    	vychozi_stav(); // nastaveni vychoziho stavu
    	Serial.println("krok 2 ... vysun valec dvere");
    	vysun_valec_dvere();
    	Serial.println("krok 3 ... vysun valec davkovani");
    	vysun_valec_davkovani();
    	Serial.println("krok 4 ... pauza 4s");
    	delay(4000); // pauza 4s
    	Serial.println("krok 5 ... zasun valec davkovani");
    	zasun_valec_davkovani();
    	Serial.println("krok 6 ... vysun valec lisovani");
    	vysun_valec_lisovani();
    	Serial.println("krok 7 ... pauza 3s");
    	delay(3000); // pauza 3s
    	Serial.println("krok 8 ... zasun valec davkovani");
    	zasun_valec_lisovani();
    	Serial.println("krok 9 ... zasun valec dvere");
    	zasun_valec_dvere(); 
    	Serial.println("krok 10 ... vysun valec vyhazovani");
    	vysun_valec_vyhazovani();
    	Serial.println("krok 11 ... zasun valec vyhazovani");
    	zasun_valec_vyhazovani();
    }
    
    void vychozi_stav(){
    	// Nastavení pneumatických válců do výchozí polohy - vše zasunuto
    	Serial.println("Nastavuji vychozi stav ...");
    	zasun_valec_davkovani();
    	zasun_valec_lisovani();
    	zasun_valec_dvere();
    	zasun_valec_vyhazovani();
    }
    
    void 	vysun_valec_dvere() {
    	Serial.println("Vysouvam valec dvere ...");
    	while(digitalRead(dvereVysunute)==0) {
    		digitalWrite(dvere, LOW);
    	}
    	Serial.println("Vysouvam valec dvere ... hotovo");
    }
    
    void 	vysun_valec_davkovani() {
    	Serial.println("Vysouvam valec davkovani ...");
    	while(digitalRead(davkovaniVysunute)==0) {
    		digitalWrite(davkovani, LOW);
    	}
    	Serial.println("Vysouvam valec davkovani ... hotovo");
    }
    
    void 	zasun_valec_davkovani() {
    	Serial.println("Zasouvam valec davkovani ...");
    	while(digitalRead(davkovaniZasunute)==0) {
    		digitalWrite(davkovani, HIGH);
    	}
    	Serial.println("Zasouvam valec davkovani ... hotovo");
    }
    
    void 	vysun_valec_lisovani() {
    	Serial.println("Vysouvam valec lisovani ...");
    	while(digitalRead(lisovaniVysunute)==0) {
    		digitalWrite(lisovani, LOW);
    	}
    	Serial.println("Vysouvam valec lisovani ... hotovo");
    }
    
    void 	zasun_valec_lisovani() {
    	Serial.println("Zasouvam valec lisovani ...");
    	while(digitalRead(lisovaniZasunute)==0) {
    		digitalWrite(lisovani, HIGH);
    	}
    	Serial.println("Zasouvam valec lisovani ... hotovo");
    }
    
    void 	zasun_valec_dvere() {
    	Serial.println("Zasouvam valec dvere ...");
    	while(digitalRead(dvereZasunute)==0) {
    		digitalWrite(dvere, HIGH);
    	}
    	Serial.println("Zasouvam valec dvere ... hotovo");
    }
    
    void 	vysun_valec_vyhazovani() {
    	Serial.println("Vysouvam valec vyhazovani ...");
    	while(digitalRead(vyhazovaniVysunute)==0) {
    		digitalWrite(vyhazovani, LOW);
    	}
    	Serial.println("Vysouvam valec vyhazovani ... hotovo");
    }
    
    void 	zasun_valec_vyhazovani() {
    	Serial.println("Zasouvam valec vyhazovani ...");
    	while(digitalRead(vyhazovaniZasunute)==0) {
    		digitalWrite(vyhazovani, HIGH);
    	}
    	Serial.println("Zasouvam valec vyhazovani ... hotovo");
    }
    
    #8294
    Dupla
    Účastník

    Řekl bych, že to vypadá dobře, nicméně po vyzkoušení je výsledek stejný, jako v případě mého kódu. Po nahrání programu se vysunou všechny válce a dojde k jejich zkřížení.

    #8295
    posjirka
    Účastník

    jak to přesně vypadá?
    Jak spustíš Arduino, tak okamžitě to takto udělá, nebo je nejdřív pauza?

    Ono totoiž arduino má na začátku bootloader, který mimo jiné uvádí piny do nějákých mezistavů.
    Zkus dát do void setup(){ } navíc delay(20000);
    ten by měl rozběh všeho zpozdit o 20s.
    pokud i tak hned po spuštění arduina okamžitě začne hýbat s válci, je chyba v bootloaderu. Musel by s to pak udělat tak, že bys musel nahrát program přes ICSP, tzn. z arduina bys odstranil bootloader a nahrál program jako čistý kod bez berliček od Arduina.

Aktuálně je na stránce zobrazeno 15 příspěvků - 1. až 15. (celkem z 19)
  • Pro reakci na toto téma se musíte přihlásit.