logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[C] Nierówne zliczanie impulsów w przerwaniach INT0 i INT1

l1715s 26 Paź 2018 10:48 1332 20
  • #1 17518972
    l1715s
    Poziom 9  
    Witam,
    na potrzeby większego projektu testuje zliczanie impulsów z czujnika szczelinowego jak poniżej:
    [C] Nierówne zliczanie impulsów w przerwaniach INT0 i INT1

    Chcę zliczać impulsy z dwóch czujników.
    Wykorzystuje do tego przerwania zewnętrzne INT0 i INT1, podłączając wyjścia sygnału z czujników odpowiednio do pinów PD2 i PD3.
    Przerwania ustawione są na zbocze opadające.
    W przerwaniu inkrementuję tylko zmienną przechowującą ilość impulsów, nic więcej.
    Z tego względu, że mam na razie jeden czujnik, podłączyłem wyjście czujnika do obydwóch pinów jednocześnie.
    W pętli głównej wysyłam tylko wartości dwóch zmiennych na LCD.
    W dużej większości przypadków wartości są równe (sygnał dochodzi w tym samym czasie do PD2 i PD3).
    Jednak zdarzają się sytuacje, kiedy wartości są różne, zawsze zmienna inkrementowana w INT1 jest mniejsza.
    Najczęściej ma to miejsce przy szybkich zmianach stanu na czujniku, ale przy wolnych tez się to zdarza.

    Podejrzewam, że ma to związek z priorytetami przerwań i z tym, że impulsy do obydwóch przerwań dochodzą w tym samym czasie.
    Po prostu czasami jedno z nich INT1 nie ma kiedy się wykonać.
    Pewnie jakby były podłączone dwa czujniki, sytuacja albo by się nie powtarzała, albo występowała by rzadziej .
    Jednak może zdarzyć się teoretyczna sytuacja kiedy sygnały z dwóch czujników dotrą w tym samym czasie.
    Szacuję, że w docelowym projekcie sygnały będą występowały z częstotliwością maksymalnie kilku - kilkunastu Hz.

    Proszę was o pomoc w rozwiązaniu problemu.
    Mam dwa pomysły:
    1) Wyprowadzę sygnały do innych pinów i przez diody do jednego pinu przerwania zewnętrznego.
    W przerwaniu będę sprawdzał i zliczał zmiany stanów na tych pinach, co w (mojej) teorii powinno dać dobre wyniki.

    2) Wyprowadzę sygnały do innych portów i w przerwaniu od timera będę sprawdzał i zliczał zmiany stanów.

    Bardziej skłaniałbym się do rozwiązania 1. Zliczanie impulsów z tych dwóch czujników jest jedna z ważniejszych rzeczy w projekcie, a przerwania INT0 i INT1 mają najwyższy priorytet wśród przerwań. Dzięki temu mam pewność, że nie zgubię żadnego sygnału.

    Proszę o sugestię, jak mogę rozwiązać ten problem.
    Z góry dzięki.
  • Pomocny post
    #2 17519020
    Konto nie istnieje
    Konto nie istnieje  
  • #3 17519063
    l1715s
    Poziom 9  
    StaryUczen napisał:
    Rozwiązanie 1 jest złe. Gdy sygnał A przyjmie poziom aktywny (niski), obsłużysz przerwanie a po chwili sygnał B poziom aktywny w sytuacji gdy A cały czas ma poziom niski, to ne zauważysz sygnału B. Podobnie gdy B aktywny, obsługa przerwania, B i A aktywny. W takich sytuacjach będziesz widział tylko jeden z sygnałów.

    Co do gubienia przerwania INT 1, pokaż kod programu przerwań INT0 i INT1.


    Masz racje, pomysł pierwszy odpada. Jak mogłem o tym nie pomyśleć.
    Co do programu, to proszę:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Czy jest jakiś sposób, aby liczyć sygnały korzystając z przerwań zewnętrznych i nie martwić się o sytuacje, kiedy sygnał nadejdzie idealnie w tym samym czasie?
    Pewnie taka sytuacja nigdy nie nastąpi, biorąc pod uwagę małą częstotliwość ich występowania, ale jednak istnieje takie ryzyko.
  • Pomocny post
    #4 17519087
    kamyczek
    Poziom 38  
    Nawet jeśli wystąpią w tym samym czasie wyższy priorytet ma int0 i jak się wykona to przerwanie powinno się wykonać INT1 . Jeśli chcesz zmniejszyć ryzyko zwiększ częstotliwość zegara .
  • #5 17519107
    l1715s
    Poziom 9  
    kamyczek napisał:
    Nawet jeśli wystąpią w tym samym czasie wyższy priorytet ma int0 i jak się wykona to przerwanie powinno się wykonać INT1 . Jeśli chcesz zmniejszyć ryzyko zwiększ częstotliwość zegara .


    Teraz Atmega działa na wewnętrznym kwarcu 8MHz.
    Wieczorem spróbuję z kwarcem 16 MHz, zobaczę czy jest różnica.

    Jak pisałem wcześniej, teraz sygnał podłączony jest do dwóch pinów równocześnie, czasami jedno z przerwań się nie wykonuje.
    W docelowym projekcie, czujnik ma liczyć obroty, dość wolno obracającej się ośki. Chcę założyć na ośkę dysk z jednym wycięciem, a przy dysku wspomniany czujnik.
    Wystarczy mi jeden impuls na obrót, może zrobię dwa, duża precyzja nie jest wymagana.
    Szczerze wątpię, żeby impulsy zgrały się idealnie w czasie, jak ma to miejsce teraz, kiedy przerwania wyzwala dokładnie ten sam impuls.

    Pytanie (teraz dopiero mi przyszło do głowy):
    czy problem może powodować zasilanie?
    Układ zasilany jest z USB komputera przez programator USBASP.
    Gdzieś czytałem, że na USB mogą być spore skoki napięć.
    Wieczorem podłączę układ pod jakiś konkretny zasilacz i zobaczę efekty.
  • Pomocny post
    #6 17519139
    Konto nie istnieje
    Konto nie istnieje  
  • Pomocny post
    #7 17519179
    Bielak_solid
    Poziom 14  
    Poniższy zapis:
    
    ISR (INT0_vect) {
    }
    


    Oznacza, że deklarujesz funkcję/kod obsługi przerwania INT0 trybie blokującym (ISR_BLOCK). Oznacza to, że jeśli w trakcie wykonywania funkcji obsługującej przerwanie INT0 pojawi się inne przerwanie, np INT1 to nie zostanie ono obsłużone. Rozwiązaniem może być deklaracja ISR z atrybutem ISR_NOBLOCK. W tym przypadku przerwania są włączone zaraz po skoku do funkcji obsługi przerwania. Można to sobie podejrzeć w deassemblowanym pliku.

    Pamiętaj, że w trybie ISR_NOBLOCK może dojść do przepełnienia stosu jeśli przerwania będą się pojawiać zanim bieżące nie zostanie obsłużone. W takich sytuacjach warto sobie wstawić jakiś licznik zliczający zagłębienie wywołań.
  • #8 17519195
    Konto nie istnieje
    Konto nie istnieje  
  • #9 17519218
    artwa
    Poziom 13  
    Ustawione flagi od INT0 się nie skasują się w INT1 i odwrotnie. Dla pewności proponuję sprawdzać flagę przerwania INT1 w ISR(INT0) oraz INT0 w ISR(INT1). Można też sprawdzić stany pinów w tych przerwaniach, choć tu można nie trafić - nie wiem, jak długie to impulsy. Na LCD można wyświetlić wtedy 4 liczniki. Jeśli tu nie będzie ich widać, to raczej ,,sprzęt" tego nie widzi - INT0 i 1 są asynchroniczne.
    Podejrzenie kodu asm wygenerowanego przez kompilator jasno pokaże, które flagi są czyszczone w ISR().

    BTW: ten LCD ma być uaktualniany z przerwą 30ms? Rozumiem, że to _delay_ms to tylko tymczasowo. Sugeruję timer, albo własną flagę ustawianą w przerwaniu, która nadpisze LCD (prościej niż konfigurowanie timera).
  • #10 17519271
    l1715s
    Poziom 9  
    artwa napisał:
    BTW: ten LCD ma być uaktualniany z przerwą 30ms? Rozumiem, że to _delay_ms to tylko tymczasowo.

    Oczywiście, cały przedstawiony program jest tymczasowy i służy wyłącznie do testowania przerwań.


    StaryUczen napisał:
    ISR zamień na INTERRUPT albo do ISR dodaj atrybut ISR_NOBLOCK.
    Jakie czasy maja impulsy na wejściach INT?


    Dzięki za ciekawy trop, wieczorem przetestuję i dam znać.

    Nie wiem jak długo trwają impulsy.
    Pochodzą one z czujnika szczelinowego. Stan wysoki utrzymuje się kiedy transoptor jest zasłonięty, przechodzi na niski, kiedy "zobaczy" źródło światła po drugiej stronie szczeliny.
    Przerwanie ustawione jest na zbocze opadające, więc czas jest uzależniony od szybkości zasłaniania i odsłaniania transoptora i od szerokości szczeliny.
  • #11 17519279
    Konto nie istnieje
    Konto nie istnieje  
  • #12 17519329
    l1715s
    Poziom 9  
    StaryUczen napisał:
    To będą długie(z punktu widzenia uC) czasy.Sprawdź jednak, czy nie ma oscylacji bo jak nic nie wiadomo o czujniku, to nie można stwierdzić czy ma jakiś układ formowania impulsów czy nie.


    Jedyne co wiem, to to, że na płytce czujnika znajduje się komparator LM393.
    Na wyjściu czujnika są dwa sygnały, cyfrowy i analogowy, podejrzewam, że cyfrowy wychodzi z komparatora a analogowy bezpośrednio z transoptora. Musiałbym się dokładniej przyjrzeć układowi.
    Jednak podłączałem obydwa sygnały (nie jednocześnie) i efekty były podobne.
    Co ciekawe, a może i ważne, to to, że kiedy sygnał brałem z wyjścia cyfrowego, to zmienna z INT0 zawsze pokazywała dwa razy większą wartość - wie ktoś może dlaczego?
    Dopiero po podłączeniu do wyjścia analogowego liczniki pokazywały równe ilości sygnałów.
  • #13 17519370
    Konto nie istnieje
    Konto nie istnieje  
  • #14 17519633
    l1715s
    Poziom 9  
    StaryUczen napisał:
    Wrzuć na forum ekran z oscyloskopu.

    Niestety nie dysponuje...
  • #15 17519770
    ex-or
    Poziom 28  
    Być może objaw nie jest skutkiem niewykonującego się przerwania od INT1, które w tej konfiguracji "nie ma prawa" nie wystąpić, ale "drgania styków". Być może ponieważ INT1 wykonuje się z opóźnieniem w stosunku do INT0 to do tego czasu stan na wyjściu czujnika jest już ustalony więc zlicza mniej zboczy. Do hipotezy pasuje mi np. stwierdzenie:
    l1715s napisał:
    kiedy sygnał brałem z wyjścia cyfrowego, to zmienna z INT0 zawsze pokazywała dwa razy większą wartość - wie ktoś może dlaczego?
    (chociaż nie do końca pasuje mi to ;-):
    l1715s napisał:
    Dopiero po podłączeniu do wyjścia analogowego liczniki pokazywały równe ilości sygnałów.
    )
    Gdybyś miał oscyl, to można by to łatwo zweryfikować. Ewentualnie sprawdzić choćby ladajakim analizatorem logicznym. Może chociaż zrób jeden impuls na czujniku i zobacz ile się zliczyło w programie?
  • #16 17519899
    l1715s
    Poziom 9  
    Sam już nie wiem co jest.
    Poniżej krótki filmik z działania układu (ze specjalnie przygotowaną karą z otworami), widać różne zliczanie impulsów:




    Po drodze z pracy wpadł mi do głowy pomysł, żeby wygenerować impulsy z dowolnego portu i podłączyć jednocześnie do pinów przerwań zewnętrznych.
    Na filmie poniżej impulsy co ok 10 ms, ale równie dobrze działało przy 1ms. Nie zgubiło żadnego impulsu.




    Więc teorię o nie wykonywaniu przerwania można odpuścić.

    Macie może pomysł jak i czym pewnie można zliczać obroty?
  • #17 17519962
    Konto nie istnieje
    Konto nie istnieje  
  • #18 17520084
    l1715s
    Poziom 9  
    StaryUczen napisał:
    No to musisz kupić. To podstawowe narzędzie do pracy w dzisiejszych czasach. Bez sprzętu to wróżenie z fusów.


    Kiedyś widziałem coś na kształt oscyloskopu, podłączane do gniazda mikrofonu w komputerze i odpowiedni program.
    Czy coś takiego w ogóle przyda się do czegoś? Biorąc pod uwagę moje amatorskie potrzeby.
  • #19 17520094
    Konto nie istnieje
    Konto nie istnieje  
  • #20 17520515
    l1715s
    Poziom 9  
    Problem może nie rozwiązany całkowicie, ale sprowadzony do akceptowalnego poziomu.

    Dodałem pomiędzy GND a wyjście cyfrowe czujnika kondensatory ceramiczne o łącznej pojemności ok 200nF.
    Wcześniej wspominałem, że zliczając impulsy z wyjścia cyfrowego z INT0 miałem zawsze dwa razy więcej na liczniku.
    Teraz zawsze jest tyle samo, przy dość szybkiej zmianie stanów czujnika, przerwania prawidłowo zliczają ilość impulsów, czasami (1 na ok 500) ucieka jeden.
    Przy bardzo szybkiej zmianie trochę częściej. Nie mniej jednak, to jak układ działa teraz jest akceptowalne.
    Teraz impuls dociera do INT0 i INT1 idealnie w tym samym czasie, docelowo będą docierały niezależnie, z dwóch czujników i istnieją nikłe szanse, że dotrą idealnie w tym samym momencie.
    Nawet jak się tak zdarzy, to będzie to bardzoo rzadkie zjawisko.

    Dziękuję wszystkim za cenne rady, pomoc i zaangażowanie.
  • #21 17521334
    tmf
    VIP Zasłużony dla elektroda
    Większość powyższych porad jest kompletnie błędna. Przede wszystkim, jak już zauważyłeś, podejrzenie, że problem wynika z jednoczesnego złoszenia dwóch przerwań można między bajki włożyć. Każde przerwanie ma swoją flagę i przy jednoczesnym zgłoszeniu dwóch przerwań, jedno (o wyższym priorytecie) jest obsługiwane, a obsługa drugiego jest odwlekana do zakończenia obsługi tego pierwszego. Jedyna możliwość zgubienia przerwania zachodzi w sytuacji, gdy to samo przerwanie jest zgłoszone dwukrotnie, a drugie zgłoszenie wystąpiło w sytuacji, w której pierwsze nie zostało jeszcze obsłużone. W twoim przypadku taka sytuacja miałaby miejsce, gdybyś generował impulsy z częstotliwością podchodzącą pod megaherce, a nie przy takim ręcznym przesuwaniu karty z dziurkami.
    Fakt, że impulsy generowane przez MCU są zliczane poprawnie, sugeruje, że problem wynika ze złego kształtu impulstów generowanych przez twój moduł transoptora. Tu oczywiście oscyloskop by pomógł, ale wobec faktu, że dowody wskazują na użyty moduł jako źródło problemów, nie ma potrzeby tej hipotezy testować - możemy przyjąć to za pewnik. Problem wynika zapewne z tego, że na wyjściu nie masz przebiegu odpowiadającego poziomom logicznym użytego MCU. Na wejściach AVR są przerzutniki Schmitta, jednak każdy pin może mieć ciut inny poziom przełączania. Jeśli na wyjściu z modułu masz napięcie na granicy poziomu wysokiego, to na jednym pinie ono może być zawsze rozpoznawane poprawnie, a na innym już niekoniecznie. I stąd problem. Przydałby sie schemat tego modułu. A najprościej to nie kombinować, tylko użyty transoptor szczelinowy podłączyć bezpośrendio do wejścia MCU. Zapewne odbiornikiem w nim jest fototranzystor czuły na podczerwień, więc spokojnie nim wysterujesz bezpośrednio wejście MCU.
    Pomysły typu ISR z NO_BLOCK są dupełnie zbedne i nie rozwiązują problemu, bo jak już wiemy nie leży on w jednoczesnym wywoływaniu przerwań.
    Na przyszłość, abstrahując od twojego problemu, warto do takich rzeczy angażować sprzęt - czyli podać impulsy na wejście zegarowe timera, dzięki czemu będzie on je zliczał sprzętowo. Oczywiście przy twoim układzie, gdzie impulsy nie mają wysokiej częstotliwości nie jest to niezbędne, niemniej, gdybyś w przyszłosci chciał zliczać impulsy, pojawiające się z częstotliwością porównywalną do taktowania MCU, to rozwiązanie jest najlepsze. W MCU zapewne masz też komparator, który można wykorzystać do kondycjonowania sygnału z optoelementu - też warto rozważyć jego użycie, jeśli częstotliwość impulsów jest duża.
    W twom programie testowym jest jeszcze jeden poważny błąd, który czasami może doprowadzić do dramatycznych przekłamań odczytów. A mianowicie dostęp do zmiennych cnt_... Otóż w pętli głównej nie jest on atomowy - zastanów się co się stanie jeśli w chwili odczytu tej zmiennej nastąpi przerwanie, w którym ją zinkrementujesz. Szczególnie ciekawy efekt wystąpi, gdy jej mniej znaczące 8 bitów będzie miało wartość 0xff...
REKLAMA