Biblioteka Timers = koniec z uciążliwym delay() - Wersja do druku +- Arduino Polska Forum (https://forum.arduinopolska.pl) +-- Dział: Inne (https://forum.arduinopolska.pl/dzial-inne) +--- Dział: Poradniki (https://forum.arduinopolska.pl/dzial-poradniki) +--- Wątek: Biblioteka Timers = koniec z uciążliwym delay() (/watek-biblioteka-timers-koniec-z-uci%C4%85%C5%BCliwym-delay) Strony:
1
2
|
Biblioteka Timers = koniec z uciążliwym delay() - wojtekizk - 13-01-2016 Witam Ten tutorial ma wiele wspólnego z flustracją jaka często nas dopada, kiedy chcemy poszerzyć nasz programik o obsługę kolejnej fajnej funkcji i nagle okazuje się, że to nie jest takie proste :-) Dotąd pisaliśmy programiki gdzie procesor wykonywał w pętli loop() kolejne instrukcje krok po kroku... w niekończącej się pętli (neverending story). Jak chcieliśmy nagle przerwać jakieś działanie to uciekaliśmy się do przerwań (zewnętrznych lub timera). Co się wtedy dzieje? - procesor zapamiętuje stan rejestrów, wykonuje skok do funkcji obsługi przerwania i następnie wraca do miejsca gdzie przerwał naszej pętli loop() działanie. OK... ale jeśli byliśmy właśnie na przykład w pętli delay(5000) i po 300 ms. wywołaliśmy przerwanie, to po powrocie procesor i tak wykona swoje delay(4700) które pozostało... a tego na przykład nie chcemy. Problem polega na tym, że nasz procek wykonuje program sekwencyjnie, czyli krok po kroku... Natomiast nasz Windows, Linux czy Android (to także Linux) swoje programy opiera o tzw. obsługę wątków. W dużym uproszczeniu system "nasłuchuje" co się dzieje z urządzeniami zarejestrowanymi w systemie i w zależności od tego co się wydarzy podejmuje określone działanie. Jeśli ruszysz myszą... system już wie że to zrobiłeś, gdzie jest myszka... Jeśli klikniesz myszką na ikonkę, system wie co to za ikonka i jakim klawiszem kliknąłeś :-) To oczywiście duże uproszczenie, zwłaszcza dla API Windows. W każdym razie system w określonych odstępach czasu (im szybszy procek, tym częściej) odpytuje wszystkie zarejestrowane składniki i przejmuje kontrolę nad zdarzeniem, które z kolei potrafi obsłużyć. W tym tutorialu postaram się przybliżyć nieco to zagadnienie i przedstawić przykład zastosowania tej właśnie techniki w naszych programach. To nie jest wcale takie trudne a jest alternatywą dla obsługi przerwań na przykład. Postanowiłem podejść do tego problemu z innej strony - napisać program oparty o obsługę zdarzeń właśnie. Celem nadrzędnym było zachowanie pełnej funkcjonalności BEZ UŻYCIA w funkcji loop() chociażby jednej funkcji delay()!!! Przykład projektu: -------------------- Nasze przykładowe zadanie - zaprojektować urządzenie - wytrawiarkę płytek drukowanych - czyli połączenie stopera, termostatu z grzałką i mieszalnika w jedno. Każde z tych urządzeń ma mieć niezależne sterowanie, czyli jeśli np. silnik (mieszadło) wykonuje ruch w jedną stronę, to funkcja delay() nie może spowalniać stopera i jednocześnie jeśli będę chciał zmienić np . temperaturę zadaną to nie powinienem czekać w kolejce wykonywanych czynności w drzewku funkcji loop :-) To zadanie można zrealizować za pomocą obsługi przerwań ( zewnętrzne lub timera)... ale jeśli za chwilę zapragnę jeszcze niezależnie zmieniać prędkość zmian kierunku ruchu silnika, to co? Kolejne przerwanie? Proponuję tu zapoznać się z biblioteką Timers (moim zdaniem najlepszą i najprostszą z trzech podobnych - Timer, TimerOne i TimerTree). Ona pozwoli nam na zastosowanie techniki programowania opartej na obsłudze wątków. Nie chcę tutaj powielać opisu... więc aby nie zanudzać więcej przedstawiam przykładowy kod z obszernym wstępnym komentarzem, który mam nadzieję wyjaśni większość ew. wątpliwości: Komentarz: ------------- Przykładowa implementacja programu opartego na obsłudze zdarzeń. Namiastka aplikacji będąca alternatywą dla programowania sekwencyjnego, krok, po kroku. Ten program nasłuchuje w określonych odstępach czasu informacji o stanie użytych w nim podzespołów (czujników, buttonów, silników itp.) i w zależności od stanu ich samych podejmuje określone działania. Dzięki takiemu podejściu możliwa jest całkowita eliminacja uciążliwej funkcji delay(). Nie trzeba bowiem czekać aż wykona się czynność ograniczona funkcją delay(). Jest to równiez alternatywa dla obsługi przerwań. Przykładowo jeśli uruchomiono silnik na czas 2 sekund, to bez obsługi przerwań (zewnętrznych lub timera) nie było prostego sposobu na wykonanie innego zadania w trakcie ruchu silnika. Ten program korzysta z biblioteki Timers, która moim zdaniem jest chyba najłatwiejsza do zastosowań i może być powszechnie używana przez wielu majsterkowiczów i czytelników naszego forum. Zamieszczony przykład jest softem do projektu "automatycznej wytrawiarki", czyli termostatu z mieszalnikiem. Projekt umożliwia: - ustawienie zadanej temperatury procesu wytrawiania płytek drukowanych (tu w zakresie 10-80 st.C) - automatyczne nadzorowanie grzałki ( włącz - wyłącz) - funkcja termostatu - dynamiczne, niezależne załączanie lub wyłączanie mieszalnika - funkcja mieszania roztworu metodą wibracyjną (szybka zmiana kierunku obrotu silnika) - dynamiczną, niezależną zmianę czasu ruchu silnika w mieszalniku - regulacja czasu ruchu silnika. - kontrolę czasu trwania procesu - funkcja stopera (tutaj max 60 minut) To wszystko realizowane jest za pomocą tylko 3 przycisków: UP, DOWN i OK. Zatem program realizuje kilka jednoczesnych procesów: odlicza czas, mierzy aktualną temperaturę, załącza/wyłącza grzałkę, steruje ruchem mieszalnika i szybkością zmian kierunku obrotów oraz w czasie rzeczywistym umożliwia zmianę parametrów: temperatury zadanej i prędkości mieszalnika bez opóźnień i wpływu na wykonywanie innych zadań. Niezbędną dotąd funkcję delay i przerwania w programie zastąpiono obsługą osobnych wątków w określonych odstępach czasu. Program jest przykładem zastosowania biblioteki Timers. OPIS BIBLIOTEKI (skrócony): ---------------------------- Czym biblioteka Timers różni się od biblioteki Timer, TimerOne czy TimerTree? Przede wszystkim prostotą użycia jej w programie. Zasadniczo korzystamy z 4 wygodnych funkcji składowych klasy Timers: 1) Konstruktor - inicjalizacja obiektu klasy Timers. Przykład: Timers <8> akcja; - Powołujemy do życia obiekt klasy Timers o przykładowej nazwie akcja, który może obsłużyć 8 niezależnych wątków (zdarzeń) 2) Funkcja attach(nr wątku, interwał wywołania, funkcja obsługi), gdzie: - numer wątku, to numer jednego z 8 wcześniej zdefiniowanych w konstruktorze wątków; - interwał - odstęp czasu w ms. W tych odstępach będzie wywoływana funkcja obsługi - funkcja obsługi - nazwa funkcji, jak ma być wykonywana. W tym zakresie funkcja attach jest łudząco podobna do funkcji attachInterrupt. Przykłady: akcja.attach(2,5000,pokazTemp); - co 5 sekund wątek 3 (liczymy od 0) wywołuje funkcję pokazTemp() akcja.attach(0, 1000, pokazCzas); - co 1 sekundę wątek pierwszy wywołuje funkcję pokazCzas() akcja.attach(1,0,flopKierunek); - definiujemy wątek nr 2, ale nie mamy na razie zamiaru z niego korzystać - interfał =0 UWAGA!!! Funkca attach musi być zainicjowana w funkcji setup() dla każdego z wątków. Jeśli nie mamy zamiaru od razu korzystać z danego wątku, to w funkcji attach ustawiamy interwał na 0 3) Funkcja updateInterval(nr wątku, akt interwał), gdzie: - nr wątku, to numer jednego z 8 wcześniej zdefiniowanych w konstruktorze wątków; - akt interwał - dynamiczna zmiana czasu wywoływania funkcji, w szczególnym przypadku dla interwał=0 wyłączamy obsługę wątku. Przykłady: akcja.updateInterval(2,0); - zatrzymanie obsługi wątku nr 3 akcja.updateInterval(4,189); - zmiana lub ustawienie dla wątku nr 5 czasu wywoływania funkcji obsługi na 189 ms. 4) funkcja process() - wywoływana w pętli loop, uruchamia globalną obsługę wszystkich zadeklarowanych w konstruktorze wątków Przykład: akcja.process(); W programie sterowanie silnikiem jest realizowane za pomocą 2 pinów cyfrowych, w oparciu o zasadę: pin A - LOW, pin B - LOW - STOP silnika pin A - HIGH, pin B - LOW - ruch w lewo pin A - LOW, pin B - HIGH - ruch w prawo Zdaję sobie sprawę, że akurat takie sterowanie wymaga specjalnego zabezpieczenia mostka H, który przy dużych prądach silnika jest niestety wymagany. Dla celów testowych zamiast silnika do płytki podłączono 2 diody LED połączone równolegle (przeciwstawnie A-K przez rezystor 220 OHm). Dzięki temu będą zapalały się na przemian symulując pracę silnika. Ponadto w funkcji pokazTemp() użyto czujnika temperatury podpiętego do wejścia A1. Jeśli posiadasz inny czujnik należy zmodyfikować jego obsługę i wzór przeliczający jednostki oraz dodać ew. bibliotekę obsługi czujnika. OBSŁUGA PROGRAMU: Po załączeniu zasilania widzimy ekran powitalny gdzie na wstępie ustawiono zadaną temperaturę roztworu na 40 st.C Klawiszami DOWN - UP możemy modyfikować tą temperaturę ze skokiem 1 st. C Klawisz OK zatwierdza zmiany i zostaje uruchomiony proces wytrawiania (start stopera, start mieszalnika, nagrzewanie) Co 1 sek. pokazywana jest zmiana czasu, co 5 sekund aktualizowana jest temperatura roztworu, a ruch silnika w jedną stronę trwa 0,6 sek. (wstępnie zadeklarowana zmienna cz=600) Klawiszem OK możemy teraz zatrzymać mieszalnik. Ponowne naciśnięcie OK uruchamia nasz mieszalnik. Naciśnięcie klawisza DOWN lub UP podczas pracy mieszalnika umożliwia zmianę czasu pracy silnika ze skokiem 50 ms. Naciśnięcie klawisza DOWN lub UP podczas postoju mieszalnika umożliwia zmianę zadanej temperatury ze skokiem 1 st.C SPIS UŻYTYCH PINÓW, płytka Arduino UNO R3: ----------------------------------- 8,9,4,5,6,7 - LCD 0 - klawisz DOWN 1 - klawisz UP 2 - klawisz OK 13 - przekaźnik grzałki 11,12 - piny silnika (do podłączenia mostka H) A1 - czujnik temperatury 3,10 - wolne piny ----------------------------------- A oto przykładowy kod wytrawiarki: (...by wojtekizk wojtek@warcaby.lh.pl) Cytat:#include <LiquidCrystal.h> // dołączona biblioteka LiquidCrystal W załączniku biblioteka Timers do zaimportowania (chodzą słuchy, że ta stara nie działa jak trzeba, więc tamtą trzeba usunąć i w to miejsce nowa :-) Pozdrawiam ...i czekam na ew. sugestie, ten wątek może być przyczynkiem do wielu rzeczowych dyskusji :-) RE: Biblioteka Timers = koniec z uciążliwym delay() - Lata - 18-01-2016 Kurde czuję, że już niedługo czeka mnie identyczna zabawa i będę miał dużo pytań bo jeszcze sporo nie rozumiem RE: Biblioteka Timers = koniec z uciążliwym delay() - Lata - 09-03-2016 Ogarnięte działa !! Dziękuję Bardzo !! RE: Biblioteka Timers = koniec z uciążliwym delay() - ANT - 09-04-2016 Witam, Możecie mi pomóc w ogarnięciu tej biblioteki TIMERS... Program testowy ma tylko mrugać diodą D13. Niestety nic się nie dzieje... Kod: //Timers. RE: Biblioteka Timers = koniec z uciążliwym delay() - -adamek - 09-04-2016 Cytat:Niestety nic się nie dzieje...Zawsze coś się dzieje ... Kod: akcja.attach (0, 500, dioda1); Kod: Dwie funkcje wywoływane są w tym samym czasie jedno 500 zmień np na 1000 RE: Biblioteka Timers = koniec z uciążliwym delay() - ANT - 09-04-2016 Faktycznie... gapa ze mnie Dzięki. RE: Biblioteka Timers = koniec z uciążliwym delay() - krzyspx - 01-11-2016 (13-01-2016, 17:45)wojtekizk napisał(a): WitamDzięki za namiary i przykłady zastosowania biblioteki Timers.h. Jest rzeczywiście genialnie prosta i łatwa w użyciu. I co ważne działa bez problemu w różnych konfiguracjach programowych i na różnych procesorach (u mnie Atmel i ESP). Może znasz równie prostą i przyjazną bibliotekę obsługi zdarzeń coś ala button ale nie ograniczoną tylko do zmian na portach procesora ale potrafiąca obsłużyć "zmiany" dowolnej zmiennej w programie (szerzej niż tylko zmienne typu bool). Oczywiście też działającej w poolingu i zawierającej ca 90 linii kodu . Krzycho RE: Biblioteka Timers = koniec z uciążliwym delay() - krzyspx - 02-11-2016 Trochę różnych wariacji programowych z biblioteką Timers.h zamiaściłem tu>>> Proszę o dodanie do opisu biblioteki funkcji setInterval. RE: Biblioteka Timers = koniec z uciążliwym delay() - pawelhuf - 15-11-2016 (01-11-2016, 15:13)krzyspx napisał(a):(13-01-2016, 17:45)wojtekizk napisał(a): WitamDzięki za namiary i przykłady zastosowania biblioteki Timers.h. Jest rzeczywiście genialnie prosta i łatwa w użyciu. I co ważne działa bez problemu w różnych konfiguracjach programowych i na różnych procesorach (u mnie Atmel i ESP). Czy biblioteka zadziała także na Attiny85? RE: Biblioteka Timers = koniec z uciążliwym delay() - bhejduk - 14-01-2017 Mam pytanie do autora tematu, czy zamiast klawiszy można użyć wyświetlacza dotykowego aby sterować pracą urządzenia? |