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

[AVR][C] - Timer1 Capture, pytanie początkującego

mirekk36 01 Paź 2008 10:39 5280 6
REKLAMA
  • #1 5587769
    mirekk36
    Poziom 42  
    Witam,

    Jak w temacie zaznaczam, że jestem początkujący w C a moje pytanie związane jest z próbą rogryzienia kodu w C a przy okazji zrozumienia do końca funkcji Compare. Znalazłem taki kodzik:

    #include <avr\io.h>
    #include <avr\interrupt.h>
    #include <avr\iom8.h>
    #define ICP PINB0
    
    //define ovrflow counter
    uint16_t ov_counter;
    
    //define times for start and end of signal
    uint16_t rising, falling;
    
    //define overall counts
    uint32_t counts;
    
    //overflow counter interrupts service routine
    ISR(TIMER1_OVF_vect){
    
      ov_counter++;
    
    }
    
    //Timer1 capture interrupt service subroutine
    ISR(TIMER1_CAPT_vect){
    
    /*This subroutine checks was it start of pulse (rising edge)
    or was it end (fallingedge)and performs required operations*/
    
    if (ICP) //if high level
                {
                //save start time (zapamiętaj czas startu)
                rising=ICR1;
    
                //set to trigger on falling edge 
                // ustaw wyzwalanie zboczem opadającym
                TCCR1B=TCCR1B&0xBF;
    
                //reset overflow counter (resetruj ov_counter)
                ov_counter=0;
       }
    else
                {
    
                //save falling time
                // zapamiętaj czas końca impulsu)
                falling=ICR1;
    
                //rising edge triggers next
                // ustaw wyzwalanie zboczem rosnącym
                TCCR1B=TCCR1B|0x40;
    
                counts=(uint32_t)falling-(uint32_t)rising+(uint32_t)ov_counter;
                /*you can convert coutns to seconds and send to LCD*/
                }
    }
    
    int main(void) {
    
    //enable overflow and input capture interrupts
    TIMSK=0x24;
    
    /*Noise canceller, without prescaler, rising edge*/
    // Timer1 bez preskalera, zbocze rosnące, eliminacja zakłóceń
    TCCR1B=0xC1;
    
    sei();
    
        for (;;) {
    
    /* loop forever timer does the job*/
    
        }
    
    }


    chodzi w nim o sprawdzenie czasu trwania impulsu wysokiego podanego na wejście ICP1.

    i mam w zasadzie 2 pytania:

    odnośnie linijki:
    Cytat:
    counts=(uint32_t)falling-(uint32_t)rising+(uint32_t)ov_counter;


    1. czy dobrze rozumiem, że taki zapis (uint32_t)falling to poprostu rzutowanie typów, ponieważ na początku zmienna falling zadeklarowana była jako 16-to bitowa?

    2. nie rozumiem za bardzo tego sposobu obliczania czasu - bo np czy czas impulsu nie jest po prostu równy zmiennej counts ???, która jest zerowana z momencie narastającego zbocza i inkrementowana do momentu wykrycia zbocza opadającego (timer1 działa przecież bez preskalera) - po co więc w tym przypadku jeszcze ta różnica falling-rising ? (jakoś już się zakręciłem)
  • REKLAMA
  • Pomocny post
    #2 5587839
    Freddie Chopin
    Specjalista - Mikrokontrolery
    1. dobrze

    2. zmienna counts nie jest nigdzie zerowana, to raz. pozatym algorytm IMHO jest bledny, to dwa <: idea jest taka, zeby byl on w stanie zmierzyc impulsy o dowolnej dlugosci, a nie tylko takie ktore zmieszcza sie w jednym okresie timera (ile on tam bitow ma). jednoczesnie wiec w pierwszym przerwaniu od gory (overflow) inkrementowany jest licznik 'przekrecen' timera. tak wiec teraz zalozmy, ze ten timer jest 8bitowy (to nieistotne). i ze sobie leci. teraz nastepuje pierwszy capture np na wartosci 250. drugi capture nastepuje na wartosci 150, a timer po drodze przekrecil sie tylko raz. teraz prawidlowa formula powinna wygladac tak:
    0xFF * ov_counter + falling - rising.

    co w efekcie da prawidlowa wartosc = 156

    nie wiedziec czemu ov_counter liczone jest w kodzie jako 1, a powinno byc IMHO jako caly okres timera. imho to blad.

    4\/3!!
  • REKLAMA
  • Pomocny post
    #3 5587855
    skynet_2
    Poziom 26  
    1. Tak

    2. falling-rising owszem ale jeżeli impuls jest większy i następuje przepełnienie licznika to ov_counter podaje liczbę tych przepełnień.

    edit:
    Freddie Chopin napisał:

    zmienna counts nie jest nigdzie zerowana.

    ale nie musi być zerowana skoro występuje tylko jedno równanie, przy kolejnych impulsach counts przyjmie ich wartość/długość.

    Freddie Chopin napisał:
    0xFF * ov_counter

    faktycznie powinno tak być ale rzutujesz 16 bitową na 32 bitową i czy przypadkiem nie zadziała to jak <<16 ?

    edit2: nie zadziała ale można by
    counts=(uint32_t)falling-(uint32_t)rising+(((uint32_t)ov_counter)<<16);
  • #4 5587994
    mirekk36
    Poziom 42  
    dzięki za odpowiedzi, też mi właśnie się to jakieś wydawało pokręcone i że trzeba by ten ov_counter przemnożyć przez maksymalną wartość licznika a nie poprostu dodać .....

    ale tak dla ciekawości podaję źródło tego kodziku:

    http://winavr.scienceprog.com/avr-gcc-tutorial/program-16-bit-avr-timer-with-winavr.html

    stronka ta wyglądała mi na taką z której można się czasem pouczyć - ale jak widać sadzą tam duże błędy

    (i skąd tu początkujący ma sobie zassać troszkę wiedzy jak w C obsługiwać różne bloki funkcjonalne AVRków ??? Oczywiście wiem, że można z różnych źródeł ale chyba sami przyznacie, że ciężko początkującemu rozszyfrować czasem zawiłą składnię bez jakichś dobrych komentarzy czy opisów :( :(
  • REKLAMA
  • #5 5588527
    BoskiDialer
    Poziom 34  
    Co do kodu:
    1/ nie dołącza się pliku iom8.h. Ten plik jest dołączany przez io.h. Należy przy kompilacji przekazać parametr -mmcu=atmega8
    2/ Makro "ICP" korzysta z "PINB0", ale to nie jest bit od zmiennej PINB, żeby można było odczytać. To nie jest nawet maska odpowiedniego bitu. To jest numer bitu w rejestrze PINB, pod którym jest pin 0. PINB0 jest równe 0. W efekcie warunek nigdy nie będzie spełniony.
    3/ Wartości konfiguracyjne zapisane w postaci bezpośrednich wartości - strasznie nie czytelne.
    4/ Rozumiem, że kod ma liczyć długość stanu wysokiego sygnału podanego na PINB0. Wtedy jednak zmienna "ov_counter" jest liczbą przepełnień timera (a nie liczby tyknięć), a więc trzeba zastosować poprawkę, jaką pokazał skynet_2

    Kod jest mówiąc w skrócie straszny. Co do samego Timer1 Capture - jest to przepisanie wartości timera (TCNT1) do ICR1 w momencie wystąpienia jakiegoś(ustawionego) zbocza. Jeśli wartość licznika traktować jako czas, to wartość ICR1 jest znacznikiem czasu kiedy wystąpiło zdarzenie. Jako że zbocze narastające może pojawić się w dowolnym momencie - przypuśćmy gdy TCNT1 = 0x1234 - to jeśli zbocze opadające pojawi się gdy TCNT1 = 0x1235, bez tego odejmowania uzyskał byś czas pomiędzy ostatnim przepełnieniem timera a zboczem opadającym. Z różnicy można wyliczyć czas pomiędzy dwoma zdarzeniami - tutaj dwoma zboczami.
  • REKLAMA
  • #6 5590562
    Dr.Vee
    VIP Zasłużony dla elektroda
    mirekk36 napisał:
    (i skąd tu początkujący ma sobie zassać troszkę wiedzy jak w C obsługiwać różne bloki funkcjonalne AVRków ??? Oczywiście wiem, że można z różnych źródeł ale chyba sami przyznacie, że ciężko początkującemu rozszyfrować czasem zawiłą składnię bez jakichś dobrych komentarzy czy opisów :( :(

    W C (inaczej niż w Bascomie) nie ma specjalnej składni do obsługi różnych bloków funkcjonalnych. Tak samo jak w asemblerze musisz wszystko obsłużyć sam - inicjalizację rejestrów, obsługę przerwań itd.

    Komentarze w kodzie powinny służyć wyjaśnianiu rzeczy, które nie są oczywiste - stąd wyjaśnianie składni języka C w komentarzu może zdarzyć się tylko w tutorialu dla poczatkujących :)

    Dla mnie jedynym pewnym źródłem informacji o C dla AVRów jest dla mnie dokumentacja projektu avr-libc. No i może czasem forum avrfreaks.net :)

    Pozdrawiam,
    Dr.Vee
  • #7 5785016
    arek4ever
    Poziom 2  
    BoskiDialer napisał:
    Co do kodu:
    1/ nie dołącza się pliku iom8.h. Ten plik jest dołączany przez io.h. Należy przy kompilacji przekazać parametr -mmcu=atmega8
    2/ Makro "ICP" korzysta z "PINB0", ale to nie jest bit od zmiennej PINB, żeby można było odczytać. To nie jest nawet maska odpowiedniego bitu. To jest numer bitu w rejestrze PINB, pod którym jest pin 0. PINB0 jest równe 0. W efekcie warunek nigdy nie będzie spełniony.
    3/ Wartości konfiguracyjne zapisane w postaci bezpośrednich wartości - strasznie nie czytelne.
    4/ Rozumiem, że kod ma liczyć długość stanu wysokiego sygnału podanego na PINB0. Wtedy jednak zmienna "ov_counter" jest liczbą przepełnień timera (a nie liczby tyknięć), a więc trzeba zastosować poprawkę, jaką pokazał skynet_2

    Kod jest mówiąc w skrócie straszny. Co do samego Timer1 Capture - jest to przepisanie wartości timera (TCNT1) do ICR1 w momencie wystąpienia jakiegoś(ustawionego) zbocza. Jeśli wartość licznika traktować jako czas, to wartość ICR1 jest znacznikiem czasu kiedy wystąpiło zdarzenie. Jako że zbocze narastające może pojawić się w dowolnym momencie - przypuśćmy gdy TCNT1 = 0x1234 - to jeśli zbocze opadające pojawi się gdy TCNT1 = 0x1235, bez tego odejmowania uzyskał byś czas pomiędzy ostatnim przepełnieniem timera a zboczem opadającym. Z różnicy można wyliczyć czas pomiędzy dwoma zdarzeniami - tutaj dwoma zboczami.




    Ja w sprawie tego "strasznego kodu":jak mam prawidłowo zadeklarować rejestry PORTD oraz DDRD,żeby uruchomic tryb input capture na PD4 ? Używam atmegi 128.czym zastąpić makro "ICP" "PIND4" w moim przypadku,żeby tryb ruszył?.Ponadto avr studio "nie widzi mi" zmiennych typu "uint16_t oraz uint32_t".Zmieniłem je na unsigned int oraz zrezygnowałem z rzutowania (uint32_t).Program się kompiluje,ale nic nie przechwytuje.Dołączam swój kod w załączniku.Proszę o pomoc.
    Z góry dziękuję i pozdrawiam.
REKLAMA