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.

[ATmega169][c] - dwa przerwania od timera1 błąd drugiego przerwania

pawelecW 13 Wrz 2012 08:40 1992 8
  • #1 13 Wrz 2012 08:40
    pawelecW
    Poziom 9  

    Witam
    Jak rozumiem z dokumentacji, Timer1 ma możliwość takiego ustawienia rejestrów aby można było wywołać dwa przerwania. I owszem przerwania występują , pierwsze mniej więcej co 1 sek. tak jak było planowane, natomiast drugie występuje naprzemiennie z przerwaniem pierwszym (z niewielkim przesunięciem czasowym) bez względu na to jaką wartość wpiszę do OCR1B

    mam takie wartości:
    OCR1A=31250; // 1sek wew 8Mhz / 256
    OCR1B=7812; // powinno wystąpić ok 4x / sek

    kiedy do OCR1A i OCR1B wpiszę tą samą wartość np 31250 to oba przerwania występują idealnie w tym samym czasie - i tak powinno być, więc ustawienia rejestrów powinny być ok.
    Dlaczego drugie przerwanie nie występuje tak jak chcę 4x/sek ?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0 8
  • #3 13 Wrz 2012 10:05
    Andrzej__S
    Poziom 28  

    pawelecW napisał:
    ...natomiast drugie występuje naprzemiennie z przerwaniem pierwszym (z niewielkim przesunięciem czasowym) bez względu na to jaką wartość wpiszę do OCR1B

    Tak niestety będzie. Wartość OCR1B określa stan licznika, przy którym następuje przerwanie, a nie z jaką częstotliwością. O tym, z jaką częstotliwością jest wywoływane przerwanie decyduje wartość, przy której licznik jest zerowany, czyli w Twoim przypadku OCR1A. Aby uzyskać efekt jakiego oczekujesz (z użyciem jednego timera) musiałbyś modyfikować wartość OCR1B w procedurze obsługi przerwania TIMER1_COMPB, coś w stylu:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Oczywiście jeśli dwa przerwania wystąpią jednocześnie mikrokontroler ich nie obsłuży w tym samym czasie. Można wtedy użyć zagnieżdżania, jeśli któreś z przerwań ma mieć wyższy priorytet.

    EDIT:
    Właściwie dokładniej powinno być:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    tylko że Ty nieprawidłowo wpisałeś wartość 31250 do OCR1A. Jeśli chcesz, by przerwanie pojawiało się co 31250 taktów timera (czyli przy preskalerze 256 co 8000000 taktów CPU), do OCR1A powinieneś wpisać wartość o 1 mniejszą, czyli 31249.

    0
  • #4 13 Wrz 2012 16:18
    pawelecW
    Poziom 9  

    Odblokowanie makrem ISR_NOBLOCK przerwań, nie daje pozytywnego rezultatu, przerwania nie działają prawidłowo, to które jest odblokowane działa, ale zakłóca pracę drugiego....
    Bardziej przemawia mi do głowy rozwiązanie kolegi Andrzeja__S, tyle że efekt działania jest taki sam jak poprzednio.
    I chyba racją jest nie da się tego w prosty sposób rozwiązać

    Rozumiem że to działa tak(w moim rozwiązaniu)
    pierwsze występuje przerwanie OCR1B = 7812, w 7812 takcie zegara
    następnie czeka przez 23437 takty zegara do momentu wystąpienia drugiego przerwania i jednocześnie następuje wtedy wyzerowanie zegara i cykl się powtarza,
    Cel stosowania tego przerwania jest chyba inny niż pierwotnie myślałem,a wpływ mamy tylko na to w którym takcie zegara wystąpi przerwanie OCR1B

    Jeszcze mam pytanie odnośnie liczenia taktów zegara, chyba nie masz racji pisząc że 31249 takt to jest faktycznie takt 31250
    przecież pierwszy takt wystąpi dopiero kiedy licznik pokaże "1" a każda kolejna cyfra oznacza kolejny wykonany takt zegara.
    chyba że znowu się mylę.....

    0
  • #5 13 Wrz 2012 16:50
    mirekk36
    Poziom 42  

    pawelecW napisał:
    Jeszcze mam pytanie odnośnie liczenia taktów zegara, chyba nie masz racji pisząc że 31249 takt to jest faktycznie takt 31250
    przecież pierwszy takt wystąpi dopiero kiedy licznik pokaże "1" a każda kolejna cyfra oznacza kolejny wykonany takt zegara.
    chyba że znowu się mylę.....


    Kolega który ci podpowiada ma rację. Ty przyzwyczaiłeś się po prostu do liczenia od "1".... i stąd twój problem... Pomyśl, ile niżej widzisz liczb

    0 1 2 3

    cztery - prawda ? ... i dokładnie tak samo aby licznik wykonał zliczenie 4 taktów jego wartość zwiększy się od 0 do 3, a gdybyś kazał doliczyć w OCR do 4 to miałbyś

    0 1 2 3 4

    sam widzisz teraz ile taktów wykonałby timer ? oczywiście 5 taktów, i wtedy by się zresetował

    0
  • #6 13 Wrz 2012 16:54
    Andrzej__S
    Poziom 28  

    pawelecW napisał:
    pierwsze występuje przerwanie OCR1B = 7812, w 7812 takcie zegara
    następnie czeka przez 23437 takty zegara do momentu wystąpienia drugiego przerwania i jednocześnie następuje wtedy wyzerowanie zegara i cykl się powtarza,
    Cel stosowania tego przerwania jest chyba inny niż pierwotnie myślałem,a wpływ mamy tylko na to w którym takcie zegara wystąpi przerwanie OCR1B

    Właśnie tak to działa.
    pawelecW napisał:
    Bardziej przemawia mi do głowy rozwiązanie kolegi Andrzeja__S, tyle że efekt działania jest taki sam jak poprzednio.

    Rozwiązanie, jakie podałem powinno zadziałać. Pokaż kod, w którym miejscu wstawiłeś tę linijkę, którą zaproponowałem.
    pawelecW napisał:
    Jeszcze mam pytanie odnośnie liczenia taktów zegara, chyba nie masz racji pisząc że 31249 takt to jest faktycznie takt 31250
    przecież pierwszy takt wystąpi dopiero kiedy licznik pokaże "1" a każda kolejna cyfra oznacza kolejny wykonany takt zegara.
    chyba że znowu się mylę.....

    No niestety mylisz się. Przyjmijmy dla uproszczenia wartość OCR1A=4 zamiast 31250. Twój tok rozumowania wydaje się słuszny na początku zliczania. W trybie CTC licznik jest zerowany po przekroczeniu wartości OCR1A, czyli sekwencja liczenia będzie wyglądała następująco:
    1-2-3-4-0-1-2-3-4-0-1-2-3-4-0-1-2
    Policz teraz z ilu taktów składa się cykl liczenia, a ile wpisaliśmy do OCR1A.

    EDIT: No i znowu za długo się rozwodziłem :D

    0
  • #7 14 Wrz 2012 08:33
    pawelecW
    Poziom 9  

    fakt, mój błąd, zatrzymałem się w liczeniu tylko na pierwszym obiegu licznika, w drugim będzie już tak jak piszecie......

    To mój kod po modyfikacji

    Kod: C
    Zaloguj się, aby zobaczyć kod

    0
  • #8 14 Wrz 2012 09:48
    Andrzej__S
    Poziom 28  

    pawelecW napisał:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Andrzej__S napisał:
    Aby uzyskać efekt jakiego oczekujesz (z użyciem jednego timera) musiałbyś modyfikować wartość OCR1B w procedurze obsługi przerwania TIMER1_COMPB


    We funkcji Init_Timer1() pozostaw tak jak było: OCR1B=7812.
    Linijkę, którą zaproponowałem dodaj na końcu procedury ISR(TIMER1_COMPB_vect).
    Scenariusz jest prosty. Licznik zlicza do wartości OCR1B, występuje przerwanie, procedura obsługi tego przerwania modyfikuje wartość OCR1B dodając do jego wartości wcześniej ustaloną stałą (tutaj 7812), przez co OCR1B ma teraz wartość 7812+7812=15624, po osiągnięciu tej wartości przez licznik (czyli znowu po 7812 taktach timera) występuje ponownie przerwanie i scenariusz się powtarza. Modulo (OCR1A+1) ma za zadanie pilnować, by wartość OCR1B nie przekroczyła wartości OCR1A, bo wtedy przerwanie (od porównania licznika i OCR1B) nie wystąpiłoby w ogóle, chyba że w innym miejscu programu zwiększyłbyś OCR1A powyżej wartości OCR1B.

    0
  • #9 14 Wrz 2012 11:44
    pawelecW
    Poziom 9  

    Działa, tak jak napisałeś, źle zrozumiałem Twój poprzedni post
    Dziękuję za pomoc

    0