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

Zmiana kodu z Timer0 na Timer1 w ATmega8 - jak to zrobić?

kosmo90 01 Cze 2006 19:04 6344 15
REKLAMA
  • #1 2687098
    kosmo90
    Poziom 10  
    Posty: 28
    Cześć
    Jestem bardzo, bardzo początkujący i nie mogę sobie dać rady z licznikami :( Nie rozumiem o co chodzi w tym preskalerze.
    Znalazłem w książce program, który zlicza 1s przy wykorzystaniu licznika 8-bitowego Timer0. Czy moglibyście mi zmienić ten kod tak żeby zliczał tą sekundę wykorzystując 16-bitowy timer1? Rezonator kwarcowy w tym układzie ma 8MHz.

    $regfile = "m8def.dat"
    $crystal = 8000000
    
    Config Pinb.0 = Output
    Config Timer0 = Timer , Prescale = 256
    On Timer0 Odmierz_1s
    Dim Licz_8ms As Byte
    Enable Interrupts
    Enable Timer0
    
    Load Timer0 = 250
    
    Do
    Loop
    End
    
    Odmierz_1s:
    
       Load Timer0 = 250
       Incr Licz_8ms
       If Licz_8ms = 125 Then
          Licz_8ms = 0
          Toogle Portb.0
       End If
    Return


    Dla Was ta przeróbka to pewnie 5 minutek, także będę bardzo wdzięczny za pomoc!!

    Z góry bardzo dziekuję i pozdrawiam.

    Ps. dlaczego zarówno w głównym programie i wewnątrz przerwania jest linijka 'Load Timer0 = 250'?
  • REKLAMA
  • Pomocny post
    #2 2687235
    M. S.
    Poziom 34  
    Posty: 2107
    Pomógł: 259
    Ocena: 680
    Load Timer 250 pojawił się 2 razy bo pierwszy jest wykonyawny przed wejściem do pętli a następny w pętli.
    W tym programie jest dodatkowa zmienna Licz_8ms bo Timer0 nie może odmierzyć całej sekundy w jednym przebiegu. Przy użyciu Timer1 i odpowiedniego kwarcu można osiągnąć przerwania co 1 s. Jest to korzystne bo odmierzanie czasu jest nieco dokładniejsze.
    Load Timer0 250 oznacza, że do przerwania timer odliczy 250 natomiast w przypadku Timer0 = 250 bedzie to początkowa wartość timera, czyli do przepełnienia wystarczy tylko 6 impulsów. (256 - 250).

    Co do rachunków to polecam program kalkulator do AVR'ów. Napisz na PW swój e-mail to odeślę jako załącznik.
  • #3 2687279
    kosmo90
    Poziom 10  
    Posty: 28
    Dziękuję za odpowiedź!
    Nie wyjaśniłeś mi jednak jak zmienić podany przeze mnie program żeby zliczał sekundę przy kwarcu 8MHz z Timer1 :)
    Czytałem trochę, ale nie wiem czy udało mi się to dobrze zrozumieć.
    Jeżeli przy 8MHz użyje preskalera 1024 to wyjdą ułamki, więc przypuszam że takiego nie powinienem stosować :) Przy preskalerze 256 wychodzi:
    8000000/256 = 31250

    Czyli musiałbym wpisać w programie:
    Timer1 = 65535 - 31250
    Czy dobrze to rozumiem?
  • Pomocny post
    #4 2687727
    _Robak_
    Poziom 33  
    Posty: 2209
    Pomógł: 231
    Ocena: 29
    Jezeli dasz prescaller 256 to musisz zliczyc 31250 impulsow aby odmierzyc sekunde.
  • REKLAMA
  • #5 2687962
    kosmo90
    Poziom 10  
    Posty: 28
    Czy taki program obliczy mi dobrze czas?
    $regfile = "m8def.dat"
    $crystal = 8000000
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
    
    Cls
    
    Config Timer1 = Timer , Prescale = 256
    
    On Timer1 Odmierz_2s
    
    Dim Licz As Byte 
    
    Enable Interrupts
    Enable Timer1
    Start Timer1
    
    Timer1 = 65535 - 31250
    Do
    Loop
    End
    
    Odmierz_2s:
        Timer1 = 65535 - 31250
        Stop Timer1   
        Incr Licz
        Lcd "Czas: " ; Licz
        Licz = 0
    Return


    Jeśli nie to czy ktoś mógłby wprowadzić zmiany w kodzie podanym przeze mnie w pierwszej wiadomości?
  • Pomocny post
    #6 2688075
    M. S.
    Poziom 34  
    Posty: 2107
    Pomógł: 259
    Ocena: 680
    Chciałem Ci dać wędkę, ale wolisz rybę.

    $regfile = "m8def.dat"
    $crystal = 8000000
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
    
    Cls
    
    Config Timer1 = Timer , Prescale = 256
    
    On Timer1 Odmierz_2s
    
    Dim Licz As Byte
    
    Enable Interrupts
    Enable Timer1
    Start Timer1
    
    Timer1  = 34285
    Do
    Loop
    End
    
    Odmierz_2s:
        Timer1 = Timer1 + 34285  
        Incr Licz
        Lcd "Czas: " ; Licz
    Return


    Zaladowałem do timera 65536 - 31250 (bo 0 to też impuls)
    W podprogramie obsługi przerwania umieściłem Timer1 = Timer1 + 34285 tak aby uwzględnić stan timera w momencie modyfikacji jego zawartości.
    Wyrzuciłem zatrzymanie timera (jeżeli to ma być wielokrotne odmierzanie czasu). Wyrzuciłem zerowanie zmiennej Licz - inaczej cały czas byłaby równa 1, a tak wyświetlane będą kolejne sekundy.

    Co do kalkulatora AVR to po dobraniu parametrów timera oblicza czas pojawienia się przerwania od przepełnienia. Można zatem po kilku eksperymentach dobrać potrzebne nastawy.
  • REKLAMA
  • #7 2688081
    kosmo90
    Poziom 10  
    Posty: 28
    Znalazłem na internecie program, który ma przerwania co 1s z licznikiem Timer1 (przy 8MHz)
    $regfile = "m8def.dat"
    $crystal = 8000000
    '--------------------Ustawienie LCD------------------
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
    
    Cls
    Cursor Off
    '----------------------------------------------------
    Lcd "Welcome"
    Dim I As Word
    Config Timer1 = Timer , Prescale = 256
    On Timer1 Times
    Enable Interrupts
    Enable Timer1
    Timer1 = 34285
    Do
    Loop
    End
    
    Times:
    Timer1 = 34285
    I = I + 1
    Cls
    Lcd I
    Return


    Program działa w symulatorze. Nie rozumiem tylko skąd wartość Timer1=34285. Czy ktoś mógłby mi to wyjaśnić?
    Dzieki!

    Dodano po 4 [minuty]:

    Napisaliśmy odpowiedz chyba w tym samym czasie bo Twojej nie widziałem :)
    Dzięki, teraz rozumiem skąd wartość 34285.
    Przy mojej wiedzy w tej chwili poradzenie sobie z wędką jeszcze jest chyba zbyt trudne :)

    M.S. dodałeś w przerwaniu Timer1 = Timer1 + 34285, w programie który ja znalazłem jest tylko Timer1 = 34285. Jaka jest różnica i która wersja jest poprawna? :)
  • Pomocny post
    #8 2688359
    M. S.
    Poziom 34  
    Posty: 2107
    Pomógł: 259
    Ocena: 680
    Moja uwzględnia czas, który upłynął od przerwania do załadowania timera. Może to mieć wpływ gdy wystąpi w tym samym czasie obsługa innego przerwania.
  • REKLAMA
  • Pomocny post
    #9 2688440
    GienekS
    Poziom 32  
    Posty: 1971
    Pomógł: 139
    Ocena: 15
    M. S. napisał:
    Moja uwzględnia czas, który upłynął od przerwania do załadowania timera. Może to mieć wpływ gdy wystąpi w tym samym czasie obsługa innego przerwania.
    Pod warunkiem że to przerwanie zabierze więcej czasu niż potrzebne będzie preskalerowi na 256 cykli. W przeciwnym przypadku nic nie trzeba korygować właśnie dzięki preskalerowi, który daje te 256 cykli na załadowanie licznika właściwą wartości a nie jakąś tam korygowaną o niewiadomo o co.
  • Pomocny post
    #11 2689368
    greg_matrix
    Poziom 17  
    Posty: 163
    Pomógł: 28
    Ocena: 3
    Jedna uwaga tak na marginesie.
    Chyba wiem z jakiej książki korzystał kosmo90 i niestety jest tam błąd. Instrukcja Load Timer ma odrobinę inną składnię. Powinno być:
    Load Timer0, 250
    czyli przecinek a nie znak =. Można ewentualnie napisać co da taki sam efekt.

    A co do sposobu ładowania Timera to w pełni podzielam zdanie M.S. Taki trick poprawi dokładność kiedy program oparty jest na przerwaniach. Jeśli używamy licznika 16-bit i większego prescalera to nie ma to rzeczywiście znaczenia. Gorzej kiedy licznik byłby 8-bit i liczyłby szybko- błedy wynikające z opóźnień na obsługę przerwań mogą być większe niż się wydaje.
  • Pomocny post
    #12 2693758
    bishop
    Poziom 16  
    Posty: 232
    Pomógł: 17
    Ocena: 27
    Kosmo Timer1=34285 wyszło z prostej kalkulacj. przy zegarze 8000000 i preskalerze 256, timer uP'a zliczy 8000000/256= 31250 "impulsów". Czyli aby licznik sie przepelnil nalezy zaczasc zliczanie od 65535-31250=34285.
  • #13 2694234
    kosmo90
    Poziom 10  
    Posty: 28
    bishop napisał:
    Kosmo Timer1=34285 wyszło z prostej kalkulacj. przy zegarze 8000000 i preskalerze 256, timer uP'a zliczy 8000000/256= 31250 "impulsów". Czyli aby licznik sie przepelnil nalezy zaczasc zliczanie od 65535-31250=34285.

    Ok dziekuje, to już rozumiem. Proszę jeszcze tylko o wyjaśnienie skąd mam wiedzieć, że akurat ta wartość (31250) oznacza zliczanie jednej sekundy?
    Co jeśli dałbym preskaler 64? Wtedy 8000000/64 = 125000.
    Pozdrawiam!
  • #14 2694373
    Holy

    Poziom 14  
    Posty: 155
    Pomógł: 5
    Ocena: 6
    Jak masz zegar 8MHz to oznacza, że w ciągu jednej sekundy masz 8000000 taktów. Jeśli masz preskaler, to częstotliwość jest dzielona przez 256. Czyli daje to 31250 taktów na wejściu timera na sekundę. A Twoje przypuszczenie co do preskalera 64 jest całkiem słuszne. :) Trzeba tylko pamiętać, że licznik 16-bitowy ma pojemność 65535, a 8-bitowy 256.
    Konto firmowe:
    HOLTECH
    Fabryczna 18 lok. U6, Białystok, 15-483 | Tel.: +48XXXXXXXXX (Pokaż) | Strona WWW: www.holtech.eu
  • #15 2694562
    bishop
    Poziom 16  
    Posty: 232
    Pomógł: 17
    Ocena: 27
    Jesli dasz prescaler 64 to okolo 2 razy przepelni ci sie timer czyli 2 razy na sekunde wywali ci przerwanie.... dlasz szybszego oliczania wrzucam programik.
    Załączniki:
    • kalk.rar (93.02 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #16 5554034
    Meridian_
    Poziom 2  
    Posty: 4
    Zdravim muzu mit prosbu....jsem tak trochu amater a nejde mi zkompilovat jeden zdrojacek v BascomAVR a hlasi mi to chybu na "Enable Timer1" jako "Unknown interrupt source[COUNT <>3]" a pak mi to vyhodi i TIMER1.....poradi mi prosim nekdo????mam neco spatne nastavene v kompilatoru????
    
    $regfile = "m8def.dat"
    
    $crystal = 16000000
    '----------------------KONFIGURACJA--------------------
    Const Falloff = 1                                           
    Const Lcd_offset = 1
    Const Czulosc = 20
    '----------------------STAŁE---------------------------
    
    Const Timer1_h = _xtal / 44000
    Const Timer1_l = _xtal / 2000
    Reset Watchdog
    Config Watchdog = 256
    Stop Watchdog
    Const Poziom_a = 8 -(czulosc * 0.4)
    
    
    '------------------------ZMIENNE--------------------------
    Dim Div As Iram Integer At 16
    Dim K As Byte
    Dim I As Byte
    Dim Tmp_s As Integer
    Dim Tmp_c As Integer
    Dim Beta As Iram Byte
    Dim Suma As Word
    Dim Sam As Byte
    Dim Sampling As Bit
    Dim Rex_t As Integer , Imx_t As Integer
    Dim Dane(32) As Integer
    Dim Sample_h(32) As Integer
    Dim Sample_l(32) As Integer
    Dim Okno(32) As Byte
    Dim Rex(16) As Integer
    Dim Sinus(40) As Integer
    Dim Wynik(20) As Byte , Wynik_o(20) As Byte
    Dim Sing As Single
    Dim Poziom As Integer
    Dim Line1 As String * 20 , Line1d(20) As Byte At Line1 Overlay
    Dim Line2 As String * 20 , Line2d(20) As Byte At Line2 Overlay
    Dim Line3 As String * 20 , Line3d(20) As Byte At Line3 Overlay
    Dim Line4 As String * 20 , Line4d(20) As Byte At Line4 Overlay
    Dim Falloff_count(20) As Byte
    
    
    $lib "lcd4busy.lbx"
    Const _lcdport = Portd
    Const _lcdddr = Ddrd
    Const _lcdin = Pind
    Const _lcd_e = 3
    Const _lcd_rw = 2
    Const _lcd_rs = 1
    Config Lcd = 20 * 4
    Initlcd
    Waitms 10
    Initlcd
    Cls
    Deflcdchar 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 31
    Deflcdchar 2 , 0 , 0 , 0 , 0 , 0 , 0 , 31 , 31
    Deflcdchar 3 , 0 , 0 , 0 , 0 , 0 , 31 , 31 , 31
    Deflcdchar 4 , 0 , 0 , 0 , 0 , 31 , 31 , 31 , 31
    Deflcdchar 5 , 0 , 0 , 0 , 31 , 31 , 31 , 31 , 31
    Deflcdchar 6 , 0 , 0 , 31 , 31 , 31 , 31 , 31 , 31
    Deflcdchar 7 , 0 , 31 , 31 , 31 , 31 , 31 , 31 , 31
    Cls
    Cursor Off
    
    
    
    Config Adc = Single , Prescaler = 4 , Reference = Avcc
    Start Adc
    
    Config Timer1 = Timer , Prescale = 1
    On Compare1a Sampleh
    On Compare1b Samplel
    Compare1a = Timer1_h
    Compare1b = Timer1_l
    Enable Timer1 <<<<<------
    Start Timer1
    
    Enable Interrupts
    Disable Int0
    Disable Int1
    

Podsumowanie tematu

✨ Dyskusja dotyczy zmiany kodu z wykorzystującego 8-bitowy Timer0 na 16-bitowy Timer1 w mikrokontrolerze ATmega8 z kwarcem 8 MHz, aby odmierzać czas jednej sekundy. Wyjaśniono, że w oryginalnym kodzie dwukrotne załadowanie Timer0 wartością 250 służy do ustawienia początkowego licznika, który odlicza do przepełnienia (256 - 250 = 6 impulsów), a zmienna Licz_8ms służy do zliczania wielu przerwań, ponieważ Timer0 nie może odmierzyć całej sekundy w jednym przebiegu. Przy Timer1 i preskalerze 256, licznik musi zliczyć 31250 impulsów, co odpowiada 1 sekundzie (8000000 Hz / 256 = 31250). Wartość początkowa licznika Timer1 powinna być ustawiona na 65535 - 31250 = 34285, aby po zliczeniu 31250 impulsów nastąpiło przepełnienie i wywołanie przerwania. Przykładowy kod z Timer1 pokazuje, jak ustawić przerwanie co 1 sekundę, z poprawnym ładowaniem licznika w procedurze przerwania, bez zatrzymywania timera i bez zerowania zmiennej zliczającej, co pozwala na ciągłe odmierzanie czasu. Omówiono także wpływ preskalera na częstotliwość zliczania i dokładność odmierzania czasu oraz różnice między 8- a 16-bitowymi timerami. Wskazano, że preskaler 64 spowoduje dwukrotne przepełnienie timera w ciągu sekundy, co wymaga innej obsługi przerwań. Podkreślono znaczenie poprawnej składni instrukcji Load Timer oraz wpływ opóźnień obsługi przerwań na dokładność pomiaru czasu. Dodatkowo pojawiła się krótka wzmianka o problemie z kompilacją w BascomAVR dotyczącym Timer1, jednak bez rozwiązania.
Wygenerowane przez model językowy.
REKLAMA