Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Sprzętowy debounce przerzutnik Schmitta

perlon 07 Lis 2015 23:29 2160 25
  • #1 07 Lis 2015 23:29
    perlon
    Poziom 19  

    Witam
    Chciałbym załatwić debounce sprzętowo i jednocześnie aby układ odpowiadał stanem niskim na zwarcie wejścia do masy tak jak zwykły switch zwierający do masy podciągnięte wejście mikrokontrolera. Dodatkowo a może przede wszystkim chcę mieć separację galwaniczną. Na podstawie konwersacji z googlem urodził się poniższy schemat. Proszę o sprawdzenie czy to zadziała, jak również o podpowiedź jak dobrać wartości rezystorów i pojemności na wejściu przerzutnika schmitta. Pytanie dodatkowe : czy warto się upierać na ściąganiu wejścia przerzutnika do masy. Schematy które znalazłem mają podciągnięcie do VCC utrzymując stan niski na wyjściu. Przyciśnięcie przycisku do masy powoduje stan wysoki na wyjściu przerzutnika. Nie ukrywam że chciałbym odwrotnie jeżeli może to być wykonalne. Znalazłem też schemat gdzie kondensator odsprzęgał wejście przerzutnika do VCC a nie do GND.
    Przycisk jaki planuję to zwykły przycisk dzwonkowy.
    Sprzętowy debounce przerzutnik Schmitta

    0 25
  • #2 08 Lis 2015 13:31
    BlueDraco
    Specjalista - Mikrokontrolery

    1. Po co to w ogóle robić, jeśli wystarczą 2 linijki kodu w C?

    2. Okres drgań to ok. 15 ms. stała czasowa RC powinna być nieco większa. U Ciebie jest 4700 * 0.0000001 s = 0.00047 s = 0.47 ms

    Rezystor na wejściu bramki jest zbędny.

    0
  • #3 08 Lis 2015 19:35
    perlon
    Poziom 19  

    BlueDraco napisał:
    1. Po co to w ogóle robić, jeśli wystarczą 2 linijki kodu w C?

    Kontroler do którego to będzie podpięte do XMega A4U. Póki co jeszcze nie wiem jak to zrobić na nim w 2-ch linijkach. Zdaje się, że na XMedze można na każdym pinie wywołać INT0 lub INT1 więc może to jest kierunek. Wiem, że nie jesteś zwolennikiem procesorów 8-bitowych ale może jakiś link do przykładów lub podpowiedź? Takich wejść będzie 23 które będą wyzwalane niezależnie.
    Sprzętowy debounce przerzutnik Schmitta
    W grę wchodzi pooling albo przerwania + oczywiście jakiś system odliczania czasu albo rozwiązanie sprzętowe bez zabawy w odliczanie czasu i ponowne sprawdzanie rejestrów. Poza tym te 23 wejścia będą w postaci shieldu który będzie mógł zawierać jedynie optoizolację, optoizolację+sprzętowy debounce lub zwykłe zwory ale wtedy przyciski muszą chodzić na 3,3V. Dlatego zależy mi na tym aby układ z przerzutnikiem nie odwracał sygnału, żeby nie ingerować zbytnio w program.
    BlueDraco napisał:

    2. Okres drgań to ok. 15 ms. stała czasowa RC powinna być nieco większa. U Ciebie jest 4700 * 0.0000001 s = 0.00047 s = 0.47 ms
    Rezystor na wejściu bramki jest zbędny.

    Czyli powinienem zastosować pojemność powyżej 10uF (stała czasowa na poziomie ok.50ms) Będzie z zapasem. Sprawdzę to najpierw na jakimś układzie testowym.

    0
  • #4 08 Lis 2015 19:41
    BlueDraco
    Specjalista - Mikrokontrolery

    Zieeeew. POczytaj mikrokontrolery.blogspot.pl "o drganiach styków bez bajek". Przerwania portów zupełnie się do tego nie nadają, a procesor 8-bitowy nie będziue tańszy od 32-bitowego, cjhociaż w tak wyrafinowanym zastospwaniu oba będą równie dobre. Zatanów się, ile kosztują i ile miejsca na płytce zajmują 2 linijko kodu na każde wejście, a ile bramka, rezystor i kondensator. Do kosztów tych całkowicie zbędnych elementów i powierzchni płytki dolicz jeszcze koszty ich montażu.

    0
  • #6 08 Lis 2015 22:17
    perlon
    Poziom 19  

    Dzięki tos18

    BlueDraco napisał:
    Zieeeew. POczytaj mikrokontrolery.blogspot.pl "o drganiach styków bez bajek". Przerwania portów zupełnie się do tego nie nadają, a procesor 8-bitowy nie będziue tańszy od 32-bitowego, cjhociaż w tak wyrafinowanym zastospwaniu oba będą równie dobre. Zatanów się, ile kosztują i ile miejsca na płytce zajmują 2 linijko kodu na każde wejście, a ile bramka, rezystor i kondensator. Do kosztów tych całkowicie zbędnych elementów i powierzchni płytki dolicz jeszcze koszty ich montażu.

    Akurat chyba jest jakiś kłopot z mikrokontrolery.blogspo.pl
    Zależy jak na to popatrzeć. Zanim wymyślę te 2 linijki to minie sporo czasu. Za ten czas projekt zapewne już powstanie z nadzieją, że zadziała. W między czasie może mnie olśni albo zanim popełnię ten debouncing to mi coś podpowiesz poza tym że są to dwie linie kodu w C.

    0
  • #7 08 Lis 2015 22:31
    BlueDraco
    Specjalista - Mikrokontrolery

    No fakt, lutowanie po 4 układy scalone i 73 innych elementów w 100 urządzeniach na pewno zajmuje mniej czasu i kosztuje mniej niż jednorazowe napisanie 46 linii kodu. Przy 1000 urządzeń zysk z niepisania kodu będzie jeszcze większy (przynajmniej dla montażystów i producentów płytek).

    Kod dla STM32 wygląda tak:
    if ((key_state = key_state << 1 | (BUTTON_PORT->IDR >> BUTTON_BIT & 1)) == 1)
    zareaguj_na_zmianę();

    0
  • #8 08 Lis 2015 22:51
    2675900
    Użytkownik usunął konto  
  • #9 09 Lis 2015 01:13
    perlon
    Poziom 19  

    No nie powiem, dla mnie nie jest to łatwe do rozgryzienia, ale spróbuję. Na początku pytanie czy przycisk zwiera do masy czy do VCC. Zakładam że do masy wejście z pull-up.
    key_state musi być jakoś zainicjowana. Zakładam, że key_state powinna odzwierciedlać początkowy stan wejścia więc jest równe 1.
    (BUTTON_PORT->IDR >> BUTTON_BIT & 1) zwraca aktualny stan przycisku. Tak wiec jest 1.
    key_state<<1 przesuwa w lewo bity stanu klawisza. Mamy aktualnie 1 więc po przesunięciu mamy 10(bitowo). Po sumie ze stanem wejścia dostajemy nową wartość 11(bitowo) którą podstawiamy to do key_state. oczywiście nie jest to 1 więc nie reagujemy.
    Tak leci w kółko wypełniając key_state jedynkami do wielkości zgodnej z typem zmiennej dla uproszczenia nie 32bity tylko 8bit.
    Wciśnięcie przycisku:
    (BUTTON_PORT->IDR >> BUTTON_BIT & 1) zwraca 0
    key_state po przesunięciu w lewo ma 11111110(bitowo) po sumie z zerem daje to samo. Zapisujemy nowy stan który nie jest 1 więc dalej nic nie robimy
    W kolejnych przebiegach pętli w wyniku drgań pojawiają kombinacje zer i jedynek aż do ustabilizowania się stanu czyli 0. Dale nie jest to 1 więc nic nie robimy. Puszczamy przycisk i w pierwszym przebiegu po puszczeniu w key_state dostajemy 1. To wyzwala funkcję rekcji. Powyższy kod eliminuje debounce i reaguje na zwolnienie przycisku. Nie jest w stanie rozpoznać wciśnięcia przycisku. Jeżeli zmieni się założenia można zapewne uzyskać efekt reakcji na wciśnięcie przycisku ale nie będzie wtedy reakcji na zwolnienie. Interwał czasowy testowania stanu przycisku zależy od szybkości obiegu pętli a ilość sprawdzeń stanu od "pojemności bitowej" zmiennej key_state. Niestety to tylko połowa sukcesu.
    Jeżeli powyższy przydługawy wywód zawiera błędy proszę o naprostowanie.
    Po chwili zastanowienia można by się pokusić o sprawdzenie czy key_state jest 00000001 jak i 11111110 co by oznaczało i zwolnienie i wciśnięcie przycisku a interwał czasowy mógłby zależeć nie od długości obiegu pętli tylko można go wyznaczyć za pomocą flagi ustawianej w przerwaniu od timera.

    0
  • Pomocny post
    #10 09 Lis 2015 08:48
    BlueDraco
    Specjalista - Mikrokontrolery

    Akurat w przypadku tego kodu przycisk wyjątkowo zwierał do plusa. Jeśli zwiera do masy, to powinno się porównywać z wartością 0b11111110. Na ogół nie ma sensu rejestrować aż 8 stanów - wystarczy wymaskować zmienną keystate maską złożoną z 2..3 jedynek i porównywać z odpowiednią maską, np. 0b110. keystate jest typu uint8_t.

    Wyglądałoby to np. tak:
    if ((key_state = (key_state << 1 | (BUTTON_PORT->IDR >> BUTTON_BIT & 1)) & 0b111) == 0b110)
    zareaguj_na_zmianę();

    Oczywiście kod jest umieszczony w przerwaniu timera, zgłaszanym z częstotliwością 100 Hz lub podobną (a nie w pętli o nieznanym i zmiennym czasie wykonania).

    Kodu używam w dziesiątkach projektów, więc jest dobrze wypróbowany.

    0
  • #11 09 Lis 2015 13:13
    perlon
    Poziom 19  

    Dzięki za zainteresowanie i pomoc. Zastosuję powyższe we własnym kodzie.

    Dodano po 3 [godziny] 53 [minuty]:

    Po adaptacji do własnych potrzeb wyszło mi coś takiego. Kod rozpoznaje czy nastąpiło wciśnięcie czy zwolnienie przycisku:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    w obsłudze zmiany stanu wejść coś w tym stylu
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Jak widać przy takiej ilości wejść procek 32bit z takimi operacjami poradziłby sobie lepiej. Ale zakładam że XMega też opanuje tą niezręczną sytuację ;-)

    0
  • #12 09 Lis 2015 20:01
    BlueDraco
    Specjalista - Mikrokontrolery

    To powyżej wygląda na całkowicie błędne. Po pierwsze - jeśli chcesz wykrywać naciśnięcie i zwolnienie, historię stanów należy aktualizować tylko raz, a następnie porównać ją z dwoma wzorcami. Zupełnie nie wiem, do czego miałby służyć ten drugi fragment kodu. Nie wiem też, po co jest potrzebna zmienna checkInputsFlag.

    Np. coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Szerokość słowa procesora nie ma wpływu na jego wydajność w operacjach 8-bitowych, niemniej każdy ARM wykona takie sprawdzenia dla wielu wejść wielokrotnie szybciej niż AVR, bo lepiej adresuje dane w pamięci i na ogół ma wyższą częstotliwość zegara.

    0
  • #13 09 Lis 2015 21:46
    perlon
    Poziom 19  

    checkInputsFlag to flaga ustawiana w przerwaniu od timera np. co 10ms. Na jej podstawie są sprawdzane wejścia co 10ms. Sprawdzenie odbywa się w pętli głównej.
    Zrobiłem tak ponieważ chcę mieć zamiecione wszystkie wejścia w stanach ustalonych zanim wykonam cokolwiek na wyjściach. Muszę zatem wiedzieć które wejście ma stan wysoki bo go miało a które ma stan wysoki bo go właśnie dostało i vice versa.
    Dlatego raz jest iloczyn a raz suma logiczna przy sprawdzaniu stanu wejścia w poszczególnych blokach if () {} else {}
    key_state == 0b1110 oznacza wykrycie pierwszego impulsu na wejściu podciągniętym do VCC a nie stan ustalony wejścia. key_state == 0b0000 oznacza stan ustalony wejścia. Jeżeli na to nałożę informację że zapamiętany ostatnio stan ustalony był wysoki to znaczy, że od ostatniego skanowania wejść nastąpiła zmiana wejścia (naciśnięcie klawisza) i że ta zmiana jest ustalona. Ustawiam znacznik pozwalający na wejście do procedury obsługi zmiany stanu wejść. Mam pewność że zmiana nastąpiła i że jest to stan ustalony. Nie sprawdzałem tego na układzie, na razie pisze tylko program, ale wydaje mi się ze powinno to zadziałać. A że tak trochę dmucham na zimne tzn. biorę wyłącznie pod uwagę stany ustalone? Być może. Jak zmajstruję coś na płytce stykowej to potestuję. Niestety nie mam zaawansowanego warsztatu (oscyloskop etc.) ale jakoś testy spróbuję wymodzić.

    0
  • #14 09 Lis 2015 23:28
    2675900
    Użytkownik usunął konto  
  • #15 10 Lis 2015 00:01
    Freddy
    Poziom 43  

    Jeśli upierasz sie przy sprzętowym debounce, to zainteresuj się układami MAX6816/MAX6817/
    MAX6818 - single, dual, and octal switch debouncers. Inne firmy też robią takie układy.

    0
  • #16 10 Lis 2015 00:46
    BlueDraco
    Specjalista - Mikrokontrolery

    Błądzisz i kręcisz się wokół własnego ogona. Masz wykryć zmianę stanu wejścia - i dokładniuśko to właśnie robi kod, który Ci pokazałem - wykrywa zmianę stanu i ignoruje następujące po niej oscylacje. W dodatku robi to poprawnie - w przerwaniu. Nic do niego nie musisz dodawać, żadnych "stanów stabilnych".

    0
  • #17 10 Lis 2015 22:33
    perlon
    Poziom 19  

    Wymazałem gumką co do tej pory napisałem i jeszcze raz przeanalizowałem twój kod. Faktycznie powinienem się chyba skupić na rozpoznaniu pierwszej zmiany stanu wejścia czyli zmiany która występuje po stanie ustalonym. W takim przypadku ile by nie trwały drgania styków kod zawsze zadziała i zareaguje natychmiast po zmianie stanu wejścia.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Martwi mnie tylko taka sytuacja, w której przycisk zostanie wciśnięty i natychmiast puszczony. Powiedzmy taka sekwencja odczytu wejścia :
    0b1111,0b1111,...,0b1111,0b1110,(tu rejestrujemy wciśnięcie)
    ,0b1101,0b1010,0b0100,(puszczamy przycisk),0b1001,0b0010,0b0101,0b1011,0b0111,0b1111,0b1111,...
    Jak widać nie ma rejestracji puszczenia przycisku. Rejestr stanu wejścia wskazuje że przycisk jest wciśnięty a wejście pokazuje coś innego.
    Gdyby jednak założyć że aby uznać że przycisk jest wciśnięty musi być to potwierdzone trzema czterema kolejnymi odczytami (mój tzw. stan ustalony) a nie tylko jedną pierwszą zmianą stanu wejścia to wtedy wprawdzie mogą mi umknąć szybkie ultrakrótkie wciśnięcia ale nie rozjedzie mi się zmienna trzymająca stan wejść z faktycznym ich stanem.

    Dodano po 11 [minuty]:

    Freddy napisał:
    Jeśli upierasz sie przy sprzętowym debounce, to zainteresuj się układami MAX6816/MAX6817/
    MAX6818 - single, dual, and octal switch debouncers. Inne firmy też robią takie układy.

    Dzięki za podpowiedź ale jak sprawdziłem ile te układy kosztują to dla mnie skromnego hobbysty cena jest zdecydowanie za wysoka.

    0
  • #18 10 Lis 2015 22:44
    2675900
    Użytkownik usunął konto  
  • #19 10 Lis 2015 22:52
    Freddy
    Poziom 43  

    perlon napisał:
    reddy napisał:
    Jeśli upierasz sie przy sprzętowym debounce, to zainteresuj się układami MAX6816/MAX6817/
    MAX6818 - single, dual, and octal switch debouncers. Inne firmy też robią takie układy.

    Dzięki za podpowiedź ale jak sprawdziłem ile te układy kosztują to dla mnie skromnego hobbysty cena jest zdecydowanie za wysoka.
    Jeśli potrzebujesz pojedynczą sztuke, to moge się podzielic z Toba za parę zł na przesyłke

    0
  • #20 10 Lis 2015 22:54
    perlon
    Poziom 19  

    Dziękuję Freddy ale wejść jest 23.
    Nie bardzo rozumiem co do powyższego ma ilość wejść. Nie wiem jaki wynik można osiągnąć ale mogę spróbować sobie popstrykać albo postrzelać karabinkiem ASG do wyłącznika. Mi raczej chodzi o kod który będzie odporny na takie strzelanie. np taki :

    Kod: c
    Zaloguj się, aby zobaczyć kod

    zakładając przerwanie co 10ms przyciśnięcie/zwolnienie musi trwać min.40ms żeby uznać że jest wciśnięty, jeżeli jest krócej to jest traktowany jak "śmieć" na wejściu.

    dodane:
    Wyedytowałem listing bo pokręciłem 0b0000 z 0b1111. Teraz chyba powinno być lepiej

    0
  • #21 10 Lis 2015 22:58
    Freddy
    Poziom 43  

    Przeglądnij kartę katalogową do tego układu, jest tam rozrysowany jego schemat blokowy.
    Można poznać sposób rozwiązania problemu.

    0
  • #22 10 Lis 2015 23:22
    perlon
    Poziom 19  

    Jeśli tylko jestem w stanie to ogarnąć to układ jest oparty na liczniku który jest resetowany za każdym razem jak wystąpi zgodność sygnałów między wejściem a wyjściem. Jeżeli sygnały są różne i licznik doliczy do końca to wyjście zmienia stan na przeciwny czyli zgodny z wejściem wprowadzając permanentny reset licznika. Chyba jest to dla mnie jakieś światełko w szeroko rozumianym "problemie debouncingu". Dzięki za podpowiedź

    0
  • Pomocny post
    #23 10 Lis 2015 23:29
    Freddy
    Poziom 43  

    Nie ma sprawy. Rozwiązanie jest rzeczywiście bardzo ciekawe. Dlatego podpowiedziałem Ci ten układ.
    Myślę, że warto zamieścić tutaj ten schemat blokowy. Dokładniejszy opis jest w DS.

    Sprzętowy debounce przerzutnik Schmitta

    0
  • #24 11 Lis 2015 15:47
    excray
    Poziom 39  

    Przy takim doborze prądu diody usmażysz transoptor.

    0
  • #25 11 Lis 2015 16:46
    perlon
    Poziom 19  

    Wg DS Vf=1.2V Ifmax=50mA
    I=(12V-1.2V)/360ohm=0,030A=30mA
    0,03*1,2V=0,036W < Pmax = 0,070W
    Gdzie mam błąd?
    Oczywiście nic nie stoi na przeszkodzie żeby dać 560ohm.

    0
  • #26 11 Lis 2015 17:18
    excray
    Poziom 39  

    Błąd masz w tym ze do wysterowania tego transoptora potrzebujesz w najgorszym wypadku 2mA czyli 4k7 to aż nadto. W elektronice trzeba dążyć do minimalizacji zużycia energii a nie do jej marnotrawstwa.

    0