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

[Atmega88][Bascom] - przerwanie zegarowe i odmierzanie czasu

Bartek_Sab 20 Sie 2009 11:04 4446 19
REKLAMA
  • #1 6912651
    Bartek_Sab
    Poziom 10  
    Witam

    Piszę procedurę wysyłającą na daną końcówkę portu 1ms impulsy w zadanych odcinkach czasu.

    Według wyliczeń kalkulatora dla AVR wychodzi iż przy 4HMz kwarcu, preskalerze ustawiony na 64 i początkowej wartości licznika 193 zegar generuje przerwanie w granicach 1ms.
    I tak mam ustawioną konfigurację:

    
    Config Timer2 = Timer , Prescale = 64
    Load Timer2 = 193
    On Timer2 Program
    


    Teraz powiedzmy potrzebuję ustawić czas trwania impulsów na 0.5s i przerwę w generowaniu na 2sek (to wszystko w pętli ciągłej)

    Czyli teoretyczne powinienem liczyć: licz 500 przerwań - wyłącz końcówkę - licz 2000 - zezwol na końcówkę...

    A więc wymyśliłem to tak:

    
    Program:
       Load Timer0 = 193
    
       If Flaga = 1 Then   ' czas właczenia 500*1ms po czym wyłacz flagę
          Incr Wlacz
          If Wlacz = 500 Then
             Wlacz = 0
             Flaga = 0
          End If
       End If
    
       If Flaga = 0 Then ' czas wyłaczenia 2000*1ms po czym włacz flagę
          Incr Wylacz
          If Wylacz = 2000 Then
             Wylacz = 0
             Flaga = 1
          End If
       End If
    
       If Flaga = 1 Then   ' jeżeli Flaga = 1 załączaj końcówkę
             Toggle Portb.2 
       Else
             Reset Portb.2 ' jeżeli Flaga = 0 końcówka wyłączona
       End If
    
    Return
    


    Niestety te czasy z podprogramu nijak nie mają się do teorii 0.5 i 2 sek...

    Czas migania diody (dioda praktycznie się pali) to coś koło 1,2sek, a czas przerwy to coś koło 4sek.
    I teraz jest pytanie, czy kalkulator źle oblicza przerwania czy ja czegoś nie rozumie i źle się do tego zabieram?
    Te czasy przerwy i czasu trwania generowania impulsów są tu czysto testowe. W programie potrzebować będę częstotliwości od 1 do 100Hz z szerokością impulsu 1ms.

    Za udzieloną pomoc będę bardzo wdzięczny. A widzę że są tu fachowcy nie w ciemię bici :)

    Pozdrawiam
  • REKLAMA
  • #2 6912664
    m.bartczak
    Poziom 16  
    Czy mógłbyś podrzucić resztę kodu?

    Brakuje mi tu przerwania...
  • #3 6912777
    Bartek_Sab
    Poziom 10  
    Dzięki za zainteresowanie.
    Reszta programu to w tej chwili praktyczne konfiguracja pinów i zmiennych, oraz pętla główna programu: wait 1, zapal drugą diodę, wait 1 zgaś diodę - tak abym wiedział że program w ogóle działa...
    Kwart ustawiony oczywiście na zewnętrzny i potwierdzony - bez kwarcu nie działa.
    Pętla główna też potwierdza dobre działanie i ustawienie kwarcu, gdyż Wait 1 działa jako 1sek miganie diody (oczywiście z poprawką na dokładność tej komendy)

    
    '   pęgtla glowna
    Do
      Toggle Portb.1
      Wait 1
      Toggle Portb.1
      Wait 1
    Loop
    


    To co zamieściłem w poście wyżej odbywa się właśnie w przerwaniu, czyli cały podprogram:

    
    Program:
    ...
    Return
    


    Ale oczywiście aby wyeliminować wszystkie ewentualne bugi zamieszczam cały program:

    
    $regfile = "m88def.dat"
    $crystal = 4000000
    
    Config Pinb.1 = Output                                      ' Led1
    Config Pinb.2 = Output                                      ' Led2
    
    Config Timer2 = Timer , Prescale = 64
    Load Timer2 = 193
    On Timer2 Program
    
    Enable Interrupts
    Enable Timer2
    
    Dim Wlacz As Byte
    Dim Wylacz As Integer
    Dim Flaga As Bit
    
    Flaga = 1
    
    Do
      Toggle Portb.1
      Wait 1
      Toggle Portb.1
      Wait 1
    Loop
    
    End                                                         'end program
    
    Program:
       Load Timer0 = 193
       If Flaga = 1 Then
          Incr Wlacz
          If Wlacz = 500 Then
             Wlacz = 0
             Wylacz = 0
             Flaga = 0
          End If
       End If
    
       If Flaga = 0 Then
          Incr Wylacz
          If Wylacz = 2000 Then
             Wylacz = 0
             Wlacz = 0
             Flaga = 1
          End If
       End If
    
       If Flaga = 1 Then
             Toggle Portb.2
       Else
          Reset Portb.2
       End If
    
    Return
    


    Pozdrawiam
  • REKLAMA
  • #5 6913435
    crazy_phisic
    VIP Zasłużony dla elektroda
    
       If Flaga = 1 Then 
             Toggle Portb.2 
       Else 
    

    Ten zapis generuje Ci ciąg impulsów na wyjściu, zamiast "toggle" wystarczy "set".
  • #6 6913657
    Bartek_Sab
    Poziom 10  
    crazy_phisic = faktyczne to mój błąd z różnych testów i kombinacji...
    m.bartczak = tu również to jedynie błąd z testów. Sprawdzałem na różnych timerach. I przy wklejaniu kodu nie zmieniłem tego.

    W ramach testu zmodyfikowałem kod, tak aby co 1000 przerwań (czyli teoretyczne 1000*1ms) dał mi 1ms impuls na diodę:

    
    $regfile = "m88def.dat"
    $crystal = 4000000
    
    Config Pinb.1 = Output                                      ' Led1
    Config Pinb.2 = Output                                      ' Led2
    
    Config Timer2 = Timer , Prescale = 64
    Load Timer2 = 193
    
    On Timer2 Program
    
    Enable Interrupts
    Enable Timer2
    
    
    Dim Temp As Integer
    Dim Flaga As Bit
    
    Flaga = 0
    
    Do
      Toggle Portb.1
      Wait 1
      Toggle Portb.1
      Wait 1
    Loop
    
    End                                                         'end program
    
    Program:
       Load Timer2 = 193
       Incr Temp
    
       If Flaga = 0 Then   ' jeżeli znacznik ustawiony na 0 licz 1000*1ms i ustaw znacznik na 1
          If Temp = 1000 Then
             Temp = 0
             Flaga = 1
          End If
       End If
    
       If Flaga = 1 Then   ' jezeli znaczik na 1 wlacz na jedno przerwanie diodę 1ms i zzeruj znacznik
          Set Portb.2
          Flaga = 0
       Else
          Reset Portb.2
       End If
    
    Return
    


    W tej chwili wedle mojego rozumowania, jeżeli przerwanie występuje co 1ms to zliczenie 1000 takich przerwań powinno dać zapalenie diody co 1000ms (Czyli raz na sekundę)....

    Niestety dioda miga ale co około 5sek...
    Ewidentnie winą musi być tu zegar i częstotliwość przerwań....
    Można by winić kwarc, że źle działa, ale komenda Wait 1 daje (w przybliżeniu) 1s a nie 5s, więc jest OK.

    Może źle obliczyłem przerwanie? Czy możecie to sprawdzić? Niestety z przerwaniami i obliczaniem czasu zegara mam bardzo małe doświadczenie i może coś nie tak zrobiłem?
    Do obliczania użyłem "Pomocnika AVR" z następującymi wartościami:

    Kwarc: 4000000
    Preskaler: 64
    Początkowa wartość: 193
    = Przerwanie co: 1,0080ms


    Przeliczenia na kalkulatorze 4000000 / 64 daje przerwanie co 16us a więc tyle co podaje kalkulator... Więc oblicza raczej dobrze.

    Będę wdzięczny za pomoc

    Pozdrawiam
  • #7 6913692
    kulmar
    Poziom 31  
    Nie jestem specjalistą od Bascomu i tych mikrokontrolerów, ale podpowiem taki test: być może Twoja procedura przerwania nie mieści się w 1ms czasu procesora i po prostu gubisz kolejne przerwania. Aby to sprawdzić ustaw przerwania na np. 10 lub więcej ms., zmodyfikuj odpowiednio obliczenia i sprawdź czas mrugania. Jeśli będzie ok. to masz ewidentny dowód na to, że przerwania co 1ms to za często dla tego programu.

    Pozdrawiam

    Mariusz
  • #8 6913732
    Bartek_Sab
    Poziom 10  
    Procedura jest na tyle prosta że raczej nie tu tkwi problem
    Ale właśnie sprawdziłem...
    Nawet dla pełnego weliminowania problemu zmieniłem kwarc i pzeliczyłem na 8MHz

    Config Timer2 = Timer , Prescale = 1024
    Load Timer2 = 178


    Co wedle wyliczeń daje przerwanie co 9,9840ms.

    Teraz zliczyłem 100 impulsów i daje to świecenie diody co 4 sek (wcześniej też tak mogło a nie 5sek tylko mignięcie było mniejsze).
    A więc mimo zwiększenia 10 krotnie okresu między przerwaniami błąd się powiela w taki sam sposób...

    Ale dzięki za zwrócenie uwagi i wyeliminowanie tej możliwości
  • REKLAMA
  • #9 6913762
    kulmar
    Poziom 31  
    Chwileczkę! A czy procedura przeliczania tych wartości dla prescalera itd. odnosi się do częstotliwości kwarcu, czy zegara procesora ? Nie wiem, jak to jest w Twoim procesorze, ale np. w procesorach typu PIC częstotliwość zegara systemowego jest 4 razy mniejsza od częstotliwości kwarcu.

    Pozdrawiam

    Mariusz
  • #10 6913779
    crazy_phisic
    VIP Zasłużony dla elektroda
    Przestawiałeś Fuse bity na zewnętrzny kwarc 4MHz? Domyślnie masz 8MHz z dzielnikiem przez 8 czyli 1MHz.
  • #11 6913815
    Bartek_Sab
    Poziom 10  
    Tak przestawiłem i jak już pisałem sprawdziłem...
    Bez kwarcu w układzie nie działa. Więc na 100% ciągnie z zewnątrz...
    Zresztą dla wewnętrznego rezonatora też sprawdzałem. Dla ustawienia bez wewnętrznego podziału chodzi ok wait 1 to 1sek, dla podziału przez 8 działa jak żółw...

    Ba nawet w tej chwili dla testów w układzie zmieniłem Atmegę88 na Atmegę8 i wynik jest ten sam.
    A więc czy to A88 Czy A8 Czy kwarc 4 czy 8MHz (oczywiście ustawienia da obu kwarców obliczone na ten kwarc - konfiguracja procesora też zmieniana na właściwą w edytorze)

    Wait 1 daje 1sek ,przerwanie ~10ms x 100 daje świecenie co około 4sek Co bym nie robił... wynik zawsze jest ten sam...
  • REKLAMA
  • #14 6914751
    Bartek_Sab
    Poziom 10  
    zumek napisał:
    Bartek_Sab napisał:
    ...Co bym nie robił... wynik zawsze jest ten sam...

    Nic dziwnego, bo Bascom ignoruje polecenie
    
    Load Timer2 = 178

    Zmień na
    
    Load Timer2 , 178
    'lub
    Timer2= 256 - 178

    i sprawdź :-P


    No faktyczne "przecinek" pomógł...
    Ale...

    No właśnie Ale. Działa ale przy przerwaniu 10ms x 100 zliczeń...
    Przy 1ms x 1000 zliczeń działa dalej nie tak (dioda miga co około 4sek).
    Czy dla takich częstotliwości (praktyczne tylko 1kHz) incrementacja i porównanie zmiennej a następnie zapalenie pojedynczej diody to za wiele?

    pozdrawiam...

    Ps. Nie nie było żadnych błędów ani ostrzeżeń...
  • #16 6915065
    zumek
    Poziom 39  
    Bartek_Sab napisał:
    ...Ale...

    Jak się tak dokładnie przyjrzałem Twoim obliczeniom, to muszę stwierdzić, że nie rozumiesz istoty działania funkcji Load Timer :(
    Przykładzik:
    $regfile = "m8def.dat"
    $crystal = 4000000
    
    Const Prescaler = 64
    Const Interval = 1 / 1000
    Const Reload_value = _xtal / Prescaler * Interval
    
    Config Timer2 = Timer , Prescale = Prescaler
    Load Timer2 , Reload_value
    


    Po skompilowaniu tego przykładu, sprawdź w raporcie jaką wartość ma stała Reload_value
  • #17 6915195
    Bartek_Sab
    Poziom 10  
    zumek napisał:

    Jak się tak dokładnie przyjrzałem Twoim obliczeniom, to muszę stwierdzić, że nie rozumiesz istoty działania funkcji Load Timer :(
    Przykładzik:
    $regfile = "m8def.dat"
    $crystal = 4000000
    
    Const Prescaler = 64
    Const Interval = 1 / 1000
    Const Reload_value = _xtal / Prescaler * Interval
    
    Config Timer2 = Timer , Prescale = Prescaler
    Load Timer2 , Reload_value
    


    Po skompilowaniu tego przykładu, sprawdź w raporcie jaką wartość ma stała Reload_value



    Raport zwrócił wartość:

    PRESCALER                        64
    INTERVAL                          .001
    RELOAD_VALUE                      62.5


    kulmar: Oczywiście bez jakichkolwiek zmian w programie owszem. Ale jak pisałem zawsze dostosowuję program do kwarcu.

    Dla kwarcu 4MHz jest to prescaler 64 i początkowa wartość licznika: 193

    Dla kwarcu 8MHz prescaler to: 64 i początkowa wartość licznika: 131
    To pokazuje kalkulator.
  • #18 6915235
    kulmar
    Poziom 31  
    Bartek_Sab napisał:
    kulmar: Oczywiście bez jakichkolwiek zmian w programie owszem. Ale jak pisałem zawsze dostosowuję program do kwarcu.

    Dla kwarcu 4MHz jest to prescaler 64 i początkowa wartość licznika: 193

    Dla kwarcu 8MHz prescaler to: 64 i początkowa wartość licznika: 131
    To pokazuje kalkulator.


    Nie rozumiemy się. Nie namawiam Cię do zmiany kwarcu bez zmiany programu, tylko do testu sprawdzającego wydajność procesora. Jeśli program dla kwarcu 8MHz (odpowiednio przeliczony) przy przerwaniu 1ms miga diodą dwa razy szybciej, niż ten sam program (również odpowiednio przeliczony) dla kwarcu 4 MHz, to masz pośredni dowód na to, że przerwania 1ms są gubione.

    Pozdrawiam

    Mariusz
  • Pomocny post
    #19 6915277
    zumek
    Poziom 39  
    Bartek_Sab napisał:

    Dla kwarcu 4MHz jest to prescaler 64 i początkowa wartość licznika: 193

    Dla kwarcu 8MHz prescaler to: 64 i początkowa wartość licznika: 131
    To pokazuje kalkulator.

    Chciałoby się zakrzyknąć : a nie mówiłem :-P
    Aby wpisać do Timer2 początkową wartość, to używamy poleceń:
    
    TCNT2=początkowa_wartosc
    Timer2= początkowa_wartosc
    Counter2=początkowa_wartosc
    

    Poczytaj w helpie łaskawco , co robi instrukcja Load Timer
  • #20 6915396
    Bartek_Sab
    Poziom 10  
    zumek Właśnie mam przed sobą książkę P. Marcina Wiazania (Programowanie mikrokontrolerów AVR w języku bascom) i cytuję za nią:

    Counter0 = 206  ' zapisanie licznika Timer0 wartości początkowej 206

    To przypisanie jest równoważ następującej instrukcji:
    Load Timer0, 50  ' zapisanie di licznika Timer0 także wartości początkowej 206


    Kurdę aż dziś odwiedziłem księgarnię i zakupiłem tę książkę


    Przepisany z niej przykład na 1sek timer działa.
    Tam przerwanie ustalone jest na 8ms i zliczanie ich x125 - dioda miga co 1sek.

    No nic idę kombinować dalej...

    Pozdrawiam

    Nie mniej fakt CounterX pomógł!
    Teraz 1ms x 1000 przerwań daje miganie co 1sek.

    Choć w helpie też niby pisze:
    Load Timer0, 10


    Nic to teraz zając się resztą programu. Podziękował wszystkim serdecznie....
REKLAMA