logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Konfiguracja timerów w Atmega8 - timer1 nieprawidłowo odlicza czas

Maryush 11 Wrz 2011 15:13 3020 7
REKLAMA
  • #1 9916400
    Maryush
    Poziom 22  
    Witam,

    piszę program, w którym zmuszony jestem użyć dwóch timerów w Atmega8. Będzie taka sytuacja, gdy obydwa timery będą musiały generować przerwanie w tym samym momencie, czyli muszą odliczyć taki sam odcinek czasu. Wszystko byłoby dobrze, gdyby nie fakt, że timer1 pomimo, że jest dobrze skonfigurowany (przynajmniej mi się tak wydaje :D ) opóźnia się w stosunku do timera0, który prawidłowo odlicza czas. Zamieszczam fragment programu z konfiguracją timerów. Czas do odliczenia to 800ms. Proszę powiedzieć, co robię źle, że timer1 opóźnia się.

    
    $crystal = 8000000
    
    Const Timer1reload = 10000
    Const Timer0reload = 250
    Config Timer0 = Timer , Prescale = 256
    Config Timer1 = Timer , Prescale = 8
    Load Timer1 , Timer1reload
    Load Timer0 , Timer0reload
    On Ovf1 Timer1_isr
    On Ovf0 Timer0_isr
    Enable Interrupts
    Enable Timer0
    Enable Timer1
    
    Do
    .
    .
    .
    .
    .
    Loop
    
    Timer0_isr:
    Incr Ms
    If Ms = 100 Then
    Ms=0
    .
    .
    .
    End If
    
    Return
    
    Timer1_isr:
    incr Ms1
    If Ms1 = 80 Then
    Ms1=0
    .
    .
    .
    End If
    
    Return
  • REKLAMA
  • #2 9916467
    xury
    Specjalista automatyka domowa
    Hmm. Dobrze napisałeś, że Tobie się wydaje, że obydwa Timery odliczają dobrze, a tak nie jest.
    Wydaje mi się, że chciałeś uzyskać przerwanie co 8ms ?
    Więc musisz po każdym przeładowaniu timera go ładować początkowa wartością.
    Czyli dla timer0 to będzie 6, a dla timera1 to będzie 57536.
    Ale i tak nie wiem czemu musisz używać dwóch timerów by generować przerwanie o tym samym czasie. Zresztą i tak pierwsze wykonane będzie przerwanie z większym priorytetem.
  • REKLAMA
  • #3 9916522
    Maryush
    Poziom 22  
    Przerwanie ma być co 800ms. Timer0 prawidłowo generuje to przerwanie: 1/8000000=0,000000125 => 0,000000125*256=0,000032 => 0,000032*250=0,008s => 0,008*100=0,8s i tyle jest odliczane. Dla timera1 rachunek jest analogiczny, ale niestety nie generuje przerwania po tym czasie, tylko kilkakrotnie później. Timery ładowane są początkową wartością w programie głównym, więc w przerwaniu jest to już zbędne, a samo przerwanie ma być generowane w odpowiednich momentach.
  • #4 9917004
    Mundi1970
    Poziom 24  
    Dla powyższego przykładu wartość dla Timera1 powinna być 7999.

    1000ms/800ms=1,25Hz
    *100=125Hz

    (clock speed 8000000Hz / (prescaler 8 * częstotliwość 125Hz)) - 1 = 7999

    lub dla prescalera 256 wartość wpisywana do licznika 24999 da przerwanie co 0,8s


    EDIT:
    Ta linijka coś nie pasuje If Ms1 = 80 Then nie powinno być 100 zamiast 80

    EDIT2:
    A, żeby nie było kłótni :)

    Load Timer0 , 250 jest równoważny do timer0=6
    Load Timer1 , 7999 jest równoważny do timer1=57536
  • REKLAMA
  • #5 9917999
    xury
    Specjalista automatyka domowa
    Maryush napisał:
    Przerwanie ma być co 800ms. Timer0 prawidłowo generuje to przerwanie: 1/8000000=0,000000125 => 0,000000125*256=0,000032 => 0,000032*250=0,008s => 0,008*100=0,8s i tyle jest odliczane. Dla timera1 rachunek jest analogiczny, ale niestety nie generuje przerwania po tym czasie, tylko kilkakrotnie później. Timery ładowane są początkową wartością w programie głównym, więc w przerwaniu jest to już zbędne, a samo przerwanie ma być generowane w odpowiednich momentach.

    I znów muszę ci napisać kilka sprostowań. Po pierwsze to co chcesz mieć co 800ms to nie nazywa się przerwanie. Ty po prostu chcesz odmierzać taki odcinek czasu.
    No i drugi podstawowy błąd to, że myślisz, że wystarczy załadowywać timery tylko na początku programu. Rejestry timerów w TYM TRYBIE, który użyłeś wymagają załadowania odpowiednią wartością PO KAŻDYM PRZEŁADOWANIU timera. Czyli na początku obsługi przerwania. Inaczej liczą sobie od zera do maksymalnej wartości licznika.
    W tym wypadku Timer0 "prawie" działa dobrze (bo późni się tylko o 6*32us), ale za to Timer 1 rozbiega się i to znacznie,bo właśnie te 57536*1us.

    Ale właśnie dotarło do mnie, że Ty nie chcesz uzyskać przerwań w tym samym czasie tylko dwa równe odcinki czasu po 800ms. Nie wiem po co do tego aż dwa timery używać.
    W takim razie timer1 najlepiej ustawić w tryb CTC, to wtedy nie będziesz musiał nic ładować po przepełnieniu.
    Zamiast konfiguracji timera daj ten kod:
    Kod: text
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #6 9918204
    Maryush
    Poziom 22  
    xury napisał:
    I znów muszę ci napisać kilka sprostowań. Po pierwsze to co chcesz mieć co 800ms to nie nazywa się przerwanie. Ty po prostu chcesz odmierzać taki odcinek czasu.

    Zgadza się, ma być odmierzony taki odcinek czasu. Mało precyzyjnie się wyraziłem, oczywiście przerwanie następuje po przepełnieniu licznika i na tej podstawie odmierzany jest żądany czas.
    xury napisał:
    No i drugi podstawowy błąd to, że myślisz, że wystarczy załadowywać timery tylko na początku programu. Rejestry timerów w TYM TRYBIE, który użyłeś wymagają załadowania odpowiednią wartością PO KAŻDYM PRZEŁADOWANIU timera. Czyli na początku obsługi przerwania. Inaczej liczą sobie od zera do maksymalnej wartości licznika.

    Nie wiem, jak ja o tym mogłem zapomnieć, przecież to oczywista sprawa, że bez załadowania licznika odpowiednią wartością po wystąpieniu przerwania zliczanie będzie rozpoczynało się od zera.
    xury napisał:
    Ale właśnie dotarło do mnie, że Ty nie chcesz uzyskać przerwań w tym samym czasie tylko dwa równe odcinki czasu po 800ms. Nie wiem po co do tego aż dwa timery używać.

    Tak, mają to być dwa równe odcinki czasu. Musi być to zrealizowane na dwóch timerach, ponieważ w czasie działania programu pojawi się czynnik zerujący jeden z timerów, a drugi nadal w tym samym czasie będzie musiał odmierzać te 800ms. Ponadto przerwania od timerów sterują dwoma niezależnymi od siebie operacjami.

    Myślę, że brak załadowania odpowiedniej wartości do licznika po nastąpieniu przerwania jest przyczyną mojego problemu. Po poprawieniu tego błędu dam odpowiedź, czy już jest tak jak powinno być.
  • #7 9918295
    Konto nie istnieje
    Poziom 1  
REKLAMA