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

[ATMega168][C] Obsługa przerwań

Stefan90 16 Gru 2011 00:43 4340 31
  • #1 16 Gru 2011 00:43
    Stefan90
    Poziom 7  

    Witam,

    Na początku zaznaczę, choć oczywiście wierzyć mi nie musicie, że przewertowałem przynajmniej kilkadziesiąt witryn internetowych w poszukiwaniu informacji, o które teraz proszę. Nie znalazłem tego, co mnie interesuje.

    Pracuję nad, jak na moje możliwości, dość rozbudowanym projektem.

    Potrzebuję w mojej ATMedze168 obsłużyć następujące przerwania:
    1) przerwania trzech przycisków (switchów) podłączonych do złącz ATMegi: PD2(INT0), PD3(INT1), PD7(AIN1[wejście komparatora]) - no i oczywiście do masy.
    2) przerwanie timera (co 1 sek) - kwarc 32,768 kHz podłączony do złącz ATMegi PB6(XTAL1) i PB7(XTAL2), oraz przez 2 kondensatory 22pF do masy.

    Nie będę owijał w bawełnę - nie bardzo wiem, jak się za to zabrać. Znalazłem kilka poradników, jeden dotyczący nawet ATMegi8, ale kod napisany na ich podstawie nie chce współpracować z moim mikrokontrolerem.

    ATMega taktowana 1Mhz. Czy do obsługi zewnętrznego kwarcu w timerze muszę mieszać w fusebitach?

    0 29
  • CControls
  • #3 16 Gru 2011 08:53
    Stefan90
    Poziom 7  

    Dziękuję, bardzo mi pomogłeś - nie trafiłem na tą stronę wcześniej, gdy poszukiwałem informacji. Największym moim problemem będą chyba przerwania timera. Czy muszę zmieniać fusebity? Czy dobrze podłączyłem kwarc? Jak w ogóle się za to zabrać?

    0
  • CControls
  • Pomocny post
    #4 16 Gru 2011 09:40
    tmf
    Moderator Mikrokontrolery Projektowanie

    Ja bym zaczął od przeczytania noty katalogowej procesora. Masz tam sekcję o timerze w trybie asynchronicznym, masz też opisane fusebity.

    0
  • #5 16 Gru 2011 11:02
    dar1231
    Poziom 11  

    Jeżeli chcesz korzystać z zewnętrznego rezonatora kwarcowego to musisz pobawić się fusebitami. Trzeba tylko uważać z fusebitami.

    0
  • #6 16 Gru 2011 11:50
    Stefan90
    Poziom 7  

    dar1231 napisał:
    Jeżeli chcesz korzystać z zewnętrznego rezonatora kwarcowego to musisz pobawić się fusebitami. Trzeba tylko uważać z fusebitami.


    Jesteś pewien, że akurat w tym zastosowaniu, do którego ja używam rezonatora, jest to konieczne? Gdzieś spotkałem się z przykładem, gdzie był podłączony rezonator zewnętrzny 32,768 kHz i był używany do przerwań timera, a fusebity były nieruszone. Tylko kodu w C nie podano...

    Moje zmagania z przerwaniami jak na razie stanęły na czymś takim:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Kompilator zwraca błąd:
    Code:
    warning: 'SIG_PIN_CHANGE2' appears to be a misspelled signal handler


    Przyciski podłączone, jak można wywnioskować z kodu - pod PD1, PD2, PD3.

    1. W źródle, które mi panowie podaliście (Link), dla przerwań INT0, INT1 podano wektor SIG_INTERRUPT0. Zmieniłem na INT0_vec (dla INT1 analogicznie). Nie mam jednak pojęcia, jak poprawić SIG_PIN_CHANGE2.

    2. Przy testowaniu pojawia się problem drgań przycisku. Jak najłatwiej mu zapobiec?

    3. Z tego, co się zorientowałem, przerwania przez PCINT będą wywoływać się tak zboczem narastającym, jak i opadającym. Jak zmodyfikować kod tak, aby wywoływały się tak samo, jak przerwania INT0 i INT1 (zboczem opadającym)?

    Oczywiście w programie docelowym przerwania nie będą powodowały wyświetlenia komunikatu na wyświetlaczu.

    0
  • Pomocny post
    #7 16 Gru 2011 11:53
    dondu
    Moderator Mikrokontrolery Projektowanie

    1. To stary wektor przerwań, a nowa funkcja ISR(). Musisz zastosować nowy wektor do tej funkcji. Znajdziesz go w tabelce szukając starego: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

    2. Drgania trwają od kilku do kilkudziesięciu milisekund. Możesz na przykład wykorzystać jakiś timer do odliczania tego czasu począwszy od pierwszego drgania i sprawdzić ponownie, czy po tym czasie przycisk jest naciśnięty. Możesz także wykorzystać okresowe przerwanie i zliczać nim czas gdy przycisk jest przyciśnięty: https://www.elektroda.pl/rtvforum/topic2071160.html

    3. Szukaj w datasheet.

    0
  • #8 16 Gru 2011 12:42
    Stefan90
    Poziom 7  

    Szukałem w datasheet, na stronach 66-70. Nie znalazłem rozwiązania problemu uruchamiania przerwania PCINT przy zboczu opadającym i narastającym. Mogę prosić o jakąś dodatkową wskazówkę?

    0
  • #9 16 Gru 2011 13:22
    dondu
    Moderator Mikrokontrolery Projektowanie

    Niestety PCINT nie da się sprzętowo ograniczyć, do jednego zbocza. Ale możesz to zrobić programowo, sprawdzając na początku przerwania czy pin generujący przerwanie był wcześniej 1, a teraz jest 0. Tak można zrobić, gdy impulsy nie są jakoś kosmicznie krótkie (musisz zdążyć wejść w przerwanie i sprawdzić). Niestety nie piszesz, do czego te przerwania wykorzystujesz, więc trudniej się odnieść czy ten sposób Ci wystarczy.

    0
  • #10 16 Gru 2011 21:23
    Stefan90
    Poziom 7  

    Przerwania przycisków w celu poruszania się po menu.

    0
  • #11 16 Gru 2011 21:33
    dondu
    Moderator Mikrokontrolery Projektowanie

    Stefan90 napisał:
    Przerwania przycisków w celu poruszania się po menu.

    No to będzie fajna jazda, bo każde drganie styku (wiesz w czym rzecz?) będzie generować przerwanie 2 razy.
    Czy to jest jakieś urządzenie bateryjne i będziesz usypiał mikrokontroler?

    0
  • #12 16 Gru 2011 21:51
    Stefan90
    Poziom 7  

    Nie, urządzenie pracuje pod stałym zasilaniem (póki co ciągnę je z programatora USB i stabilizatora na 3,3V).

    0
  • Pomocny post
    #13 16 Gru 2011 22:20
    dondu
    Moderator Mikrokontrolery Projektowanie

    W takim przypadku ja zrezygnowałbym z INTów i przeszedł na zwykłe skanowanie klawiatury za pomocą timera i przerwania z niego - łatwo zrobisz eliminację drgań styków.

    0
  • #14 16 Gru 2011 22:27
    Stefan90
    Poziom 7  

    Łatwo, czyli jak?

    0
  • #16 16 Gru 2011 22:51
    Stefan90
    Poziom 7  

    Dobrze, jutro, najpóźniej w niedzielę nad tym przysiądę i spróbuję zrobić tak, jak mi poradziłeś ;) Pozostała kwestia obsługi timera.

    A więc, o czym już wspominałem, mam kwarc podłączony pod XTAL1 i XTAL2, 32,768kHz. Oczywiście przez dwa kondensatory 22pF podłączony do masy. Co zrobić, aby przy jego pomocy wywoływać przerwania na przykład co 20 ms i co 1 sekundę?

    0
  • #17 18 Gru 2011 19:23
    Stefan90
    Poziom 7  

    Poradziłem sobie z przyciskami. W zasadzie pozostało mi zrobić wyłącznie przerwania timera. Pomoże ktoś?

    0
  • Pomocny post
    #18 18 Gru 2011 21:04
    janbernat
    Poziom 38  

    Czeka Cię cierpliwe studiowanie DS.
    W trybie asynchronicznym- który musisz skonfigurować w twoim projekcie- przerwanie co 1s będziesz miał gdy w trybie CTC ustawisz rejestr 0CRA na 127 (str.160).
    Oczywiście musisz też ustawić zezwolenie na obsługę tego przerwania.
    Jeśli chodzi o 20ms- to z dokładnością jest trochę gorzej.
    Przy początkowej wartości timera 174 mamy 20,0195ms.
    W przypadku trybu CTC oznacza to wpisanie do 0CRA 256-174.
    Jeśli ta dokładność jest zadowalająca- to ustawiasz w przerwaniu flagi- dwie albo jedną- zależy od Twoich potrzeb- i sprawdzasz ich stan w głównej pętli, wykonujesz jakąś funkcję- np. zaświecasz diodą na jakimś pinie- po czym ją zerujesz i czekasz na następne przerwanie a program robi swoje.
    Podejrzewam że trudno Ci załapać istotę przerwań- a to po prostu chodzi o to że co 20ms wchodzi Ci do pokoju szef, każe odłożyć (porządnie) papiery nad którymi pracujesz i żąda obsłużenia klienta.
    Masz się z tą obsługą wyrobić w mniej niż 20ms i wrócić do swojej roboty.
    Wziąć z powrotem te papiery które odłożyłeś (porządnie) i dalej robić swoje.
    Musisz zdążyć- po jeśli w tym czasie (20ms) szef znowu wejdzie to następne przerwanie będzie nieobsłużone i wkradnia się bałagan.

    0
  • #19 18 Gru 2011 21:38
    Stefan90
    Poziom 7  

    Z grubsza rozumiem, o co chodzi z przerwaniami - ale dziękuję Ci serdecznie za dość łopatologiczne przetłumaczenie ;)

    Największy problem stanowi dla mnie ten zewnętrzny kwarc - czy sposób, o którym piszesz, umożliwi mi korzystanie z niego? Muszę mieć po prostu pewność, że w miarę precyzyjnie mam odliczany czas co sekundę.

    Dodam, że jest to część bardziej rozbudowanego projektu i z całą resztą jakoś sobie poradziłem - to tak trochę na moje usprawiedliwienie ;)

    EDIT:
    Znalazłem coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Niestety, nie działa. Domyślam się, że problem tkwi w nazwach rejestrów - kod powyższy był pisany chyba dla ATMegi8.

    0
  • Pomocny post
    #20 18 Gru 2011 23:14
    janbernat
    Poziom 38  

    Czy w nazwach rejestrów- sprawdź.
    Ja sprawdzę jutro.
    Ale nie ma w tym kodzie pętli- a to w pętli głównej masz zerować flagę ustawianą w przerwaniu.

    0
  • #22 19 Gru 2011 13:47
    Stefan90
    Poziom 7  

    Za poradę dotyczącą volatile dziękuję.

    Co do pętli - czy koniecznie muszę zerować flagę w niej? W mojej pętli dość sporo się dzieje (występują np. delay-e) i boję się, że (choć prawdopodobieństwo jest bardzo niskie) w pewnym momencie przerwanie timera mogłoby się wykonać dwukrotnie w czasie jednego obiegu pętli - a wtedy, zakładając że licznik sekund właśnie dobił do sześćdziesiątki, nie zdążę go wyzerować.

    0
  • Pomocny post
    #23 19 Gru 2011 14:00
    janbernat
    Poziom 38  

    W przerwaniach masz _delay()- to wielki błąd.
    A _delay() w pętli- to duzy błąd.
    Masz Timer i masz go ustawić na przerwanie co 20ms.
    W tym przerwaniu ustawiasz sobie tyle flag ile trzeba i je zwiększasz.
    W głównej petli sprawdzasz czy flaga1==1, zerujesz i wykonujesz jakiś warunek.
    Potem sprawdzasz czy flaga2==5, zerujesz i robisz to co ma być robione co 1s.
    Potem sprawdzacz cy flaga3==15, zerujesz itd.

    0
  • #24 19 Gru 2011 22:11
    Stefan90
    Poziom 7  

    _delay() w pętli mam tylko tam, gdzie to konieczne - w obsłudze interfejsu 1Wire, aczkolwiek odczyt temperatury z termometru przy użyciu takowego interfejsu może trwać nawet ~800ms.

    0
  • Pomocny post
    #25 19 Gru 2011 22:35
    janbernat
    Poziom 38  

    Ale to się da zrobić bez _delay().
    Po prostu wystawiasz żądanie odczytu- zapominasz o tym na 1s a program robi swoje- a po 1s przerwanie Ci przypomina o odczycie.
    To jest może nieco trudniejsze do zrozumienia- ale program powinien chodzić bez żadnego _delay().
    No może jak masz pojedyncze us- ale już setki us- to trzeba nad tym popracować.

    0
  • #26 19 Gru 2011 23:35
    Stefan90
    Poziom 7  

    Będę to wszystko próbował poprawić (albo nawet napisać od zera), kiedy uda mi się obsłużyć przerwania timera, bo póki co nadal nie mogę się z nimi dogadać. Tak czy siak dzięki za masę dobrych rad. Jeśli uda mi się uruchomić timer, wrzucę kod i zapytam o jego poprawność.

    0
  • #27 19 Gru 2011 23:45
    janbernat
    Poziom 38  

    No to zacznij od zera- a potem dobuduj kod.
    Najpierw- zapomnij o zegarze asynchronicznym.
    Potem się zrobi.
    Ustaw jakiś Timer żeby przerwania generował co ileś- np. 20ms.
    W przerwaniu zwiększaj jakąś flagę.
    Jak osiągnie 1s- czyli 50- to w pętli głównej sprawdź, skasuj i wywołaj jakąś funkcję- coś wystaw na port.
    Flaga ma być volatile.
    Potem już z górki.

    0
  • #28 20 Gru 2011 00:41
    Stefan90
    Poziom 7  

    Czy ktoś mógłby wytłumaczyć mi działanie poniższego kodu?:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Przerwanie obsłużone za jego pomocą działa, jeśli kryształ kwarcu jest w układzie w momencie jego uruchomienia. Potem mogę wypiąć kryształ, a przerwanie... nadal działa ;)

    Inna jest sytuacja, gdy uruchamiam układ bez kwarcu. Do czasu jego wpięcia, przerwanie nie jest obsługiwane.

    Proszę o wyjaśnienie kodu i sytuacji z włączaniem/wyłączaniem kwarcu.

    0
  • #29 20 Gru 2011 08:17
    dondu
    Moderator Mikrokontrolery Projektowanie

    Jak masz ustawione fusebity - jakie źródło zegara taktującego jest wybrane?

    0
  • #30 20 Gru 2011 09:24
    Stefan90
    Poziom 7  

    Fusebity nie ruszane. Atmega taktowana wewnętrznym oscylatorem.

    I ponoć do tego zastosowania, do którego ja używam zewnętrznego oscylatora, fusebitów ruszać nie trzeba.

    0