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.

Jeśli nie przerwanie od przycisku to co?

szymonjg 29 Mar 2017 18:07 453 7
  • #1 29 Mar 2017 18:07
    szymonjg
    Poziom 15  

    Witam.
    Czyniąc historię krótką, buduję prosty analizator logiczny na PIC18LF46K80, który w najszybszym trybie zbiera próbki z PORTB z częstotliwością 8MHz co zużywa całą moc CPU. Funkcja samplująca o której mowa wygląda w skrócie tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod



    Konstrukcja tej funkcji wynika z faktu, że koniecznie chcę zarejestrować pierwsze zbocze wyzwalające i to co się działo choćby jedną próbkę przed nim. W międzyczasie nie chcę stracić zbyt wiele próbek na inne czynności dlatego sprawdzam tylko jedną flagę od pinu RB0/INT0, która ustawi mi się automatycznie po wystąpieniu żądanego zbocza. Przerwanie od pinu INT0 mam wyłączone.
    Jak widać powyższa funkcja ma tę wadę, że jeśli z nie zależnych od uC przyczyn nie będzie żadnego przebiegu na pinie RB0 i flaga INT0IF nie zostanie ustawiona to program mam praktycznie zawieszony przez pętlę while(1), która bynajmniej nie znajduje się tutaj przypadkowo bo po przekompilowaniu na język maszynowy zajmuje tylko 2 takty CPU. Nie mogę (a przynajmniej nie potrafię) jej zastąpić czymś innym co by zajmowało równie mało czasu CPU a zarazem rozpoczynało zapis bufora od początku w przypadku nie wystąpienia zbocza synchronizującego plus dodatkowo sprawdzałoby stan przycisków. Przycisk bowiem jest mi potrzebny aby aby odwiesić program w momencie gdyby przez dłuższy czas nie było okazji na ustawienie flagi INT0IF, a jednak wymagana by była interakcja z urządzeniem. Oczywiście mam 3 przyciski, których stan sprawdzam cyklicznie w przerwaniu timera2 zgodnie ze sztuką (a przynajmniej prawie (w każdym razie, działa)), ale na czas włączenia odczytu muszę to przerwanie wyłączyć ponieważ nie mogę sobie pozwolić na cykliczne przerwy podczas samplowania. Po różnych wzlotach i upadkach postanowiłem mimo wszystko przejść na ciemną stronę programowania i dołożyć dodatkowy czwarty przycisk obsługiwany bezpośrednio przez przerwanie wyzwalane zboczem pinu do którego ten przycisk jest podłączony. Rolą tego przycisku ma być anulowanie samplowania i zakończenie funkcji samplującej poprzez programowe ustawienie flagi INT0IF.
    I tu nasuwa się moje pytanie: Czy naprawdę jest to rozwiązanie tak karygodne, że nawet w drodze wyjątku w tym przypadku nie wypada go użyć? Jeśli tak, to czy zna ktoś jakiś inny sposób którym można rozwiązać przedstawiony przeze mnie problem?

    0 7
  • Pomocny post
    #2 29 Mar 2017 18:50
    dondu
    Moderator Mikrokontrolery Projektowanie

    Nie ma jednej, jedynie słusznej drogi.
    Każdą funkcjonalność można opracować na wiele sposobów.
    Jeśli potrzebujesz podłączyć przycisk do przerwań zewnętrznych, możesz to oczywiście zrobić.
    Po to one są, by z nich korzystać, byle świadomie :)

    Istotne jest tylko jedno - program ma działać tak jak tego sobie życzysz i spełniać założenia projektowe.


    Edit:

    Dodam tylko jeszcze, byś w przerwaniu INT wyłączył przerwania z tego INT, by kolejny raz się nie wykonywały od drgań styków, a włączył je tylko przed rozpoczęciem zapisywania próbek.

    0
  • #3 29 Mar 2017 19:08
    BlueDraco
    Specjalista - Mikrokontrolery

    No i właśnie nie mogę nic zmienić, bo się zmoderowało, a to był jedynie szkic i początek tego, co chciałem napisać.

    Aha, się skasowało, więc mogę pisać od nowa. To już nie powtarzam o przerwaniu timera, bo się znów wymoderuje.

    Coś się w tym algorytmie nie trzyma kupy. Wciśnięcie przycisku zajmuje człowiekowi czas rzędu 1-10 sekundy (ok, przy trzymaniu palca na guziku daje się zejść do 1/40). Przez 1/40 sekundy przy 8 MHz próbkowaniu można zarejestrować 200 tysięcy próbek, a bufor mamy na kilka tysięcy. No to co my tu udajemy? Jakie użyteczne dane można złapać w parę kB pamięci po wyzwoleniu z palca próbkowania 8 MHz?

    Nawet jeśli to nie palec naciska ten przycisk, tylko jakaś maszyna, to i tak precyzja czasowa zadziała nie przycisku jest na poziomie milisekund, czyli bufor raczej nie będzie zawierał tego, co byśmy chcieli.

    Dalej:
    Na moje wyczucie liniowa sekwencja zapisów kolejnych elementów tablicy wykona się raczej wolniej niż zapisy w pętli ze zmiennym indeksem lub (lepiej) wskaźnikiem. Czemu ma służyć ten długi ciąg identycznych instrukcji, z których każda ładuje adres absolutny? Bo raczej nie przyspieszeniu zapisów, a ich spowolnieniu.

    0
  • #4 29 Mar 2017 20:40
    szymonjg
    Poziom 15  

    BlueDraco napisał:
    Coś się w tym algorytmie nie trzyma kupy. Wciśnięcie przycisku zajmuje człowiekowi czas rzędu 1-10 sekundy (ok, przy trzymaniu palca na guziku daje się zejść do 1/40). Przez 1/40 sekundy przy 8 MHz próbkowaniu można zarejestrować 200 tysięcy próbek, a bufor mamy na kilka tysięcy. No to co my tu udajemy? Jakie użyteczne dane można złapać w parę kB pamięci po wyzwoleniu z palca próbkowania 8 MHz?


    Tak. Ale przypomnę o funkcji tego czwartego przycisku, którą ma być anulowanie odczytu, gdy czekanie na flagę trwa zbyt długo. Natomiast przy normalnej pracy tego algorytmu jeśli użytkownik cierpliwie poczeka na zbocze i nie tknie przycisku przerywającego proces to po wystąpieniu zbocza cały bufor zostanie zapełniony bez zakłóceń gubiąc tylko jedną próbkę na sprawdzenie flagi INT0IF. Algorytm nie jest idealny, ale szybszego na obecną chwilę nie udało mi się wymyślić.
    3KB pamięci nie przeskoczę bo ogranicza mnie RAM MCU, ale oczywiście przewidziałem tryby wolniejszego samplowania, aby rejestrować dłuższe przebiegi.
    Tryb 2MHz wykonuję puszczając tryb 8MHz z czasowo wyłączoną pętlą PLL.
    Potem mam tryb 480kHz i tu pomimo, że na przerwania jeszcze było za szybko to już znalazło się miejsce na sprawdzanie stanu przycisków:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Przy czym ilość instrukcji i nopów została dobrana tak by odczyt następował dokładnie co 33 takty CPU co sprawdziłem na puszczonym równolegle TIMER4 z PR4=32. Choć tu muszę się przyznać że sprawdziłem to tylko w jednym trybie kompilacji bez włączania żadnych optymalizacji kodu, bo okazuje się, że nawet w bezpłatnej wersji kompilatora C18 coś tam można po optymalizować.
    Jeszcze wolniejsze tryby wykonuję w przerwaniu wysokiego poziomu od TIMER3 i tam już mam czas na wszystko.
    Także jak widać nikogo nie oszukuję. :)


    BlueDraco napisał:
    Na moje wyczucie liniowa sekwencja zapisów kolejnych elementów tablicy wykona się raczej wolniej niż zapisy w pętli ze zmiennym indeksem lub (lepiej) wskaźnikiem. Czemu ma służyć ten długi ciąg identycznych instrukcji, z których każda ładuje adres absolutny? Bo raczej nie przyspieszeniu zapisów, a ich spowolnieniu.

    No właśnie na przyspieszeniu, bowiem taka sekwencja w skrócie kompiluje mi się na coś takiego:
    Jeśli nie przerwanie od przycisku to co?
    i dzięki temu że nie robię tego np w pętli for( ; ; ), cpu nie zużywa czasu na odczyt i inkrementację licznika oraz ustawienie odpowiedniego adresu komórki bufora w zależności od tego licznika. Choć trzeba zaznaczyć, że takie podanie procesorowi adresów na tacy zajmuje trochę kB we Flashu, ale coś za coś.






    dondu napisał:
    Dodam tylko jeszcze, byś w przerwaniu INT wyłączył przerwania z tego INT, by kolejny raz się nie wykonywały od drgań styków, a włączył je tylko przed rozpoczęciem zapisywania próbek.

    Jeśli chodzi o flagę INT0IF o której mowa w ww funkcji to przerwanie od niej jest wyłączone zawsze wyłączone a odczytuję ją tylko w tej funkcji. Jeśli natomiast chodzi o to przerwanie które ma wyzwalać ten felerny przycisk to kod jego obsługi obecnie wygląda tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Przy czym przycisk mam podłączony do wejścia modułu CCP2 ustawionego w trybie Capture every rising edge. I właściwie to drgania styków nie są mi groźne w tym przypadku bo to czy to przerwanie wykona mi się raz czy 100 razy, nie ma dla mnie dużej różnicy. Ważne że samplowanie będzie anulowane a odpowiednie zmienne będą miały takie wartości jakie sobie życzę.
    Ale w sumie pomyślę o tym, bo poza przerywaniem funkcji samplującej już nie potrzebuję tego przerwania od przycisku, a równie dobrze mogę wtedy stan tego przycisku odczytywać tak jak pozostałych.
    Jedynie czego się boję i o co w sumie już dziś pytałem, to że mi następne przerwanie przerwie wykonywanie poprzedniego zanim ono się skończy i tak w kółko, aż do przepełnienia stosu. Ale chyba tak się nie dzieje bo w bitach konfiguracyjnych mam włączoną opcję: "Stack Overflov Reset" i jak na razie nie zauważyłem niechcianych resetów. Ale to w sumie też jest do sprawdzenia po podłączeniu generatora zamiast przycisku. :)

    0
  • #5 29 Mar 2017 20:52
    dondu
    Moderator Mikrokontrolery Projektowanie

    Nie musi to być stricte funkcja przerwania tylko sprawdzanie flagi przerwania w pętli, która zapisuje wyniki.
    Po wykryciu przerwania INT od przycisku niech od razu zablokuje to przerwanie i zgasi jego flagę.

    0
  • #6 29 Mar 2017 21:03
    szymonjg
    Poziom 15  

    No właśnie w pętli zapisującej wyniki chciałbym (jeśli to tylko możliwe) sprawdzać jak najmniej flag tak by mieć jak największe szanse na zarejestrowanie pierwszego zbocza w przebiegu, które właśnie w tym momencie mogło by wystąpić. Dlatego wszelkie czynności nie niezbędne do działania tej funkcji chciałbym przenieść gdzie indziej, a zwłaszcza sprawdzenie stanu przycisku, który ma być używany tj. awaryjnie już w sytuacji ostatecznej gdy użytkownik z własnej woli zrezygnuje z rejestracji przebiegu.

    0
  • #8 29 Mar 2017 21:14
    szymonjg
    Poziom 15  

    Racja. Dlatego jedną, jedyną flagę przecież sprawdzam (w pierwszym poście jest kod o którym mówię). W przerwaniu ustawiam kilka zmiennych i między innymi też tą flagę ustawiam na warunek zakończenia funkcji samplującej. Nie chcę natomiast sprawdzać dodatkowej flagi od przycisku i stąd mi się wzięło to przeklęte przerwanie generowane przez przycisk.

    0