Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[ATMEGA32][BASCOM] - Przerwania zagnieżdżone - LCD razem z INT0

glu80 11 Apr 2013 14:29 2514 7
  • #1
    glu80
    Level 2  
    Witam forumowiczów,
    Natknąłem się na pewien problem, z którym nie wiem jak sobie poradzić. Sprawa dotyczy nieprawidłowej obsługi przerwania INT0 podczas wykonywania komend sterujących wyświetlaczem LCD.

    Do Atmega32 podłączone są:
    - standardowy wyświetlacz LCD,
    - źródło impulsów (dokładniej jest to liniał cyfrowy),
    - przyciski.
    Impulsy wprowadzone na pin INT0 mają wywoływać procedurę odczytu stanu z dwóch innych wejść, wykonywana jest prosta operacja (zliczanie kroków w przód lub w tył) a wynik wyświetlany na LCD.

    Jest to programowo zrealizowane w oparciu o dwa osobne przerwania i pętlę:
    1. przerwanie INT0, wywoływana jest procedura odczytu stanu na wejściach i odpowiednio zwiększany lub zmniejszany jest wynik. Impulsy pojawiają się dosyć gęsto, nawet co około 20 us (mikrosekund), ale przeważnie odstępy są większe. Czas wykonywania podprogramu obsługi tego przerwania zajmuje 250 cykli zegara, co daje jakieś 15us przy zegarze 16MHz.



    2. przerwanie TIMER0, użyte jest do odświeżania wyświetlacza. Przerwanie wyskakuje co 16ms, ale tylko co 12-te wywołanie jest odświeżany LCD, czyli mniej wiecej 5x na sekundę. Zawartość wyświetlacza jest konstruowana "na żywo" na podstawie aktualnej wartości zmiennych.

    3. Pętla główna, gdzie obsługiwane są tylko przyciski.


    PROBLEM polega na tym, że część impulsów które trzeba zliczać jest gubiona. Przy odświeżaniu wyświetlacza 5x na sekundę gubi się około 20% impulsów, bez względu na częstotliwość impulsów wyzwalających INT0 (przy założeniu, że nie są krótsze od pewnej granicznej wartości).

    Nie jest to na pewno spowodowane zbyt małymi odstępami pomiędzy wywołaniami INT0. Można to łatwo sprawdzić, co też zrobiłem na dwa sposoby:
    - wyłączam przerwanie TIMER0, natomiast wyświetlacz odświeżam przyciskiem, otrzymuję wynik dokładny, czyli wszystkie impulsy są zliczane
    - spowalniam odświeżanie na przykład do 1x na sekundę albo jeszcze wolniej, w efekcie gubionych jest odpowiednio mniej impulsów.


    Wydaje mi się, że podczas wykonywania komend obsługujących LCD (Locate, Lcd) dzieje się jedna z dwóch rzeczy:
    a) przerwania zewnętrzne są wyłączane (nie są obsługiwane przerwania, które są zagnieżdżone jedne w drugich),
    b) brakuje miejsca na zapisanie stanu programu, zapełnia się jakiś stos albo coś takiego (?)
    Tak ma być czy robię coś źle? Jakieś pomysły o co może chodzić i jak podejść do problemu?
  • Helpful post
    #3
    emarcus
    Level 38  
    glu80 wrote:


    Wydaje mi się, że podczas wykonywania komend obsługujących LCD (Locate, Lcd) dzieje się jedna z dwóch rzeczy:
    a) przerwania zewnętrzne są wyłączane (nie są obsługiwane przerwania, które są zagnieżdżone jedne w drugich),
    ...............)
    Tak ma być czy robię coś źle? Jakieś pomysły o co może chodzić i jak podejść do problemu?



    Pokaż gdzie i jak masz zaprogramowaną obsługę LCD.
    -Nie robisz chyba tego w przerwaniu ?
    Możesz to umieścic w programie głównym lub subrutynie do której wejście byłoby warunkowane flagą.

    Jeżeli przerwania z jakiegokolwiek powodu występują relatywnie często, to ich obsługa winna byc ograniczona do minimum, - inaczej cos będzie gubione.
    Należy unikac "zanieżdżania" przerwań.
    Normalnie, podczas obsługi przerwania wszystkie ewentualnie występujące przerwania są 'zawieszone' do czasu jej ukończenia (Return) i wtedy są zwyczajnie pomijane (gubione).

    e marcus
  • #4
    BlueDraco
    MCUs specialist
    Masz błąd w samej koncepcji. Przyciski obsługuj w przerwaniu timera, a LCD w pętli głównej. Nie możesz czekać na LCD w przerwaniu, a testowanie przycisków bez bazy czasu to nieporozumienie.
  • #5
    glu80
    Level 2  
    Na wstępie dziękuję za zainteresowanie moim problemem.

    dondu
    Nie da się tak. Być może nie napisałem tego precyzyjnie, w każdym razie impulsy które wchodzą na INT0 są tylko informacją, że wystąpił krok w prawo lub w lewo. W tym momencie analizując stan dwóch innych wejść (aktualny i sprzed zmiany) trzeba ustalić czy pomiar ma być zwiększony czy zmniejszony o krok.

    emarcus
    LCD obsługuję tak:
    Dim Droga As Long
    Dim Tmp As String * 6
    Dim Tymcz As Single

    Code:
    Config Timer0 = Timer , Prescale = 1024
    
    On Timer0 Przerw_wyswietlacz
    ...
    Przerw_wyswietlacz:
       Pomocn_wysw = Pomocn_wysw + 1
       If Pomocn_wysw > 12 Then
          Pomocn_wysw = 0
          Locate 1 , 1
          Tymcz = Droga / 1000
          Tmp = Fusing(tymcz , " ##.&&&")
          Lcd Tmp ; "  "
    Return


    Jeśli jest tak jak piszesz:
    Quote:
    Normalnie, podczas obsługi przerwania wszystkie ewentualnie występujące przerwania są 'zawieszone' do czasu jej ukończenia (Return) i wtedy są zwyczajnie pomijane (gubione).

    to wszystko byłoby jasne... Spróbuję zrobić tak jak sugerujecie, w przerwaniu ustawiana będzie tylko flaga dla LCD. Zobaczę i dam znać.
  • #6
    emarcus
    Level 38  
    glu80 wrote:

    Tmp = Fusing(tymcz , " ##.&&&")


    Raczej może tak:

    Tmp = Fusing(tymcz , "#.&&&")

    Przed kropką tylko jeden znak 'hash', niezależnie jak wielka liczba.

    e marcus
  • #7
    SylwekK
    Level 32  
    Kurcze, taka obsługa LCD w przerwaniu to wg mnie marnotrawstwo przerwania. Przecież to w pętli głównej powinno być. Tak się nie powinno robić. Komendy wyświetlacza są czasochłonne i jak Ci to w krew wejdzie to się zaplątasz w końcu.
  • #8
    glu80
    Level 2  
    Dzięki kolego emarcus za trafną sugestię. Zmiana koncepcyjna i jest OK. Odpisuję późno bo czasu jakoś było brak...

    Poprawny kod, być może przyda się w przyszłości komuś kto będzie miał podobny problem:


    Code: basic4gl
    Log in, to see the code