Lekce 21 - Arduino a využití přerušení (interrupt) a ošetření záchvěvů při stisku tlačítka

22.06.2013 21:25

Translate to English

V dnešní lekci si řekneme něco o přerušení neboli anglicky"interrupt". Určitě jste si říkali někdy při psaní programu do Arduina, že program nebo cyklus programu musíte napsat tak, aby v cyklech např zjišťoval, zda nebylo stisknuto nějaké tlačítko. V malém programu na pár řádků to není problém, ale pokud máme nějaký program, kde smyčka v "loop" trvá např. 2 sekundy, tak přidávat funkci zda uživatel stiskl nějaké tlačítko by byl nesmysl a také co když se uživatel zrovna "trefí" do času, kdy program dělá něco jiného. Řešení je právě tzv. "přerušení", které zastaví aktuální běh programu, a vykoná funkci, která je zapsaná, aby se při tomto právě vykonala. Jinak řečeno, když Arduino dostane na pin, kde je možné nastavit přerušení, nějaký určený impuls, zastaví běh programu a vykoná něco jiného.

Tabulka pinů, kde je možno nastavit přerušení:

Arduino 0 1 2 3 4 5
UNO, Ethernet 2 3 -- -- -- --
Mega 2560 2 3 21 20 19 18
Leonardo 3 2 0 1 7 --

 

Zápis funkce, která aktivuje přerušení:

attachInterrupt(přerušení, funkce, mód);

Příklad:

attachInterrupt(1, Reakce, RISING); - což v překladu znamená, že se spustí funkce Reakce(), když se na pinu 3 (Arduino UNO), změní hodnota z LOW na HIGH

V tabulce nahoře vidíme, kde naše Arduino má piny kde lze aktivovat přerušení. V případě Arduina UNO máme přerušení dvě na pinech 2 a 3 a v případě Arduino MEGA (typ 2560) je možnost nastavit přerušeních dokonce 6 na pinech, uvedených v tabulce. V případech jiných typů Arduina, byste měli přerušení nalézt v jejich dokumentaci. 

My si nyní zkusíme jednoduchý praktický příklad. Nějak zaměstnáme Arduino a budeme chtít, aby něco udělal když detekuje přerušení. Do Arduina si nahrajeme tedy tento program:

Sami můžete vidět, že je to kód jenom pro demonstraci. Nic užitečného nedělá jen v cyklech něco počítá a čísla cyklu vypisuje na sériový port. Ale tím jsme Arduino zaměstnali a můžeme vyzkoušet přerušení, které jsme si v setup() nastavili na pin 2 (přerušení 1 u UNO), vykoná funkci test (ta jenom rozsvítí nebo zhasne LED integrovanou na Arduinu k pinu 13), a bude aktivována když se na pinu 2 (přerušení) změní hodnota z LOW na HIGH.

Samozřejmně by jsem k Arduinu připojil tlačítko, aby jsme simulovali změnu honoty na přerušení tlačítkem, ale neučiním tak a to z důvodu, který zjistíme dále. Jako zdroj této změny jsem si naprogramoval jednoduchým kódem druhé Arduino (MEGA), které pouze bliká ledkou integrovanou k pinu 13 na svoji desce. 

Kód pro druhé Arduino:

Takže jedno Arduinko nám dává hezký signál, který je připojený na ke druhému Arduino. To spustí funkci, kterou má nastavenou, když v našem případě jde signál z 0 do 1. My jsme nastavili mód detekce na RISING, ale možností je více jak ukazuje následující tabulka:

   
spustí funkci při přechodu z 0 na 1
spustí funkci při přechodu z 1 na 0
spustí funkci při kterékoliv změně jak z 1 na 0, tak z 0 na 1
spustí funkci pro 0 (LOW)

Tak tento příklad funguje bezvadně a i když si Arduino ve funkci loop() hezky něco dělá, nemusíme ošetřovat v kódu a zjišťovat zda bylo přerušení aktivováno. V běžné praxi budeme, ale chtít, aby jsme třeba zjistili, zda bylo stisknuto nějaké tlačítko. No není problém, připojíme si tedy místo Arduina s naším uměle vyrobeným signálem tlačítko, které když stiskneme, tak budeme chtít, aby se rozsvítila nebo zhasla LED (digital 13) na Arduinu. Připojíme si ho tedy (samozřejmě dle zvyklostí musí být vstupní pin připojen přes odpor k 0 nebo 1 a tlačítkem měníme hodnotu).

 

Tak a co se nám děje? funguje to zcela nespolehlivě, někdy nám dioda zhasne nebo se rozsvítí, ale né podle pravidel. Funguje to náhodně. A teď otázka, čím je to způsobeno? Vysvětlení je jednoduché. Tlačítko je vlastně elektromechanický prvek, který když stiskneme tak v našem reálném čase byť je to zcela okem nezjistitelné dojde při zapnutí, nebo rozpojení tlačítka k záchvěvům (bouncing). Viz obrázek z osciloskopu:

Takže Arduino to vyhodnotí jako několik stisknutí i když jsme tlačítko stisky pouze jednou. Takže pokud náš program vyhodnotí a spustí 4x funkci k přerušení (protože zjistil 4x změnu z 0 na 1) tak spustí také 4x funkci test, která ze stavu vypnuté LED  - zapne, vypne, zapne, vypne. Takže my si vlastně můžeme myslet, že to nefunguje, ale funguje to zcela správně. Co tedy udělat. Existují 2 způsoby, buď to ošetřit v programu tím, že po zjištění prvního přerušení toto přerušení vypneme nebo deaktivujeme, vykonáme co potřebujeme, poté počkáme třeba 300 ms  a následně zase přerušení aktivujeme, tak je upraveno zde:

Má to ovšem i své nevýhody. Zastavíme tím program na 300ms a také nemáme jistotu co se stane, když stisk bude trvat déle jak 300ms. Takže moje rada používat toto jen v nejnutnějších případech a z rozvahou.

Pozn.: V mém případě nepomohlo ani nastavení prodlevy na 500ms a ledka si po stisknutí tlačítka dělala co chtěla.

Druhá možnost je ošetřit tyto záchvěvy elektronicky pomocí několika málo součástek. Bude se jednat o obvod RC složený z kondenzátoru a odporu a jednoho integrovaného obvodu 40106, který obsahuje 6x Schmittův klopný obvod. Zakladní schéma je zde:

Princip je následovný. Když stiskneme tlačítko vybijeme kondenzátor C1, tím se vstupu Schmittova klopného obvodu objeví 0. Po uvolnení tlačítka se kondenzátor opět nabije. Pro zvádavé nabití kondenzátoru C1 si můžeme vypočíst podle vzorce t = R*C (10 000 Ohm * 0,00001 F) což je 0,1sec. Pro nás nepodstatné. Využijeme vlasnosti Schmittova klopného obvodu, který upraví signál do podoby podle obrázku (vidíme tam i průběh před na vstupu klopného obvodu i na výstupu)

Schmittův KO slouží k úpravě tvaru impulzů. Jeho základní vlastností je hystereze. To znamená, že jeho výstup je závislý nejen na hodnotě vstupu, ale i na jeho původním stavu. Hystereze, která je jindy nežádoucí, má zde své opodstatnění v tom, že zabraňuje vzniku zákmitů výstupního signálu v okolí střední úrovně spínání. Citlivost obvodu se nastavuje šíří-velikostí hystereze. Obvod je možno využít i jako jednobitový analogově digitální převodník - komparátor.

Schema zapojení pinů obvodu 40106, existuje několik integrovaných obvodů, které Schmittovy klopné obvody obsahují - máte mnoho možností při nákupu.

 

Jinak mnou uvedený integrovaný obvod obsahuje celkem 6 uvedených klopných obvodů, takže k 6ti tlačítkům nám stačí 1 integráček. Až ho budete kupovat, zjistíte, že jeho cena je opravdu nízká :-). 

Poté co máme zapojeno, vyzkoušíme a zjistíme, že to funguje touto metodou opravdu skvěle. Odstranění záchvěvů při práci s tlačítky a využití přerušení v Arduinu myslím, že využijete a doufám, že Vám tento návod pomohl a posunul Vaše vědomosti a malý kousek dále. 

Zpět

Diskusní téma: Lekce 21 - Arduino a využití přerušení (interrupt) a ošetření záchvěvů při stisku tlačítka

Datum
Vložil
Titulek

Kdybychom, abychom...

Pise se abychom, ne aby jsme, lzice se drzi v prave ruce, nesrka se a pri odchodu ze zachoda se myji ruce. Nektera pravidla pro prumerne vzdelaneho cloveka jsou jednoznacna, pokud chce byt prijatelne vniman okolim.

Datum
Vložil
Titulek

přerušení

Já nevím jak někdo může radit ostatním, když si ani nepřečte základní materiály (www.arduino.cc).
1.V přerušení zakazovat přerušení nemá smysl, protože je implicitně zakázáno.
2. Funkce delay() v přerušení nefunguje.
3. Totéž platí pro fci millis() - vrací stejnou hodnotu.

Doporučuji autorovi celý příspěvek opravit a nešířit mylné informace.

Datum
Vložil
Titulek

Re: přerušení

Zdravím Jeana a odpovím za autora. V přerušení vypnout a zapnout přerušení jde. Pokud přerušení vypnu, funguje i funkce delay a ostatní.

Datum
Vložil
Titulek

RGB

Ahoj.
Stavím RGB CUBE 8x8x8.
Potřebuji spouštět podprogram "refresh"co 8 ms.
Uvažoval jsem použít knihovnu "TimerOne",ale nevím,jak na to.
Poradí někdo?
Dík.

Datum
Vložil
Titulek

prerusenie nevypina led

robim co robim, dookola pozeram ten program a vsetko som dal ako to je napisane..ked stlacim tlacidlo, nastane prerusenie, vysvieti sa led..potom slucka loop ide dalej ako ma ale uz nenastane po stlaceni tlacidla prerusenie, resp. stlacim a led stale zostava svietit..vobec ju nevypne..resetnem arduino, a zase to iste, raz stlacim ledka svieti a uz potom stlacam a nic, zostava svietit..co stym moze byt?

Datum
Vložil
Titulek

kondik

Mohl bych se zeptat jaký přesně kondenzátor jste použil?

Datum
Vložil
Titulek

Re: kondik

naco kondiky, da sa to osetrit aj softwerom...
stlacim tlacidlo, nastane prerusenie a v nom sa urobi co treba
na konci miesto delay(x) zakazem prerusenie, spustim casovac a vratim sa do hlaveho programu.
v nom kontrolujem casovac
ak dopocital tak prerusenie zase povolim...
casovac nastavim napr. na 300ms
pocas behu casovaca sa hlavny program normalne vykonava

Datum
Vložil
Titulek

Re: Re: kondik

U jednoduchých tlačítek ok, ale pokud bys takto chtěl např. ošetřit rotační encoder se stabilními stavy těsně po hraně, budeš mít problémy, pokud použiješ běžné rotační spínače, u kterých se deklarují zákmity 3ms. Nebude to fungovat spolehlivě. Pak se hodí hw ošetření vstupů, nebo se musí použít dražší decoder.

Datum
Vložil
Titulek

Re: Re: Re: kondik

Rotační encoder zpravidla (typicky pro ruční "točení") není potřeba nijak ošetřovat. Je založený na Grayově kódu, vždy se mění jediný bit. O směru se rozhoduje nikoli během zákmitů v začátku pohybu, ale až ve chvíli, kdy je stav na jednom pinu ustálený a po odeznění zákmitů druhého pinu nastane další přesně definovaný stav. Tak je to například řešené u http://www.mathertel.de/Arduino/RotaryEncoderLibrary.aspx. Něco jiného je běžný "ruční" rotační encodér použitý nesprávně třeba na snímání polohy u amatérských robotů.

Datum
Vložil
Titulek

odpoved na to proc nefunguje to spozdeni

Mam zde odpoved, proc ti nefungovalo to osetreni zakmitu. je to pouzitim funkce delay(), ta totis neni funkcni, sama pouziva na pozadi preruseni. Jedina funkce ktera bude fungovat je delayMicroseconds().
Je to napsano primo v popisu te funkce preruseni jako aplikacni poznamka.

1 | 2 >>

Vyhledávání

arduino8.cz © 2015 Všechna práva vyhrazena.