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

[Atmega32][c] timer1 ctc nie dziala clear output on comp match

sajmon5544 29 Mar 2011 12:15 2313 5
  • #1 9336313
    sajmon5544
    Poziom 10  
    Witam,
    Nie mogę sobie poradzić z konfiguracją licznika 16b (timer1) w procesorze atmega32. Potrzebuję sobie wygenerować impuls o zadanej długości, próbuje użyć do tego celu licznika w trybie CTC z ustawieniem "Clear OC1A/OC1B on compare match (Set output to low level)" a więc zawartość OCR1A będzie regulować długość impulsu.

    Kod testowy:
    
        
       DDRD |= _BV(5); //OC1A (PD5) na wy 
    
       TCCR1A |= _BV(COM1A1) ;     //nastawa "Clear OC1A/OC1B on compare match (Set 
    output to low level)" 
       TCCR1B |= _BV(WGM12);     //wybor trybu CTC 
       TCCR1B |=  _BV(CS10) | _BV(CS12);   //int clock z prescalerem 1024 
            OCR1A = 2000; //na tych ustawieniach powinien doliczyc do 2000 po kilku sek 
    
       while(1); 
    }
    


    Niestety, za cholerę nie chce to działać.
    Wyjście OC1A jest ustawione na stan niski zaraz po inicjalizacji licznika, a nie dopiero po doliczeniu do OCR1A, jak głosi dokumentacja (wcześniejsze ręczne ustawienie OC1A (czy tez PD5) na stan wysoki nie pomaga i tak jest resetowane przy inicjalizacji licznika)

    Co ciekawe inne tryby CTC jak:
    *Toggle OC1A/OC1B on compare match (Set
    output to low level)

    *Set OC1A/OC1B on compare match (Set
    output to high level)

    działają idealnie, więc albo źle rozumiem dokumentacje, albo o czymś zapominam.

    pzdr.
  • #2 9337447
    hotdog
    Poziom 26  
    Zastanów się, co jest w rejestrze OCR1A w momencie uruchamiania timera.

    Wpisz do OCR1A wartość przed włączeniem timera.
  • #3 9339731
    sajmon5544
    Poziom 10  
    Źle wkleiłem kod, oczywiście ustawiam OCR1A przed włączeniem Timera, jednak bez efektu.

    Odpaliłem program w avr studio, licznik liczy, ale stan portu odpowiadającego OC1A zawsze jest niski.
  • #4 9339917
    dondu
    Moderator na urlopie...
    sajmon5544 napisał:
    .... wcześniejsze ręczne ustawienie OC1A (czy tez PD5) na stan wysoki nie pomaga i tak jest resetowane przy inicjalizacji licznika)

    Bo to chyba wynika z tego:

    Cytat:
    If one or both of the COM1A1:0 bits are written to one, the OC1A output overrides the normal port functionality of the I/O pin it is connected to.

    If one or both of the COM1B1:0 bit are written to one, the OC1B output overrides the normal port functionality of the I/O pin it is connected to. However, note that the Data Direction Register (DDR) bit corresponding to the OC1A or OC1B pin must be set in order to enable the output driver


    Czy po włączeniu zasilania korzystasz z Timer1 wcześniej do innych celów (czy zapisujesz inne wartości bitów do TCCR1A i TCCR1B niż te podane powyżej) ?

    Spróbuj może włączyć na razie tylko tryb przełączania stanu pinu przy każdym złapanym porównaniu czyli Toggle OC1A/OC1B on compare match z tabelki 44. To da podstawę do zdiagnozowania problemu.

    I pokaż Twój aktualny kod odpowiedzialny za ustawianie i włączenie timera.
  • Pomocny post
    #5 9340011
    Andrzej__S
    Poziom 28  
    Atmel napisał:

    A change of the COM1x1:0 bits state will have effect at the first compare match after the bits are
    written. For non-PWM modes, the action can be forced to have immediate effect by using the
    FOC1x strobe bits.

    Być może w tym jest problem. OC1A jest prawdopodobnie inicjowane z wartością 0 do momentu wystąpienia pierwszego "compare match". W trybach "set on compare match" i "toggle on compare match" Twój kod działa, bo wtedy po osiągnięciu odpowiedniej wartości pin jest ustawiany na 1. W przypadku "clear on compare match" OC1A jest zerowany, czyli cały czas będziesz miał na nim stan niski.
    Jeśli potrzebujesz jednego impulsu i wartości OCR1A nie muszą być bliskie maximum pojemności liczby 16-bitowej proponuję użyć np. trybu fast PWM. Przed "wystartowaniem" impulsu można wyzerować licznik (TCNT1), wystartować z odpowiednim preskalerem i w przerwaniu TIMER1_COMPA_vect zatrzymać taktowanie (bitami CS12:CS10 w TCCR1B).

    Dodano po 1 [godziny]:

    sajmon5544 napisał:

    Wyjście OC1A jest ustawione na stan niski zaraz po inicjalizacji licznika, a nie dopiero po doliczeniu do OCR1A, jak głosi dokumentacja (wcześniejsze ręczne ustawienie OC1A (czy tez PD5) na stan wysoki nie pomaga i tak jest resetowane przy inicjalizacji licznika)

    Chyba trochę źle to rozumiesz. W momencie ustawienia któregoś z bitów COM1A0 lub COM1A1 kontrolę nad pinem przejmuje "waveform generator" (patrz rysunek 44 "Compare Match Output Unit, Schematic"), a on nie działa w trybie CTC tak jak opisujesz. Zwróć uwagę na różnice w interpretacji bitów COM1A0 i COM1A1 dla trybu non-PWM i np. fast PWM (tabelki 44 i 45).
    W trybie fast PWM jest napisane: "Clear OC1A/OC1B on compare match, set OC1A/OC1B at BOTTOM".
    W trybach non-PWM (czyli np. CTC) jest tylko "Clear OC1A/OC1B on compare match (Set output to low level)", nie ma nic o ustawianiu w stan wysoki.
    Dlatego też w trybie CTC możliwe jest tylko generowanie sygnału non-PWM o wypełnieniu 50% przy ustawieniu "Toggle OC1A/OC1B on Compare Match".

    Stosowanie ustawienia "Clear OC1A/OC1B on compare match" w trybie CTC będzie raczej miało sens, gdy przykładowo najpierw ustawisz "Set OC1A/OC1B on compare match", a po wystąpieniu porównania, gdy wyjście OC1A jest w stanie wysokim, zmienisz to ustawienie na "Clear OC1A/OC1B on compare match" (np. w przerwaniu TIMER1_COMPA).

    EDIT:
    Może jednak da się to zrobić w CTC. Jak wcześniej napisałem wewnętrzny rejestr OC1A (nie mylić z pinem) po resecie mikrokontrolera jest wyzerowany. Dlatego też, po ustawieniu pinu OC1A jako wyjście i przełączeniu bitów COM1A1:COM1A0 na dowolną kombinację różną od 0, na pinie tym będzie stan niski. Można jednak ustawić ten wewnętrzny rejestr (OC1A) na wartość 1 używając bitu FOC1A w rejestrze TCCR1A:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ten kod powinien zadziałać tak jak oczekujesz (włączyć stan wysoki na czas określony przez wartość OCR1A i ustawienie preskalera).
    Ustawienie wyjścia w stan wysoki następuje po wykonaniu instrukcji TCCR1A |= (1<<FOC1A);, a włączenie taktowania timera (rozpoczęcie odliczania czasu) następuje po TCCR1B = (5<<CS10) | (1<<WGM12);, dlatego (szczególnie przy krótkich czasach - niski preskaler i mała ilość zliczanych impulsów) należy oczywiście uwzględnić takty potrzebne na wykonanie dwóch ostatnich instrukcji (w asemblerze będzie ich zapewne więcej niż dwie), bo to opóźnienie może wpłynąć na dokładność czasu trwania impulsu.
  • #6 9344955
    sajmon5544
    Poziom 10  
    Dzięki wszystkim za zainteresowanie.
    Rzeczywiście jak pisze Andrzej_S, po włączeniu trybu Clear on Compare Match, wyścia OCx można ustawiać tylko używając flag FOCx.

    Troche to problematyczne, bo trzeba:
    1. Przekonfigurować licznik na Set on Comp Match
    2. Ustawić FOCx
    3. Wrócić do Clear on Comp Match

    Jest trochę kombinacji jak na poważną operację ustawienia stanu wysokiego na nóżce.
    W każdym razie działa.
REKLAMA