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

ATmega8 Timer0/Timer1 – jak ustawić prescaler, by uzyskać 1s przy 1MHz?

pend0lino 14 Mar 2006 08:58 2978 27
REKLAMA
  • #1 2411935
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Czesc
    Czytam, czytam i nie moge zrozumiec jak dziala parametr prescale.
    Mam atmege8 bez kwarcu zewnetrznego czyli dziala na 1MHz. Czy ktos moglby mi wytlumaczyc jak oblicza sie czas dla Timerow (Timer0 i Timer1).
    Najlepiej na przykladzie programu z bascoma - zalozmy ze chcialbym co sekunde ''puszczac'' sygnal na jeden z pinow ustawiony jako wyjscie (np. zeby zaswiecic led).
    Dzieki za wyjasnienie.

    Ps. zaznaczam, że nie umiem jeszcze angielskiego na tyle, zeby poradzić sobie z dokumentacjami producentow, takze bylbym wdzieczny za nie odsylanie mnie do nich.
  • REKLAMA
  • Pomocny post
    #2 2411967
    myrcioch
    Poziom 18  
    Posty: 150
    Pomógł: 30
    Ocena: 5
    1000000 dzieli się przez 64:
    1000000/64=15625
    Masz więc gotowe ustawienia preskalera (64) oraz licznika 16-bitowego T1 (15625).

    Do dokumentacji i tak Cię odeślemy - nie zasłaniaj się nieznajomością angielskiego - książek po polsku trochę jest, a nawet parę wątków niżej można znaleźć pdf atmega32 po polsku
  • REKLAMA
  • #3 2412030
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    myrcioch napisał:
    1000000 dzieli się przez 64:
    1000000/64=15625
    Masz więc gotowe ustawienia preskalera (64) oraz licznika 16-bitowego T1 (15625).

    Tylko co z tym dalej zrobić żeby sekunde policzyć?
    Mam dwie książki, ale nie jest w nich jasno wytłumaczone to zagadnienie, dlatego pytam Was.
  • Pomocny post
    #4 2412045
    myrcioch
    Poziom 18  
    Posty: 150
    Pomógł: 30
    Ocena: 5
    Jeśli do tego włączysz przerwania, ustawisz licznik T1 w tryb porównywania z kasowaniem, to dokładnie co 1 sekundę wywoła się przerwanie przepełnienia licznika T1. Dalej to już tylko odpowiednia obsługa tego przerwania.
  • #5 2412076
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Wlsanie chodzi o to ze nie wiem jak ustawic to przerwanie.
    W ksiazce mam napisane tak:
    "Przerwanie od przepelnienia Timer0 jest generowane co 8ms (8MHz/256/250 = 125, a 1/125s = 8ms)"
    Skąd się biorą te liczby? Rozumiem że preskaler sie dobiera tak żeby wyszła ''okrągla'' liczba (jesli sie myle to prosze o poprawe). Skad sie natomiast biorą dalsze liczby (250, 125) ? Prosiłbym o przełożenie tego na mój przypadek, czyli 1MHz, który myrcioch już zaczął liczyć.
    Dziękuje
  • Pomocny post
    #6 2412106
    WaldekPrzybyłek
    Poziom 15  
    Posty: 103
    Pomógł: 10
    Ocena: 4
    Wejdż na www.elportal.pl >bascom a tam jest znakomity help w naszym rodzimym języku w którym to zagadnienie jest opisane .
    Polecam również kalkulator do obliczania czasu pomiędzy przerwaniami - do pobrania w/w linku.
    Pozdrawiam.
    Waldek.
  • REKLAMA
  • Pomocny post
    #7 2412121
    myrcioch
    Poziom 18  
    Posty: 150
    Pomógł: 30
    Ocena: 5
    256 to inna wartość preskalera wybrana w Twojej książce. 250 to wartość porównania dla licznika T0. Licznik T0 jest 8-bitowy, nie da się na nim ustawić 15625. Dla wartości porównania powyżej 256 musisz użyć T1. Idea działania jest taka sama:
    8000000Hz/256/250=125Hz
    1000000Hz/64/15625=1Hz
  • #8 2412307
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Czy moglbym prosic o poprawienie tego kodu. Chcialbym zeby co dwie sekundy zmienial sie stan PB1, ale chyba jeszcze źle coś robie z tym przeliczaniem :| Jak juz ktos bedzie taki dobry i to poprawi to prosilbym tez o dodanie komentarza dlaczego akurat taka zmiana. Dziekuje bardzo!
    $regfile = "m8def.dat"
    Config Pinb.1 = Output
    
    $crystal = 1000000
    
    Config Timer1 = Timer , Prescale = 64
    
    On Timer1 Odmierz_1s
    
    Dim Licz As Byte
    
    Enable Interrupts
    Enable Timer1
    
    Load Timer1 = 15625
    Do
    Loop
    End
    
    Odmierz_1s:
       Load Timer1 = 15625
       Incr Licz
       If Licz = 2 Then
       Licz = 0
       Toggle Portb.1
       End If
    Return
  • Pomocny post
    #9 2412413
    Ntp
    Poziom 12  
    Posty: 36
    Pomógł: 4
    Ocena: 1
    Kod wydaje sie ok, przy czym moje walki z odmierzaniem czasu mowia ze trzeba brac poprawke na Bascoma /i to duuuza/. Sprawdzilem pod symulatorem (Bascom) i program dziala, w realnym procku pewnie czasy sie rozjada.
  • #10 2412426
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Stan portu się zmienia, ale nie co 2 sekundy tylko 8 (nie wiem czy równe 8 bo mierzyłem stoperem).
  • Pomocny post
    #11 2412432
    hunterhouse
    Poziom 26  
    Posty: 893
    Pomógł: 84
    Ocena: 3
    $regfile = "m8def.dat" 
    Config Pinb.1 = Output 
    
    $crystal = 1000000 
    
    Config Timer1 = Timer , Prescale = 64 
    
    On compare1a Odmierz_1s 
    
    Dim Licz As Byte 
    
    Enable Interrupts 
    Enable compare1a
    start timer1
    
    compare1a = 15625 
    Do 
    Loop 
    End 
    
    Odmierz_1s: 
       timer1 = 0
       Incr Licz 
       If Licz = 2 Then 
       Licz = 0 
       Toggle Portb.1 
       End If 
    Return
    według mnie to powinno działać
    ADD:
    sory błąd był już poprawiłem
  • #12 2412450
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Niestety nic z tego. Z Twoim programem dioda świeci cały czas. Co źle zrobiłem w programie, napisałem?
    Dobrze przynajmniej mam przeliczenie dwóch sekund?
  • Pomocny post
    #13 2412453
    hunterhouse
    Poziom 26  
    Posty: 893
    Pomógł: 84
    Ocena: 3
    ten poprawiony też nie działa ??
    jeszcze zapomniałem aktywować przerwania compare1a

    ja dodasz

    Enable compare1a

    to powinno działać

    co do twpjego programu to on nieliczył do 15625 tylko do (65536 - 15625)=49911 czyli 3,19 razy dłużej niz powinien czyli jakieś6 z groszem sekund
  • #14 2412475
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Ntp napisał:
    Kod wydaje sie ok, przy czym moje walki z odmierzaniem czasu mowia ze trzeba brac poprawke na Bascoma /i to duuuza/. Sprawdzilem pod symulatorem (Bascom) i program dziala, w realnym procku pewnie czasy sie rozjada.

    U mnie symulator w ogole tego nie pokazuje - wszystkie porty wylaczone caly czas.

    hunterhouse napisał:
    ten poprawiony też nie działa ??
    jeszcze zapomniałem aktywować przerwania compare1a
    ja dodasz
    Kod:
    Enable compare1a
    to powinno działać

    Ok, działa !!

    Mógłbyś mi tylko wytłumaczyć co robi komenda compare1a ?

    Mozesz mi tez poprawić moj program jesli wiesz jak?
  • REKLAMA
  • Pomocny post
    #15 2412528
    hunterhouse
    Poziom 26  
    Posty: 893
    Pomógł: 84
    Ocena: 3
    symulator bascoma jest bardzo dokładny i liczy co do taktu.
    jeżeli program opiera sie na przerwaniach timera to należy włączyć okienko "Slim Timers" , wtedy symulacja trwa trochę dłużej ale bierze pod uwagę przerwania timera.

    co do compare1a to jest to rejestr poruwnawczy timera1.
    co takt zegara jest on poruwnywany z zawartościa timera (czyli licznika) i jesli wartości sa takie same to wyzwalane jest przerwanie.

    co do twojego programu
    
    $regfile = "m8def.dat" 
    Config Pinb.1 = Output 
    
    $crystal = 1000000 
    
    Config Timer1 = Timer , Prescale = 64 
    
    On Timer1 Odmierz_1s 
    
    Dim Licz As Byte 
    
    Enable Interrupts 
    Enable Timer1 
    
    Load Timer1 = 65535- 15625 
    Do 
    Loop 
    End 
    
    Odmierz_1s: 
       Load Timer1 =  65535- 15625 
       Incr Licz 
       If Licz = 2 Then 
       Licz = 0 
       Toggle Portb.1 
       End If 
    Return

    i też powinien działać
    niestety zegara z tego nie zrobisz bo wewnętrzny generator jest mało dokładny i do tego trzeba wziąść poprawkę na czas portzebny na wejścia do przerwania
  • Pomocny post
    #16 2412569
    Ntp
    Poziom 12  
    Posty: 36
    Pomógł: 4
    Ocena: 1
    Na dobra sprawe w tym przypadku do compare1a chyba moznaby dac 2x15625 czyli 31250 i tym sposobem procka przerwania bedzie krotsza.
  • #17 2412799
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    hunterhouse niestety poprawki w moim programie, które wprowadziłeś nic nie zmieniły bo dalej stan portu ''przeskakuje'' co ok. 8 sekund. Może komuś uda się znaleźć błąd.

    Ponieważ wersja hunterhouse'a działa bez problemów, chciałbym przejść o krok dalej i zrobić coś takiego:

    Włącza się czasomierz Timer1 na załóżmy 5 sekund. W ciągu tych 5 sekund zliczane są impulsy na liczniku Timer0. W zależności od ilości impulsów po 5 sekundach zaswiecana jest tyle razy dioda po czym zaczyna się nowe 5 sekund, po nich znowu miga dioda tyle razy ile bylo impulsów, itd, itd.
    Napisałem program, ale bede znowu musiał prosić o poprawki bo chyba jeszcze za mało wiem, żeby samemu dojść do tego gdzie jest błąd.
    $regfile = "m8def.dat"
    Config Portb = &B00000010
    
    $crystal = 1000000
    
    Config Timer0 = Counter , Edge = Rising
    Config Timer1 = Timer , Prescale = 64
    
    On Compare1a Odmierz_5s
    
    Dim Licz As Byte
    Dim I As Byte
    I = 0
    Licz = 0
    
    Tcnt0 = 0
    
    Enable Interrupts
    Enable Compare1a
    
    Start Timer1
    
    Compare1a = 15625
    
    Do
    Loop
    End
    
    Odmierz_5s:
    
       Timer1 = 0
       Incr Licz
    
       If Licz = 5 Then
          Licz = 0
          Stop Timer0
    
          If Tcnt0 > 0 Then
             While I < Tcnt0
                Toggle Portb.1
                Waitms 100
                Toggle Portb.1
                I = I + 1
             Wend
          End If
       End If
    
    Return

    Dziękuje!
  • Pomocny post
    #18 2412945
    Jaca
    Poziom 32  
    Posty: 1332
    Pomógł: 239
    Ocena: 217
    Co do starego problemu, sprawdź ten kod:

    $regfile = "m8def.dat"
    $crystal = 1000000
    
    Config Portb.1 = Output
    Config Timer1 = Timer , Prescale = 64
    
    Dim Licz As Byte
    
    On Timer1 Odmierz_1s
    Enable Interrupts
    Enable Timer1
    Load Timer1 , 15625
    Start Timer1
    Do
    Loop
    End
    
    Odmierz_1s:
       Load Timer1 , 15625
       Incr Licz
       If Licz = 2 Then
          Licz = 0
          Toggle Portb.1
       End If
    Return


    Pozdrawiam...
  • Pomocny post
    #19 2413071
    Ntp
    Poziom 12  
    Posty: 36
    Pomógł: 4
    Ocena: 1
    Co do problemu nr 2 to nigdzie nie uruchamiasz Timer 0, zarówno na poczatku programu jak i w procedurze przerwania (tam masz tylko Stop Timer0).
  • #20 2413342
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Jaca Twoj kod dziala! Dziekuje.

    Jesli chodzi o drugi program - dodalem start Timer0, ale nic nie pomoglo.

    Kod wyglada tak:
    $regfile = "m8def.dat"
    $crystal = 1000000
    
    Config Portb.1 = Output
    Config Timer1 = Timer , Prescale = 64
    
    
    Config Timer0 = Counter , Edge = Rising
    
    
    Dim Licz As Byte
    
    Dim I As Byte
    I = 0
    Licz = 0
    
    Tcnt0 = 0
    
    
    On Timer1 Odmierz_5s
    Enable Interrupts
    Enable Timer1
    Load Timer1 , 15625
    Start Timer1
    Start Timer0
    
    Do
    Loop
    End
    
    Odmierz_5s:
       Load Timer1 , 15625
       Incr Licz
       If Licz = 5 Then
          Stop Timer0
    
             If Tcnt0 > 0 Then
                While I < Tcnt0
                   Toggle Portb.1
                   Waitms 100
                   Toggle Portb.1
                   Incr I
                Wend
                Timer0 = 0
             End If
    
    
           Licz = 0
    
       End If
    
    
    Return


    Czy ktoś wie jak to poprawić?
  • Pomocny post
    #21 2413596
    hunterhouse
    Poziom 26  
    Posty: 893
    Pomógł: 84
    Ocena: 3
    $regfile = "m8def.dat"
    Config Pinb.1 = Output
    
    $crystal = 1000000
    
    Config Timer1 = Timer , Prescale = 64
    Config Timer0 = Counter , Edge = Rising
    
    
    On Timer1 Odmierz_1s
    
    Dim Licz As Byte , I As Byte
    
    Enable Interrupts
    Enable Timer1
    Start Timer1
    
    Timer1 = 65535 - 15625
    Do
    Loop
    End
    
    Odmierz_1s:
       Timer1 = 65535 - 15625
       Incr Licz
       If Licz = 5 Then
          Licz = 0
          While I < Tcnt0
                Toggle Portb.1
                Waitms 100
                Toggle Portb.1
                Waitms 100
                Incr I
          Wend
          Timer1 = 65535 - 15625 
          Tcnt0 = 0
       End If
    Return
    


    ten kod działa tak jak chciałeś
    dodam jeszcze że ten twój program po moich poprawkach faktyczni nie działał a to przez load timer.
    niegdy tego nie uzywałem i niewiedziałem do czego to jest. load timer sam odejmuje liczbę od zakresu timera. ja wole to robić recznie tak jak teraz.

    jesli w tamtym programie usuniesz load prze timer1 to będzie działać.

    ten programik co teraz wżuciłew testowałem w symulatorze i działa.
  • #22 2413862
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Działa u Ciebie cały czas? Ja wrzuciłem do symulatora i działa tylko zaraz po uruchomieniu, tzn. jeden cykl 5-sekundowy. Jak na początku podam załóżmy 4 impulsy to po 5 sekundach zaswieca sie 4 razy port, ale następne 5 sekund już nie dziala :|
  • Pomocny post
    #23 2414205
    hunterhouse
    Poziom 26  
    Posty: 893
    Pomógł: 84
    Ocena: 3
    no raczej działa nawet w następnych cyklach.

    sprawdz jeszcze to

    $regfile = "m8def.dat"
    Config Pinb.1 = Output
    
    $crystal = 1000000
    
    Config Timer1 = Timer , Prescale = 64
    Config Timer0 = Counter , Edge = Rising
    
    
    On Timer1 Odmierz_1s
    
    Dim Licz As Byte , I As Byte
    
    Enable Interrupts
    Enable Timer1
    Start Timer1
    
    Timer1 = 65535 - 15625
    Do
    Loop
    End
    
    Odmierz_1s:
       Timer1 = 65535 - 15625
       Incr Licz
       If Licz = 5 Then
          Stop Timer1
          Licz = 0
          While I < Tcnt0
                Toggle Portb.1
                Waitms 100
                Toggle Portb.1
                Waitms 100
                Incr I
          Wend
          I=0
          Timer1 = 65535 - 15625
          Start Timer1
          Tcnt0 = 0
       End If
    Return


    i napisz co się dzieje
  • #24 2414287
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Chyba coś jest nie tak z moim bascomem bo u mnie nie chodzi poprawnie. Dalej jest pierwszy cykl dobry, a nastepne juz loteria. Wchodzi do podprogramu tylko co jakis czas i z reguly liczba zaswiecen portu w pozniejszych przypadkach nie ma nic wspolnego z iloscia impulsow podanych na port licznika.

    Może ktoś ma jakiś inny pomysł na rozwiązanie tego. Czasem lepiej zacząć od początku.
  • Pomocny post
    #25 2414399
    hunterhouse
    Poziom 26  
    Posty: 893
    Pomógł: 84
    Ocena: 3
    ups. znowu mój błąd. zapomniałem zerować zmienną I
          I=0


    program u góry już poprawiłem
    moze teraz zadziała ??? :D
  • #26 2414427
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Działa, działa!!!

    Daj znać jak Ci mam przekazać browara za to bo bez Ciebie chyba bym do tego nigdy nie doszedl! :D

    Dodano po 11 [minuty]:

    Jeszscze tylko jedno - w jaki sposób dołożyć zatrzymanie timer0 w trakcie wykonywania podprogramu. Przy takiej konfiguracji jak teraz jesli impulsy będą podawane w trakcie wykonywania pętli w podprogramie nigdy nie nastąpi jej zakończenie. Dlatego wydaje mi się że licznik powinien się zatrzymywać po wejściu do podprogramu, sprawdzić warunek, wykonać pętle (zmienic stan portu odpowiednia ilosc razy), wrocic do glownego programu i wlaczyc znowu zliczanie timer0.
  • Pomocny post
    #27 2414515
    hunterhouse
    Poziom 26  
    Posty: 893
    Pomógł: 84
    Ocena: 3
    bezpośrednio z bascoma się nieda. trzeba by wpisać odpowiednią wartość do rejestru sterującego timerem ale niepamiętam dokładnie jak to sięrobi, trzeba by zajżec do noty katalogowej tam wszystko dokładnie opisane.

    ale mozna zrobić inna sztuczkę

    $regfile = "m8def.dat" 
    Config Pinb.1 = Output 
    
    $crystal = 1000000 
    
    Config Timer1 = Timer , Prescale = 64 
    Config Timer0 = Counter , Edge = Rising 
    
    
    On Timer1 Odmierz_1s 
    
    Dim Licz As Byte , I As Byte , K as Byte
    
    Enable Interrupts 
    Enable Timer1 
    Start Timer1 
    
    Timer1 = 65535 - 15625 
    Do 
    Loop 
    End 
    
    Odmierz_1s: 
       Timer1 = 65535 - 15625 
       Incr Licz 
       If Licz = 5 Then 
          Stop Timer1 
          Licz = 0
          K= Tcnt0
          While I < K 
                Toggle Portb.1 
                Waitms 100 
                Toggle Portb.1 
                Waitms 100 
                Incr I 
          Wend 
          I=0 
          Timer1 = 65535 - 15625 
          Start Timer1 
          Tcnt0 = 0 
       End If 
    Return



          K= Tcnt0
          While I < K 

    dodanie tych dwóch linijek zabezpieczy licznik przed zliczaniem impulsów w trakcie wyswietlania.
  • #28 2414723
    pend0lino
    Poziom 11  
    Posty: 66
    Ocena: 1
    Jestes swietny !

    Teraz daj namiary na dostarczenie skrzynki piwa, nie tylko jednego :D

Podsumowanie tematu

✨ Dyskusja dotyczy ustawienia preskalera i konfiguracji timerów Timer0 i Timer1 w mikrokontrolerze ATmega8 pracującym z wewnętrznym zegarem 1 MHz, aby uzyskać przerwania co 1 sekundę i sterować sygnałem na pinie (np. do migania diodą LED). Wyjaśniono, że dla 1 MHz i preskalera 64 licznik 16-bitowy Timer1 powinien być ustawiony na wartość 15625 (lub 65535-15625 przy odliczaniu wstecznym), co daje przerwanie co 1 sekundę. Timer0 jest 8-bitowy i nie nadaje się do takich długich odliczeń, dlatego do sekundowego timingu używa się Timer1. Omówiono także różnicę między przerwaniami od przepełnienia a przerwaniami porównania (compare1a), gdzie rejestr porównawczy wyzwala przerwanie po osiągnięciu zadanej wartości licznika. Przedstawiono przykładowy kod w Bascom AVR, który wykorzystuje Timer1 z preskalerem 64 i przerwaniami do zmiany stanu portu co 2 sekundy. Wskazano, że w praktyce dokładność wewnętrznego oscylatora 1 MHz jest ograniczona i wymaga korekt. W dalszej części omówiono bardziej zaawansowany program, który przez 5 sekund zlicza impulsy na Timer0 (tryb licznika impulsów zewnętrznych) i po tym czasie miga diodą tyle razy, ile impulsów zostało zliczonych. Podkreślono konieczność zatrzymania Timer1 podczas wykonywania migania, zerowania zmiennych i poprawnego startu/stopu timerów. Zwrócono uwagę na poprawne użycie rejestrów i funkcji Load Timer oraz ręczne ustawianie wartości licznika, aby uniknąć błędów czasowych. Wskazano, że Bascom ma pewne ograniczenia i symulator wymaga włączenia opcji "Slim Timers" dla dokładnej symulacji przerwań. Ostatecznie zaproponowano rozwiązanie z kopiowaniem wartości licznika Timer0 do zmiennej pomocniczej przed miganiem, co pozwala na poprawne działanie programu w kolejnych cyklach.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA