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

ATMEGA32[C] tryb CTC i odliczanie dokładnie 1 sekundy

pawel_5 26 Sty 2011 18:57 2787 16
  • #1 9060651
    pawel_5
    Poziom 13  
    Od paru godzin męczę sprawę z CTC, czytam na forum i dochodzę do pewnych wniosków, nie wiem czy prawdziwych?:


    Timer1 16 bit ATMEGA32, kwarc 8MHz preskaler 8 (1 takt = 1us):

    1.jeżeli użyję CTC, rejestr OCR1 (OCR1A oraz OCR1B) załaduję wartością 50000 to uzyskam przerwanie dokładnie co 0,5s. Tylko, że jeżeli dobrze rozumiem, po wygenerowaniu przerwania Output compare(rejestr TIMSK bit OCIE1A ustawiony) i tak będę musiał za każdym razem zerować TCNT1, żeby znów liczył Timer1 od wartości 0 do zapełnienia 50000 (50000 taktów)

    2. Jeżeli użyję normalnego przerwania z Timer1 (przepełnienie rejestru TCNT1 wygeneruje przerwanie) to mogę za każdym razem przy wywołanym przerwaniu ładować tą samą wartość czyli 15535 do TCNT1. Czyli będzie liczył od 15535 do 65535.

    Moim zdaniem pkt. 1 = pkt 2. Tylko, że ten drugi jest łatwiejszy do implementacji.

    Czy mam racje?


    Czy jest inny sposób aby uP ładował mi wartość do TCNT1 automatycznie i zawsze liczył od tej wartości do zapełnienia?

    Dodano po 3 [minuty]:

    Ps. w pkt. 1 pomyliłem zera i powinno być 0,05s.

    Dodano po 1 [minuty]:

    w pkt.1 jeszcze jeden błąd nie będzie liczył do zapełnienia TCNT1 wasrtością 50000 tylko do porównania z OCR1 z wartością 50000.
  • #2 9060751
    asembler
    Poziom 32  
    Po co się męczyć użyj kwarcu 32Khz w trybie asynchronicznym otrzymasz dokładnie 1 sek. Tak nawiasem mówiąc to ja na tej podstawie mierze częstotliwośc oscylatoara RC a przy podłączeniu np kwarcu 12Mhz otrzymuje wynik 11.999Mhz,, Dodatkowa stosując power-save masz zegarek do dyspozycji
  • #3 9060777
    pawel_5
    Poziom 13  
    nie mogę użyć 32kHz, to nie jest tylko zegarek a funkcja mierzenia czasu jest dodatkiem do urządzenia które projektuję. Przy 32kHz czekałbym 2 dni na pozostałe wyniki;)

    Dodano po 2 [minuty]:

    aha, masz na myśli użycie w trybie asynchronicznym, tylko że już zamówiłem płytkę, gdzie użyłem portów PC7 i PC6 (TOSC1 i TOSC2) do czego innego :(
  • #4 9060861
    asembler
    Poziom 32  
    Zawsze można przekrosować.
  • #5 9060876
    pawel_5
    Poziom 13  
    Ale zgadzasz się z moim tokiem rozumowania, że pkt.1=pkt.2, w moim pierwszym poście?
  • Pomocny post
    #6 9060920
    MacGyver 7
    Poziom 21  
    1. W trybie CTC licznik liczy aż do osiągnięcia ustalonej wartości, następnie może (ale nie musi) generować przerwanie i zawsze jest automatycznie zerowany i liczy od nowa.
    2. Tak, możesz w przerwaniu załadować TCNT dowolną wartością od której licznik będzie liczył. Tylko w przypadku rejestrów 16-bitowych pamiętaj, że koniecznie najpierw musisz załadować starszy bajt TCNT1H.

    Prościej jest wykorzystać tryb CTC który jest wręcz stworzony do takich zastosowań.
  • #7 9060939
    asembler
    Poziom 32  
    Jak się już upierasz wykorzystywać przerwanie od ocr1a to w przerwaniu od wyżej wymienionego wystarczy dodac do aktualnego licznika wartosc tak aby znowu przerwanie od ocr1a nastąpiło w zadanym czasie.
    Korzysć taka ze nie zatrzymujemy licznika 1 i mozemy wykorzystać go do innych celów, aczkolwiek taka metoda odliczania 1 sek jest conajmniej dziwna.
    Gdy potrzebujesz własnie takich interwałów to należałoby zastosować odpowiedni kwarz, których wartość właśnie jest tak dobrana aby sie miesciła do wzoru 2^n najblizej to popularny kwarz 11059200Hz
    Jak sobie pewnie wykombinujesz po zastosowniu owego program zrobi sie tak prosty że aż strach.
  • #8 9060979
    dondu
    Moderator na urlopie...
    MacGyver 7 napisał:
    Tylko w przypadku rejestrów 16-bitowych pamiętaj, że koniecznie najpierw musisz załadować starszy bajt TCNT1H.


    Ponieważ pisze w C (patrz tytuł) to nie musi się o to martwić jeżeli postępuje zgodnie z DS gdzie pisze:
    void TIM16_WriteTCNT1( unsigned int i )
    {
      unsigned char sreg;
      unsigned int i;
      
      sreg = SREG;
      _CLI();
      TCNT1 = i;
      SREG = sreg;
    }
  • #9 9061043
    pawel_5
    Poziom 13  
    MacGyver 7 napisał:
    1. W trybie CTC licznik liczy aż do osiągnięcia ustalonej wartości, następnie może (ale nie musi) generować przerwanie i zawsze jest automatycznie zerowany i liczy od nowa.


    Prościej jest wykorzystać tryb CTC który jest wręcz stworzony do takich zastosowań.



    A podasz w jaki sposób ustawić licznik w taki tryb? Bo czytam manula, ustawiam i coś mi nie chce to zadziałać. Ja ustawiałem tak jak to opisałem w pkt.1. Ale jak ustawiam OCIE1A (rejestr TIMSK) cały program się zamula:( Mógłbyś podać co po kolei w taki tryb ustawić?
  • #10 9061385
    janbernat
    Poziom 38  
    Tryby CTC w ATMega32 są dwa.
    Ustawiasz WGM12 w rejestrze TCCR1B i wpisujesz wartość końcową do OCR1.
    Albo wpisujesz WGM12 i WGM13 do TCCR1B i wpisujesz wartość końcową do ICR.
  • #11 9061438
    pawel_5
    Poziom 13  
    janbernat napisał:
    Tryby CTC w ATMega32 są dwa.
    Ustawiasz WGM12 w rejestrze TCCR1B i wpisujesz wartość końcową do OCR1.
    Albo wpisujesz WGM12 i WGM13 do TCCR1B i wpisujesz wartość końcową do ICR.


    A co z obsługą przerwania? Czy dobrze rozumuję, że wystąpi ono odpowiednio Output compare dla 0CR1 i Input capture dla ICR?
  • #12 9061619
    janbernat
    Poziom 38  
    Zezwolenie na obsługę przerwania też ustawiasz w rejestrze TIMSK.
    To które chcesz.
    I piszesz obsługę przerwania.
    I teraz tak-albo piszesz to w danym przerwaniu - jeśli jest na to czas- albo w obsłudze przerwania ustawiasz tylko flagę a obrabiasz w main().
    Albo wewnątrz przerwania wywołujesz jakąś funkcję.
    Albo w main() wywołujesz jakąś funkcję po sprawdzeniu flagi z tego przerwania.
    A potem flagę kasujesz.
    Chyba wyczerpałem ilość możliwości. :D
  • #13 9061707
    pawel_5
    Poziom 13  
    Tak, wyczerpałeś, ale mi chodzi o to czy jeśli będę używał OCR1 to czy obsługę przerwania będę musiał wpisać w przerwaniu TCNT1 czy OCR1?



    z przepełnienia rejestru TCNT1
    #pragma vector = TIMER1_OVF_vect
    __interrupt void przepelnienie_T11(void)
    {
      PORTB_Bit6=~PORTB_Bit6;
    
    }  

    czy z przepełnienia rejestru OCR1?
    
    #pragma vector =   TIMER1_COMPA_vect
    __interrupt void przepelnienie_CTC(void)
    
    {
      PORTB_Bit6=~PORTB_Bit6;
    }


    Przepraszam za laickie pytanie, ale fakt, że próbowałem już uruchomić to na wszelkie sposoby bez skutku, skłania mnie do właśnie takich pytań:(

    Bo widzisz, ja nie rozumiem, gdzie uP będzie szukał obsługi tego przerwania?
    Mój to rozumowania jest taki:

    ustawiam OCR1 na np. 1024
    startuje TCNT1
    kiedy TCNT1 doliczy się do 1024, wyzeruje się i "coś" zgłosi przerwanie, czy zgłosi to rejestr OCR1 czy TCNT1?
  • #14 9061942
    janbernat
    Poziom 38  
    Dobrze że nie tylko ja jestem laikiem.
    uP nigdzie nie będzie szukał obsługi przerwania.
    To Ty mu pozwalasz na obsługę danego przerwania- ustawiając rejestr TIMSK.
    Oczywiście jak mu zezwolisz to będzie się starał to obsłużyć.
    Jak nie będzie niczego to będzie bad isr vector i się zawiesi.
    Musi byc chociaż puste:
    
    ISR(TIMER0_......)		  
    	{						
    
    	}
    
    
  • Pomocny post
    #16 9062050
    janbernat
    Poziom 38  
    W zasadzie to jest jeszcze nieco bardziej skomplikowane.
    Można ustawić jakiś tryb CTC-albo od ICR albo od COMP- i po osiągnięciu tej wartości licznik się wyzeruje.
    Ale jeśli się wyzeruje np. po osiągnięciu wartości wpisanej w ICR to jeśli wartość wpisana w COMP będzie mniejsza niż w ICR to też wygeneruje żądanie obsługi przerwania w TIFR.
    Jeśli na to zezwolisz w TIMSK- to będzie chciał obsłużyć.
  • #17 9062077
    pawel_5
    Poziom 13  
    Tak:) Zrobiłem:) Dzięki za pomoc!! Jeżeli TCNT1 doliczy się do OCR1 na skutek pracy CTC, to nie wywoła tego TCNT1, tylko rejestr OCR1 czyli przerwanie aktywowane bitem OCIE1A w rejestrze TIMSK (str. 112). Właśnie tam w przerwaniu z obsługi flagi OCF1A zostanie wygenerowane przerwanie, bo w końcu ustawiam WGM12 na taki tryb pracy timera. Gdyby był zwykły tryb pracy to oczywiście zostałaby ustawiona flaga TOV1 - przepełnienie Timer1. W trybie CTC przy wartości poniżej 65535 Timer1 się nie przepełni, a jedynie zostanie porównany z OCR1A i zostanie przedwcześnie wyzerowany, stąd obsługa z porównania z OCR1A, a nie z przepełnienia TCNT1.
    Wszystko ładnie można zrozumieć czytając wyjaśnienie ustawiania przez uP flag na str. 113 manuala.
    Mam przerwania 1s z dokładnością do 1us co sprawdziłem na digitalnym HP Agilencie. W moim zastosowaniu nie potrzeba większej dokładności bo to nie jest typowy zegar.
    Dziękuję za pomoc!
    Temat chyba do zamknięcia.
REKLAMA