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

Jak przeliczyć opóźnienie w timerze zamiast _delay_ms(x) w AVR?

squelch 06 Maj 2017 10:40 1869 10
  • #1 16458220
    squelch
    Poziom 11  
    Witam nie mogę rozkminić jak działa przeliczenie opóznienia z kodu poniżej

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    A dokładnie chodzi mi o tę linijkę uint16_t val=delay*(F_CPU/10000UL)/1024; //Przelicz opóźnienie
    Ona uniezależnia procek od narzuconego F_CPU, ale jak to działa dokładnie?

    Pozdrawiam
  • #2 16458226
    excray
    Poziom 41  
    Zmienna val przelicza opóźnienie na ilość taktów zegara, jakie wykona on w podanym czasie, a pętla while zatrzymuje program, dopóki nie zostanie osiągnięta taka właśnie ilość taktów zegara. Nie wiem gdzie jest wyższość tej funkcji, nad biblioteką delay.h. To i tamto, tak samo bezproduktywnie blokuje procesor, z tym, że to jeszcze dodatkowo angażuje w tę czynność licznik.
  • #3 16458237
    tmf
    VIP Zasłużony dla elektroda
    @excray Wyższość w pewnych zastosowaniach polega na większej dokładności. Jeśli program korzysta z przerwań, a większość korzysta, to klasyczne delay odmierza czasy z czapy wzięte.
  • #4 16458260
    excray
    Poziom 41  
    To są jeszcze ludzie, którzy używają delaya do precyzyjnego odmierzania czasu? :-) Zresztą ta funkcja też odmierza czasy "z czapy wzięte" w momencie gdy wystąpi dłuższe przerwanie. A sekcje krytyczne czasowo - to chyba już nawet początkujący powinien wiedzieć, że trzeba zrobić atomowo. Więc zamiana siekierki na kijek tutaj ma miejsce.
  • #5 16458264
    Konto nie istnieje
    Konto nie istnieje  
  • #6 16458267
    tmf
    VIP Zasłużony dla elektroda
    Sekcje krytycznenie trwają milisekund, podobnie obsługa przerwań. Zaletą tej funkcji jest to, że błedy związane z obsługą przerwań i sekcji krytycznych nie kumulują się - łączny błąd odmierzania czasu nie przekroczy więc czasu najdłuższej sekcji krytycznej/ISR.
    Co do odmierzania czasu - zazwyczaj delay na poziomie ms i dłuższe świadczą o nie najlepiej napisanym kodzie. Ale jak zawsze są wyjątki. Akurat odmierzanie czasu na podstawie takiego delay opartego o timery jest całkiem precyzyjne. Z drugiej strony tak właśnie implementuje się delay na ARM, jako timer używa się SysTick.

    Dodano po 1 [minuty]:

    Piotrus_999 napisał:
    To też da "z czapy" jak przerwanie trafi akurat prawie w moment spełnienia warunku. Ale prawda jest że tych błędów będzie mniej.


    No i co się wtedy stanie? Problem byłby, gdyby tam było ==, a jest <.
  • #7 16458281
    excray
    Poziom 41  
    tmf napisał:
    Akurat odmierzanie czasu na podstawie takiego delay opartego o timery jest całkiem precyzyjne. Z drugiej strony tak właśnie implementuje się delay na ARM, jako timer używa się SysTick.

    Z pewnością. Ale nie robi się tego w tak brutalny sposób, że angażujemy jeden timer do tylko jednego odliczania opóźnienia. Lepiej to zrobić w taki sposób:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Uruchamiamy wcześniej timer tak, aby liczył co 1us z pełnym zakresem licznika - w tym przypadku 16-bit.
    Dzięki tak skonstruowanej funkcji możemy równolegle używać tego samego timera do odliczania kilku opóźnień.
  • #8 16458296
    Konto nie istnieje
    Konto nie istnieje  
  • #9 16458303
    tmf
    VIP Zasłużony dla elektroda
    @excray No nie za bardzo robi się to tak jak pokazałeś. Przeanalizuj dokładniej pokazany kod a zauważysz, że nie działa prawidłowo. Np. TCNT1 ma 0xFFFF, ina ma więc 0xFFFF. Odmierzasz np. 10 taktów. 0xffff-0x0009 i warunek zakończenia pętli nie jest spełniony...

    Dodano po 1 [minuty]:

    Piotrus_999 napisał:
    tmf napisał:
    No i co się wtedy stanie? Problem byłby, gdyby tam było ==, a jest <.
    Delay będzie dłuższy o czas przerwania, tak że precyzja jet średnia.

    Działanie w przerwaniu jest dokładniejsze a nie polling licznika.

    Jak już napisałeś o ARM-ach to w więszości wypadków konieczności robienia czegoś w dokładnie określonych okresach czasu lepiej wykorzystać timery jako trygierze do jakiś operacji DMA, a jeżeli się nie da to masz do dyspozycji prorytety


    Ale przerwanie zwykle trwa krótko, przy czasach rzędu ms, wprowadzony błąd może nie mieć znaczenia. Poza tym dyskusja jest o przewadze delay realizowanego w oparciu o timer vs. pętla (co na ARM jest zupełnie bez sensu). Więc trzymajmy się tego wątku.
  • #10 16458318
    excray
    Poziom 41  
    tmf napisał:
    @excray No nie za bardzo robi się to tak jak pokazałeś. Przeanalizuj dokładniej pokazany kod a zauważysz, że nie działa prawidłowo. Np. TCNT1 ma 0xFFFF, ina ma więc 0xFFFF. Odmierzasz np. 10 taktów. 0xffff-0x0009 i warunek zakończenia pętli nie jest spełniony...

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Teraz jest OK. Zapomniałem, że w AVR licznik liczy do góry.
  • #11 16458360
    grko
    Poziom 33  
    A nie lepiej po prostu nie blokować i pozwolić programowi wykonywać się? Coś w stylu:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Albo jak ktoś potrzebuje czegoś dokładniejszego to zrobić sobie programowy timer z możliwością rejstrowania callbacków. Nie wiem jaki sens ma ten blokujący delay na timerze. Mógłby się przydać do odmierzania czasu podczas jakiejś inicjalizacji sprzętu. Tylko po co marnować timer na tak bezsensowną funkcjonalność jak można ten przypadek załatwić zwykłym delay_us.
REKLAMA