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.

Atmega32, C - Przerwania INT0 i INT1 - Co tu nie gra?

martin_cb 14 Lis 2013 23:32 2376 20
  • #1 14 Lis 2013 23:32
    martin_cb
    Poziom 9  

    Witam szanownych kolegów. Piszę z prośbą o pomoc w następującym problemie.
    Sprawa dotyczy mikrokontrolera Atmega32, konkretnie zewnętrznych przerwań INT0 i INT1. Wspomniany mikrokontroler steruje pracą większego urządzenia pomiarowego, którego jednym z zadań jest zliczanie impulsów pochodzących z zewnętrznego urządzenia. Impulsy są zbliżone do prostokątnych o częstotliwości od 20 do 200Hz. Z racji tego że, napisany przeze mnie kod jest bardzo rozbudowany, prezentuję tu jedynie fragmenty istotne dla tego problemu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Problemem jest błędne zliczanie impulsów. Dla celów testowych na oba wejścia (INT0 i INT1) jednocześnie podaję ten sam sygnał. Gdy usunę z kodu wszystkie instrukcje nie związane ze zliczaniem impulsów, wyniki są prawidłowe. Przykładowo:
    impulsy_A = 60 000 impulsów
    impulsy_B = 60 000 impulsów
    Natomiast gdy zaczynam dodawać do kodu poszczególne pozostałe fragmenty kodu ilość zliczonych impulsów zaczyna się coraz bardziej rozjeżdżać:
    impulsy_A = 59 900 impulsów
    impulsy_B = 60 000 impulsów
    Nie wiem czy obie zmienne są zaniżane bo nie mam możliwości zadania układowi dokładnej ilości impulsów, natomiast zawsze impulsy zliczone na przerwaniu INT0 są zaniżone w stosunku do tych zliczanych na przerwaniu INT1.
    Gdy tworzyłem program kierowałem się tą zasadą, że przerwania te są o najwyższym priorytecie i każdy przychodzący impuls na pewno zostanie zliczony bez względu na to w jakim zadaniu czy przerwaniu mikrokontroler aktualnie się znajduje. Czy byłby ktoś tak dobry wyprowadzić mnie z błędu?
    Mikrokontroler taktowany jest kwarcem 16MHz.

    0 20
  • #2 15 Lis 2013 00:33
    dondu
    Moderator Mikrokontrolery Projektowanie

    Witaj.

    Ciekawy eksperyment :)

    A jest tak:

    Cytat:
    The interrupts have priority in accordance with their Interrupt Vector position.
    The lower the Interrupt Vector address, the higher the priority.

    a w tabeli wektorów przerwań INT0 jest wyżej.

    Dlaczego zmienna TRYB nie jest volatile?

    Następne tematy umieszczaj w dziale mikrokontrolerów: https://www.elektroda.pl/rtvforum/forum12.html
    Poprosiłem moderatora by ten temat tam przeniósł.

    0
  • #3 15 Lis 2013 04:38
    dreamy
    Poziom 12  

    W przerwaniu INT1 wywołujesz funkcję start, która czyści bit INTF0 w rejestrze GIFR.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Jeżeli twój dodatkowy kod ustawia gdzieś TRYB = '2' i przerwanie INT1 zdarzy się minimalnie wcześniej, to możesz gubić jedno przerwanie INT0 na każde wywołanie funkcji start.

    0
  • #4 15 Lis 2013 08:54
    martin_cb
    Poziom 9  

    Dzięki za odpowiedzi.
    Zmienną TRYB nie dałem jako volatile, dlatego że wykonuję na niej operacje również w pętli głównej, a z tego co wiem volatile powinny być tylko te które wywoływane są przerwaniach.
    Zliczanie impulsów zachodzi tylko w trybach '1' i '3'. Funkcja start() wywoływana jest tylko raz przy przejściu do trybu '3', a w trakcie zliczania w kodzie nie są wykonywane żadne operacje na rejestrze GICR.

    Co do priorytetów przerwań...

    Cytat:

    The interrupts have priority in accordance with their Interrupt Vector position.
    The lower the Interrupt Vector address, the higher the priority.

    zastanawiałem się czy nie jest problemem to, że INT0 ma większy priorytet od INT1. Ale gdyby tak było to przecież zaniżałaby wtedy zmienna z przerwania INT1, gdyż to te impulsy byłyby pomijane gdy wystąpiłyby równocześnie z impulsami o wyższym priorytecie.

    0
  • #6 15 Lis 2013 09:41
    martin_cb
    Poziom 9  

    No tak, człowiek uczy się cale życie... Dodałem volatile do zmiennej TRYB, a później nawet do wszystkich zmiennych w programie ale nie wpłynęło to na poprawę działania programu. Problem dalej nierozwiązany :|

    0
  • #7 15 Lis 2013 10:01
    dondu
    Moderator Mikrokontrolery Projektowanie

    Być może inne przerwania realizowane w trakcie trwają zbyt długo.
    Niestety z fragmentów programu trudno wywnioskować przyczynę.

    0
  • #8 15 Lis 2013 12:49
    BlueDraco
    Specjalista - Mikrokontrolery

    Poza błędnym użyciem volatile szukałbym przyczyny w długim wykonaniu procedur przerwań i procedur wywoływanych z przerwań, których nie pokazałeś. W AVR mamy jednopoziomowy system przerwań, więc każde przerwanie blokuje obsługę każdego innego, a odblokowywanie przerwań podczas obsługi przerwań (SIGNAL) - to proszenie się o kłopoty. Przejrzyj wszystko, co dzieje się w przerwaniach.

    0
  • #9 15 Lis 2013 13:18
    tmf
    Moderator Mikrokontrolery Projektowanie

    martin_cb napisał:

    Nie wiem czy obie zmienne są zaniżane bo nie mam możliwości zadania układowi dokładnej ilości impulsów, natomiast zawsze impulsy zliczone na przerwaniu INT0 są zaniżone w stosunku do tych zliczanych na przerwaniu INT1.


    Owszem, masz taką możliwość - skorzystaj z symulatora dostępnego w Atmel Studio i wygeneruj mu potrzebny plik stymulacji, dzięki czemu dokładnie zobaczysz, gdzie co się gubi. Warto też sprawdzić w symulatorze czas wykonania ISR.

    martin_cb napisał:
    Gdy tworzyłem program kierowałem się tą zasadą, że przerwania te są o najwyższym priorytecie i każdy przychodzący impuls na pewno zostanie zliczony bez względu na to w jakim zadaniu czy przerwaniu mikrokontroler aktualnie się znajduje. Czy byłby ktoś tak dobry wyprowadzić mnie z błędu?
    Mikrokontroler taktowany jest kwarcem 16MHz.


    Jeśli MCU się nie wyrabia to gubi przerwania - masz tam tylko jednobitowe flagi, więc dwa kolejne przerwania, jeśli nie zostaną obsłużone, będą widziane jako jedno. Symulator pozwoli ci określić czas wykonania kodu.
    Z drugiej strony dlaczego liczysz te impulsy programowo, a nie podasz je na wejście zegarowe timera?

    0
  • #10 16 Lis 2013 13:08
    martin_cb
    Poziom 9  

    Podczas obsługi przerwań podczas zliczania impulsów nie dzieje się nic innego poza inkrementowaniem tych dwóch zmiennych. Wkleiłem je tu w całości tak jak są. Poniżej zamieszczam przebiegi czasowe zarejestrowane oscyloskopem. Na potrzeby sprawdzenia długości trwania obsługi przerwań dodałem do nich instrukcje ustawiające wyprowadzenie jednego z portów w stan "1" przy wejściu do przerwań i w stan "0" przy wyjściu z nich. Dzięki temu widać że obsługa przerwań trwa znikomo mało w porównaniu z częstością nadchodzenia kolejnych impulsów. Przy dłuższej obserwacji nie stwierdziłem, żeby wystąpił choć jeden impuls bez swojego "piku przerwania". Skąd więc te różnice w ilości zliczonych impulsów... ?

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Atmega32, C - Przerwania INT0 i INT1 - Co tu nie gra?

    Cytat:

    Z drugiej strony dlaczego liczysz te impulsy programowo, a nie podasz je na wejście zegarowe timera?

    Nie mogę zliczać impulsów timerami gdyż są one już zajęte do innych celów. Ogólnie zasoby tej Atmegi mam w tym momencie wykorzystane do tego stopnia, że gdybym chciał cokolwiek teraz zmieniać w układzie musiałbym raczej wszystko zaprojektować i zlutować od nowa. Dlatego też zależy mi aby układ zadziałał poprawnie w takiej konfiguracji jak teraz... :|

    0
  • #11 16 Lis 2013 13:13
    excray
    Poziom 39  

    Przebieg ma bardzo duży czas narastania. Na przebiegach widać coś takiego jakby przerwanie zostało wykonane 2 razy. Być może musisz przepuścić sygnały przez przerzutnik Schmitta aby ukształtował sygnał cyfrowy a nie taką postrzępioną przez zakłócenia narastającą falę.

    0
  • #12 16 Lis 2013 13:27
    BlueDraco
    Specjalista - Mikrokontrolery

    Zliczaj impulsy w przerwaniu timera zgłaszanym z częstotliwością znacznie większą od częStotliwości impulsów, np. kilka kHz. Możesz wtedy b. łatwo zrobić prohgramowe ignorowanie "zafalowań" na wejściach. Jaka jest szerokość impulsu?

    0
  • Pomocny post
    #13 16 Lis 2013 15:18
    dreamy
    Poziom 12  

    Cytat:
    Nie mogę zliczać impulsów timerami gdyż są one już zajęte do innych celów.
    A przerwań innych niż INT0, INT1 używasz?

    0
  • #14 16 Lis 2013 19:19
    martin_cb
    Poziom 9  

    Może faktycznie szum nałożony na zbocze jest tu przyczyną wielokrotnego wywołania przerwania przy jednym impulsie. W poniedziałek przyjrzę się dokładniej temu zboczu i spróbuje coś zaradzić. Ale z drugiej strony gdyby tak było, to dlaczego impulsy zliczane są prawidłowo wtedy gdy program okrojony jest do minimum?

    Cytat:
    Jaka jest szerokość impulsu?

    Maksymalna częstotliwość impulsów na pewno nie przekroczy 500Hz. Ich kształt jest zawsze zbliżony do tych widocznych na obrazku, a wypełnienie waha się od 50 do 80%.
    Cytat:
    A przerwań innych niż INT0, INT1 używasz?

    Przerwanie INT2 - przyciskiem na tym przerwaniu steruję przełanczaniem TRYBów pracy mikrokontrolera, jednak nie występuje ono w trakcie zliczania impulsów.

    ISR(USART_RXC_vect) - przerwanie od USARTa, sterowanie pracą mikrokontrolera z poziomu komputera, nie występuje w trakcie zliczania impulsów.

    TIMER1 - pracuje w trybie CTC i zblicza impulsy czasowe z RTC (32,768kHz) generując co sekundę krótkie przerwanie SIGNAL (SIG_OUTPUT_COMPARE1A).

    Interfejs TWI - pobranie co parę sekund kilku bajtów danych z sąsiedniej Atmegi16.

    Interfejs SPI - komunikacja z zewnętrznym przetwornikiem ADC

    Oprócz tego w trakcie zliczania wykonywane jest całe mnóstwo działań matematycznych, a chwilowe wyniki obliczeń i pomiarów na bieżąco przesyłane są po RS232 (9600 B/s) do komputera, więc mikrokontroler ma co robić, ale przecież to wszystko jest o niższym priorytecie niż INT0 i INT1...

    0
  • #15 16 Lis 2013 19:45
    BlueDraco
    Specjalista - Mikrokontrolery

    Powtórzę pytanie: czy masz jakieś inne przerwania? Jeśli tak, to przeczytaj mój poprzedni post w tym wątku i uwierz, że to jest właśnie przyczyna - w jednopoziomowym systemie przerwań jedno przerwanie nie przerywa drugiego.

    0
  • #16 16 Lis 2013 21:21
    martin_cb
    Poziom 9  

    Wszystkie przerwania których w tym programie używam podałem w poprzednim poście. Owszem obsługa przerwania nie może być przerwana przez inne przerwanie, ale jego zgłoszenie jest zapamiętane i zostaje obsłużone po zakończeniu obsługi tego pierwszego. Tak mi się przynajmniej wydaje, ale mogę się mylić. W moim programie żadne przerwanie nie trwa tak długo aby w trakcie jego obsługi zdążyło wystąpić więcej niż raz zgłoszenie przerwania INT0 lub INT2.
    A tak na marginesie czy informacje podane tu Link są błędne?

    Cytat:
    Mikrokontroler wykonuje załadowany program, a urządzenie, jeśli potrzebuje uwagi, zgłasza tzw. przerwanie. Wykonywany program zostaje wówczas zawieszony i wykonywana jest procedura obsługi przerwania. Gdyby w tym czasie pojawiło się przerwanie o wyższym priorytecie, procedura aktualnie wykonywanego przerwania zostaje zawieszona, wykonywana jest procedura przerwania o wyższym priorytecie, jeśli natomiast przerwanie ma niższy priorytet niż aktualnie wykonywane, wówczas wywołanie procedury jego obsługi czeka na zakończenie aktualnie wykonywanej procedury obsługi przerwania. Po zakończeniu obsługi przerwania program jest dalej wykonywany.


    Propozycja zliczania impulsów w przerwaniu licznika wydaje się bardzo ciekawa. W poniedziałek spróbuje sprawdzić tą alternatywę :)

    0
  • Pomocny post
    #17 16 Lis 2013 21:55
    tmf
    Moderator Mikrokontrolery Projektowanie

    Tak, są błędne. ATMega32 dysponuje jednopoziomowym systemem przerwań i aktualnie wykonywana funkcja obsługi przerwania nie może być przerwana. Chyba, że jawnie na to zezwoli odblokowując flagę I rejestru stanu. Z AVR dopiero XMEGA posiadają 3-poziomową obsługę przerwań.

    0
  • #18 16 Lis 2013 22:03
    dreamy
    Poziom 12  

    Szum na wejściach raczej nie jest problemem, każde wejście ma wbudowany przerzutnik schmitta.

    martin_cb napisał:
    Oprócz tego w trakcie zliczania wykonywane jest całe mnóstwo działań matematycznych,
    Gdzie są te obliczenia wykonywane? Jeśli w przerwaniu to być może trwa za długo.
    martin_cb napisał:
    a chwilowe wyniki obliczeń i pomiarów na bieżąco przesyłane są po RS232 (9600 B/s) do komputera
    Przesyłane po 1 bajcie czy pakietem, jeżeli pakietem to czy wysyłasz wykorzystując przerwanie UDRE? (możesz na chwilę zmienić BAUD na np. 250k)
    martin_cb napisał:
    więc mikrokontroler ma co robić, ale przecież to wszystko jest o niższym priorytecie niż INT0 i INT1...
    Priorytet oznacza tylko tyle, że jeżeli wystąpią 2 przerwania w tym samym czasie np. INT0 i INT1, to INT0 będzie obsłużone jako pierwsze. Ale jeżeli twój program aktualnie znajduje się w innym przerwaniu np. od SPI czy USART, to INT0 zostanie wykonane dopiero kiedy aktualnie obsługiwane przerwanie się zakończy.

    @edit: martin_cb dobrze myślisz.
    Co do tego cytatu, w AVRkach serii mega/tiny nie działa to w ten sposób, ale możesz uzyskać zagnieżdżone przerwania poprzez ISR_NOBLOCK, tylko że w przypadku błędu ryzykujesz przepełnieniem stosu.

    Może dodaj do każdego przerwania busy flag:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    od razu będziesz widział, czy gdzieś blokuje

    @edit: tmf był szybszy.

    0
  • #19 16 Lis 2013 22:17
    martin_cb
    Poziom 9  

    No tak, system przerwań przynajmniej dla mnie nie jest łatwym zagadnieniem, szczególnie jeśli nawet w wydawałoby się pewnych źródłach są błędne informacje... Teraz już mi się to w miarę rozjaśniło i faktycznie z powodu innych przerwań impulsy mogą być źle zliczane. Przede wszystkim spróbuję rozwiązania zaproponowanego przez BlueDraco, czyli zliczanie impulsów w przerwaniu timera.

    0
  • #21 18 Lis 2013 20:28
    martin_cb
    Poziom 9  

    Problem rozwiązany. Wykorzystałem propozycję BlueDraco, czyli zliczam impulsy w przerwaniu Timera. Zastosowałem Timer0 z preskalerem 64. Mimo iż przerwanie generowane jest znacznie częściej niż przedtem a i w przerwaniu troszkę więcej kodu to procek i tak się ze wszystkim wyrabia i co najważniejsze impulsy są zliczane poprawnie. :D
    Dzięki wszystkim, którzy zaangażowali się w pomoc. Pozdrawiam!

    0
  Szukaj w 5mln produktów