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, Bascom 1.11.8.3 - Timer0 liczy błędnie przy 16 MHz, dlaczego?

adrach 21 Mar 2007 22:18 2332 13
REKLAMA
  • #1 3704846
    adrach
    Poziom 12  
    Posty: 82
    Pomógł: 1
    Ocena: 19
    Zastosowałem kwarc 16 MHz oraz zasilanie uP +5V.
    Według poniższych wzorów odliczany czas powinien wynosić 1 sekundę, a niestety w przypadku b) i c) tak NIE JEST i w programie wynosi odpowiednio: około 2 i około 10 sekund. Tylko dla konfiguracji z pkt. a) jest okey. Gdzie jest problem? O co tu chodzi? Proszę o pomoc!

    Oto tożsame wzory, z których obliczany czas powinien byc taki sam i wynosić 1 sekundę:
    a) 16000000/64/250/1000 = 1 s
    b) 16000000/64/125/2000 = 1 s
    c) 16000000/64/25/10000 = 1 s


    A oto testowy kod w Bascomie:

    $regfile = "m8def.dat"
    $crystal = 16000000

    Config Pinc.1 = Output

    Config Timer0 = Timer , Prescale = 64
    On Timer0 Sekunda

    Dim Jednostki_czasu As Word : Jednostki_czasu = 0

    Enable Interrupts

    Enable Timer0

    Load Timer0 = 250
    'Load Timer0 = 125
    'Load Timer0 = 25


    Dioda Alias Portc.1


    Do
    Loop
    End



    Sekunda:
    Load Timer0 = 250
    ' Load Timer0 = 125
    ' Load Timer0 = 25


    Incr Jednostki_czasu

    If Jednostki_czasu = 1000 Then 'po 1 sekundzie - prawidłowo !!!
    ' If Jednostki_czasu = 2000 Then 'po ok. 2 sekundach ???
    ' If Jednostki_czasu = 10000 Then 'po ok. 10 sekundach ???


    Jednostki_czasu = 0
    Set Dioda
    Waitms 1000
    Reset Dioda
    End If
    Return


    Dorzucam jeszcze ustawienie bezpieczników:
    Załączniki:
    • fuse.jpg (53.47 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • #2 3705307
    teedd
    Poziom 19  
    Posty: 219
    Pomógł: 24
    Ocena: 2
    Witam
    Zrób tak:

    ...
    Sekunda:
    Tcnt0 =6
    'Tcnt0 =131
    'Tcnt0 = 231
    ...

    będzie dobrze.
    Pozdrrowienia - teedd
  • REKLAMA
  • #3 3705850
    adrach
    Poziom 12  
    Posty: 82
    Pomógł: 1
    Ocena: 19
    Wielkie dzięki Teedd,

    ale czy możesz mi jeszcze wyjaśnić o co tu chodzi, bo przecież
    instrukcja Load Timer0 = 25 powinna być tożsama z instrukcją Tcnt0 = 231.

    A przy okazji jeszcze jedno pytanko.
    Spotkałem się z tego typu zapisem: Timer0 = Timer0 + liczba (lub analogicznie Tcnt0 = Tcnt0 + liczba), gdzie liczba to wartość początkowa wpisywana do licznika (a więc Timer0 przepełnia się po 256-liczba impulsach). Komentarz był następujący: "Dodanie wartości początkowej do licznika a nie jej bezpośrednie przypisanie umożliwia zwiększenie dokładności odmierzanego czasu".
    Szczerze mówiąc prosiłbym o szerszy komentarz, bo nie jest to zadnie dla mnie takie oczywiste :-)
  • #4 3705952
    teedd
    Poziom 19  
    Posty: 219
    Pomógł: 24
    Ocena: 2
    Witam.
    Według helpa rzeczywiście te instrukcje powinny być tożsame. Niemniej jednak instrukcji Load Timer0 używasz podczas obsługi przerwania. Generalnie obsługa przerwania powinna być jak najprostsza i najkrótsza. Jeden z kolegów kiedyś napisał, że pisze w Bascomie, ale obsługę przerwań wyłącznie w asemblerze.
    Odchudź maksymalnie obsługę przerwania (wyrzuć to wait!), warunki sprawdzaj poza przerwaniem itp., zwiększ stos - może wtedy Load Timer0 w obsłudze przerwania Ci zadziała - ale nie gwarantuję.
    Daj znać o wynikach - teedd
  • REKLAMA
  • #6 3708410
    adrach
    Poziom 12  
    Posty: 82
    Pomógł: 1
    Ocena: 19
    M. S. napisał:
    Load timer = ... nie jest równy Timer = ...

    ... no to akurat jest oczywiste :-)
    Problem dotyczy zupełnie czegoś innego - poczytaj powyżej, ale dokładniej ;-)


    M. S. napisał:
    Skąd te obliczenia?
    Poniżej masz kalkulator do timerów. Policz i się nie dziw.

    ... no jakoś się nie dziwię, bo kalkulator (swoją drogą całkiem fajny - szczególnie przydatny dla tych, który nie radzą sobie z prostą matematyką) liczy tak samo jak ja :-)

    Dodano po 1 [godziny]:

    teedd napisał:
    Według helpa rzeczywiście te instrukcje powinny być tożsame.

    ... no właśnie :cry:

    teedd napisał:
    Odchudź maksymalnie obsługę przerwania (wyrzuć to wait!), warunki sprawdzaj poza przerwaniem itp., ... - może wtedy Load Timer0 ... zadziała - ale nie gwarantuję.

    ... przerobiłem kod testowy według Twojego zalecenia, ale niestety Load Timer0 przy tych ustawieniach PRESCALE jakie widzisz nadal nie działa prawidłowo.
    (diodę i wait zostawiam, bo od razu mogę się zorientować, czy program działa prawidłowo - czas świecenia i wygaszenia diody powinien wynosić 1 sekundę);

    Oto kod po modernizacji (rozumiem, że mniej więcej to miałeś na myśli):

    $regfile = "m8def.dat"
    $crystal = 16000000

    Config Pinc.1 = Output

    Config Timer0 = Timer , Prescale = 64
    'czas taktu rowny 4us
    On Timer0 Przerwanie_timer0

    Dim Jednostki_czasu As Word : Jednostki_czasu = 0
    Dim Flaga As Bit

    Enable Interrupts
    Enable Timer0


    'Load Timer0 = 25
    Tcnt0 = 231

    Dioda Alias Portc.1


    Do
    If Flaga = 1 Then
    Flaga = 0
    Incr Jednostki_czasu

    If Jednostki_czasu = 10000 Then
    'odliczanie sekundy
    Jednostki_czasu = 0
    Set Dioda
    Waitms 1000
    Reset Dioda
    End If

    End If
    Loop
    End


    Przerwanie_timer0:

    ' Load Timer0 = 25 'przerwanie powinno wystapic co 100us ale w praktyce jest co ok. 12 sekund !!!
    Tcnt0 = 231 'przerwanie wystepuje co 100us !!!
    Flaga = 1 'tu specjalnie zastosowalem "lekka" zmienna BIT-owa
    Return
  • #7 3708944
    M. S.
    Poziom 34  
    Posty: 2107
    Pomógł: 259
    Ocena: 680
    Gdzieś czytałem, że któraś wersja Bascoma (chyba 1.11.8.3) wadliwie konfiguruje Timery. Spróbuj dobrać się do stosownych rejestrów i "ręcznie" wpisać im odpowiednie ustawienia.
  • REKLAMA
  • #8 3709003
    teedd
    Poziom 19  
    Posty: 219
    Pomógł: 24
    Ocena: 2
    Witam.
    Bascom 1.11.8.5 też tak się zachowuje. Zaraz spróbuję poprawić program.
    teedd

    Dodano po 38 [minuty]:

    Witam.
    Wyrzuciłem Load Timer0=... poza obsługę przerwania (tam zostało tylko ustawianie flagi) ale bez zmian. Na pierwszy rzut oka wygląda, że ta instrukcja nie działa. Chyba jednak byłoby to zbyt proste wytłumaczenie - pewnie działa, ale czegoś nie doczytaliśmy. Ja jednak nie potrafię tego wytłumaczyć. Może ktoś bardziej doświadczony może to wytłumaczy?
    Ciekawa sprawa.
    Pozdrowienia - teedd
  • #9 3709151
    adrach
    Poziom 12  
    Posty: 82
    Pomógł: 1
    Ocena: 19
    teedd napisał:
    Wyrzuciłem Load Timer0=... poza obsługę przerwania (tam zostało tylko ustawianie flagi) ale bez zmian.

    ... nie wspominałem już o tym, ale to też wcześniej przerobiłem i nie pomogło.
  • Pomocny post
    #10 3709291
    vain
    Poziom 13  
    Posty: 89
    Pomógł: 8
    Tak poza tematem, czy to sie nie pisze "Load Timer0, 100" ?
    i zrob timer0=cos na starcie i w przerwaniu.
  • Pomocny post
    #11 3709344
    teedd
    Poziom 19  
    Posty: 219
    Pomógł: 24
    Ocena: 2
    Brawo vain!
    O to chodziło! Ma być Load Timer0, ... Nie wiem dlaczego tego nie zauważyłem - a zaglądałem do helpa kilka razy. Jak już człowiek się czymś zasugeruje, to potem ciężko zauważyć własny błąd.
    Pozdrowienia
  • #12 3710306
    adrach
    Poziom 12  
    Posty: 82
    Pomógł: 1
    Ocena: 19
    No faktycznie błąd składni ... - sprawdziłem i u mnie też teraz działa.
    Reasumując, prawidłowo działa instrukcja: Load Timer0 , 25
    natomiast problemy są z instrukcją: Load Timer0 = 25
    chociaż tą drugą spotyka się w książkach i publikacjach (?)

    Dzięki chłopaki za doprowadzenie sprawy do finału.


    Jeśli jeszcze możemy pociągnąć wspomiany na samym początku przeze mnie wątek, to chciałbym powrócić do kwestii:
    adrach napisał:

    Spotkałem się z tego typu zapisem: Timer0 = Timer0 + liczba (lub analogicznie Tcnt0 = Tcnt0 + liczba), gdzie liczba to wartość początkowa wpisywana do licznika (a więc Timer0 przepełnia się po 256-liczba impulsach).
    Komentarz był następujący: "Dodanie wartości początkowej do licznika a nie jej bezpośrednie przypisanie umożliwia zwiększenie dokładności odmierzanego czasu".
    Szczerze mówiąc prosiłbym o szerszy komentarz, bo nie jest to zadnie dla mnie takie oczywiste :-)

    ...no właśnie i jak to rozumieć ???
  • #13 3710354
    M. S.
    Poziom 34  
    Posty: 2107
    Pomógł: 259
    Ocena: 680
    Jeśli pomiędzy przerwaniem od timera a wpisaniem do niego nowej wartości upływa zbyt "długi" czas to może się okazać, że timer zgłosił przerwanie w międzyczasie, które zostanie uwzględnione jeśli zapiszemy Timer1 = Timer1+wartość, a utracone jeśli zastosujemy Timer1 = wartość.
  • #14 3712534
    adrach
    Poziom 12  
    Posty: 82
    Pomógł: 1
    Ocena: 19
    Dzięki M. S. za komentarz.

    Z tego co obecnie ułożyło mi się w głowie, to zapis typu Timer0 = Timer0 + liczba skróci po prostu czas liczony do zgłoszenia najbliższego przerwania o wartość uwzględnioną w parametrze Timer0.
    Skrócenie tego czasu jest konieczne, aby wyeliminować czas jaki "stracił" procesor m. in. na:
    a) dokończenie instrukcji, którą wykonywał, gdy przyszło zgłoszenie przerwania,
    b) odłożenie na stos wszystkich potrzebnych informacji, które będą mu potrzebne, aby po wykonaniu instrukcji wypisanych w obsłudze przewania mógł powrócić do wykonywania "porzuconej" wcześniej pracy,
    c) w końcu jakiś czas upłynął również od momentu wejścia w obsługę przerwania do chwili wykonania pierwszej instrukcji w przerwaniu.

    Reasumując,
    czas, który upłynął między zgłoszeniem przerwania a realnym momentem rozpoczęcia jego obsługi (tj. rozpoczęciem wykonania pierwszej instrukcji w obsłudze przerwania) jest korygowany właśnie w zapisie: Timer0 + liczba.

    Jeśli ktoś ma coś jeszcze do dodania, to zapraszam, bo po weekendzie zamykam temat.
    Pozdrawiam serdecznie i dziękuję za udział w dyskusji.

Podsumowanie tematu

✨ Problem dotyczył nieprawidłowego odmierzania czasu przez Timer0 w mikrokontrolerze Atmega8 przy taktowaniu 16 MHz i użyciu Bascom 1.11.8.3. Pomimo poprawnych teoretycznych obliczeń czasu (1 sekunda) dla różnych wartości rejestru załadowania timera (Load Timer0), w praktyce czas odmierzany był znacznie dłuższy (około 2 i 10 sekund). Przyczyną okazał się błąd składniowy w instrukcji ładowania timera: poprawna forma to "Load Timer0, wartość" a nie "Load Timer0 = wartość". Różnica ta wpływa na prawidłowe ustawienie licznika i generowanie przerwań. Dodatkowo omówiono zasadę stosowania zapisu Timer0 = Timer0 + liczba w celu kompensacji opóźnień związanych z obsługą przerwania, co pozwala na zwiększenie dokładności odmierzania czasu przez uwzględnienie czasu potrzebnego na wykonanie instrukcji i obsługę przerwania. Wskazano również, że obsługa przerwań powinna być maksymalnie uproszczona, a konfiguracja timerów w Bascomie może wymagać ręcznego ustawienia rejestrów ze względu na potencjalne błędy w wersji kompilatora.
Wygenerowane przez model językowy.
REKLAMA