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

[c]Timer1, Zgubione MHz w trybie CTC.

washu 24 Lis 2009 09:14 1634 8
REKLAMA
  • #1 7301607
    washu
    Poziom 11  
    Używam Timera1 z Atmega164P w trybie CTC, Atmega ma kwarc 16MHz, interesujący kawałek programu wygląda tak:

    Konfiguracja Timera:
    
    void Timer1_Init(void)
    {
        DDRD  |= (1<<PD7);                                                    // PD7 wyjście
        PORTD |= (1<<PD7);                                                    // PD7 <= 1
        TCCR1B = (1<<WGM12)|(1<<CS12)|(0<CS11)|(0<<CS10);                     // Timer w tryb CTC + Prescaler/256
        OCR1A = 15625;                                                        // Rejestr porównania
        TIMSK1 |= (1<<OCIE1A);                                                // Włączenie przerwania
    }
    

    Definicja przerwania:
    
    ISR(TIMER1_COMPA_vect)
    {
        PORTD ^= (1<<PD7);
    }
    

    Z tego co rozumiem to działa to tak:
    16000000 / 256 = 62500 inkrementacji timera na sekundę, więc wartość 15625 powinien osiągnąć w 1/4 sekundy czyli przerwanie wywołane 4 razy na sekundę.
    A u mnie ewidentnie przerwanie wywołuje się zmieniając stan diody raz na sekundę tak jakby zegar miał 4MHz
    Sprawdziłem - Program transmituje dodatkowo po RS z ustaloną prędkością, a USART jest jak wiadomo konfigurowany względem zegara, i działa prawidłowo przy założeniu, że mam 16MHz.

    Gdzie się gubią MHz ?
  • REKLAMA
  • #2 7301711
    mirekk36
    Poziom 42  
    No , tak z grubsza patrząc to nie pomyliło ci się coś w tym kodzie z ustawieniem preskalera ??? ;)

    TCCR1B = (1<<WGM12)|(1<<CS12)|(0<CS11)|(0<<CS10);

    wg mnie to ustawiasz bity na wartość 111, co w nocie PDF opisane jest jako:

    Cytat:
    External clock source on Tn pin. Clock on rising edge.


    może stąd ten problem?

    dla preskalera = 256 powinno być chyba tak jak poniżej:

    TCCR1B = (1<<WGM12)|(1<<CS12);

    prawda ?
  • #3 7301824
    washu
    Poziom 11  
    No ale mnie przygniotło teraz.

    Rzeczywiście ma być jak napisałeś.

    Ja po prostu w całej swojej głupocie myślałem że
    jak (1<<BIT) wstawia 1 to (0<<BIT) wstawi 0 !!!

    Teraz to widzę jaki ze mnie ciemniak. Dzięki za naprowadzenie !!!
  • REKLAMA
  • Pomocny post
    #4 7301834
    Freddie Chopin
    Specjalista - Mikrokontrolery
    mirekk36 napisał:
    No , tak z grubsza patrząc to nie pomyliło ci się coś w tym kodzie z ustawieniem preskalera ??? ;)

    TCCR1B = (1<<WGM12)|(1<<CS12)|(0<CS11)|(0<<CS10);

    wg mnie to ustawiasz bity na wartość 111,...

    WRONG!

    washu napisał:
    Ja po prostu w całej swojej głupocie myślałem że
    jak (1<<BIT) wstawia 1 to (0<<BIT) wstawi 0 !!!


    I tak jest (0 << x) zawsze równe jest 0, więc nie ma sensu tego w ogóle pisać.

    Zwróć jednak uwagę na to:

    TCCR1B = (1<<WGM12)|(1<<CS12)|(0<CS11)|(0<<CS10);

    Wynikiem x < y jest 0 albo 1, w tym przypadku 0 jest mniejsze niż CS11, więc wynikiem jest 1 - na pewno nie to co chcesz.

    4\/3!!
  • REKLAMA
  • #5 7302002
    mirekk36
    Poziom 42  
    Freddie Chopin napisał:
    mirekk36 napisał:
    No , tak z grubsza patrząc to nie pomyliło ci się coś w tym kodzie z ustawieniem preskalera ??? ;)

    TCCR1B = (1<<WGM12)|(1<<CS12)|(0<CS11)|(0<<CS10);

    wg mnie to ustawiasz bity na wartość 111,...

    WRONG!


    racja ;) ja po prostu z przyzwyczajenia (bo w ten sposób tylko ustawiam bity, a tych, które domyślnie po resecie są = 0 nie ruszam) nie zauważyłem tych zer ;) tylko jedynki widziałem (ale chyba oczami wyobraźni) - a tymczasem ten brak znaczka < był rzeczywiście powodem całego ambarasu
  • REKLAMA
  • #6 7302156
    washu
    Poziom 11  
    Sprawa więc wyjaśniona, nie głupota ale ślepota :D

    Mam jeszcze jedno pytanie:
    Jak jakimś makrem zastąpić kopiowanie bitu ?

    Mam na myśli coś w typie: BajtA.Bit1 = BajtB.Bit3
    czyli ustawienie bitu na wzór innego niezależnie od jego stanu.

    Rozumiem że można to zrobić popularymi CHECKBIT SETBIT CLEARBIT i if'em
    czyli coś w stylu (if(CHECKBIT(BajtB,Bit3)) SETBIT(BajtA,Bit1) else CLEARBIT(BajtA,Bit1)

    ale jak uprościć ? Da się ?
  • #7 7302687
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Nie da się uniwersalnie, ale coś na styl:

    PORTx |= (PORTy & (1 << read_bit)) << (write_bit - read_bit);

    Chyba powinno działać, ale na AVR (gdzie nie ma barrel shiftera) pewnie if() byłby wydajniejszy, szczególnie jeśli write_bit i read_bit byłyby zmienne.

    4\/3!!
  • #8 7302858
    BoskiDialer
    Poziom 34  
    C jako taki nie był projektowany głównie dla mikrokontrolerów, więc operacje na bitach należy dokonywać używając przesunięć, iloczynu logicznego, sumy oraz ewentualnie if'ów. Przesunięcia mogą być kosztowne (brak barrel shift), chociaż dobrze napisane przeniesienie da się zoptymalizować do 3 instrukcji (skasowanie bitu, pominięcie jeśli bit źródłowy skasowany, ustawienie bitu):
    	a &=~(1<<3);
    	if(b & (1<<5))
    		a |= (1<<3);


    Można jednak napisać wstawkę asemblerową, która w 2 cyklach przenosi bit (tylko z bajtu do bajtu):
    #define BIT_T(dest, destbit, src, srcbit) asm("bst %3, %4" "\n\t" "bld %0, %2": "=r"(dest): "0"(dest), "I"(destbit), "r"(src), "I"(srcbit))
    
    BIT_T(a, 3, b, 5); // przenosi bit 5 zmiennej b do bitu 3 zmiennej a.
    Nie polecam stosować tego makra, chyba że ktoś chce. Zaraz pewnie ktoś wspomni o strukturach z polami bitowymi - w takim przypadku bardziej preferuję mój sposób.

    Freddie Chopin: Twoje przypisanie nie będzie do końca działać: nie będzie się dało wyzerować bitu.
REKLAMA