Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[Atmega8][c] obsługa timera

30 Lip 2011 16:52 6847 53
  • Poziom 13  
    Witam, pomału uczę się programowania w C AVrów. W sumie to nawet napisałem to co chciałem ale teraz napotkałem problem. Opiszę o co chodzi.
    Mikrokontroler ma reagować na różne impulsy wejściowe i to jakoś opanowałem. Ale przy niektórych powinien zmierzyć czas przez jaki pojawia się stan wysoki lub niski na wejściu i zależnie od czasu trwania tego stanu odpowiednio zareagować. Czas pomiaru powinien być robiony z dokładnością 100ms czyli nie tak bardzo dokładnie. Jak rozumiem bez obsługi Timerów nie obejdzie się? Czy ktoś w takim razie mógłby dać najprostszy przykład działania takiego timera w takiej konfiguracji jak pisałem, wszystko co znalazłem to strasznie zaawansowane programy i nie bardzo potrafię ich rozgryźć.
    Pozdrawiam
  • Pomocny post
    VIP Zasłużony dla elektroda
    Kodu nie mam w rękawie, ale w tym wypadku użyj ICP...
    A chwila, zapytałem Woojka G.:
    http://www.google.pl/search?q=ICP+AVR+tutorial
    I znalazłem to :
    http://winavr.scienceprog.com/avr-gcc-tutorial/program-16-bit-avr-timer-with-winavr.html
    A nawet takiego rodzynka ;) :
    https://www.elektroda.pl/rtvforum/topic1108984.html
    snnaap napisał:
    Jaki język?
    Jest w temacie... ;)
  • Poziom 13  
    Częstotliwość z jaką taktuję mikrokontroler to 1MHz, język oczywiście to C jak zaznaczyłem w temacie. A przykłady faktycznie są, i wcześniej je znalazłem ale jak dla mnie strasznie skomplikowane. Jak wiedzę sporo nauki jeszcze przede mną :) Nadal bym jednak prosił o super prosty przykład wykorzystania timera.
    Pozdrawiam
  • Pomocny post
    Poziom 38  
    Timery zwykle- choć nie zawsze- są ściśle związane z przerwaniami.
    Może od tego zacząć?
  • Pomocny post
    Poziom 38  
    Jak potrafisz angielski to w nocie są dokładnie rejestry opisane, jest ich bardzo niewiele i właściwie nietrudno poustawiać je tak, żeby otrzymać żądany tryb
  • Poziom 13  
    angielski na poziomie not katalogowych niestety jest mi obcy :(
    Pozdrawiam
  • Poziom 38  
    Poziom angielskiego w notach katalogowych nie przekracza 500 słówek.
    Reszta- to znajomość działania procesorów.
    Po polsku- Adam Górecki- jeśli nic nie wiesz.
    Co prawda Bascom- ale opis rejestrów i zasad działania jest uniwersalny.
    Mirosław Kardaś, Tomasz Francuz, Rafał Baranowski- obie części, Andrzej Pawluczuk- oba tomy.
    No i do C- Stephen Prata, Stephan G. Kochan.
    Coś z elektroniki- Tietze, Schenk- ale raczej starsze wydania.
  • Pomocny post
    VIP Zasłużony dla elektroda
    No jak 46 linijek kodu od ICP (liczone razem z komentarzami , nawiasami i klamrami) to jest zbyt skomplikowane, to ja wymiękam... Proponuję pytać konkretnie co jest niezrozumiałe..
  • Poziom 13  
    Mam książkę Pana Kardasia, mam notę a WinAVR zainstalowałem w wtorek. Z czego przy programowaniu spędziłem 2-3 godzinny dziennie więc nie oszukujmy się, nic nie jest dla mnie zrozumiałe z tematu timerów. Patrząc do książki a szczególnie na przykłady z kursu znalezionego w sieci udało mi się napisać program który ma kilka warunków, pętli i temu podobnych a co najważniejsze działa tak jak to sobie wyobraziłem. Bo tak jest mi najprościej się uczyć. Teraz zachciało mi się go jeszcze rozbudować o jedną funkcję, czyli pomiar czasu przez jaki jest na jednym z wejść stan niski i odpowiednie zareagowanie jeśli ten czas mieści się w pewnych granicach, dlatego miałem nadzieję na najprostszy z możliwych przykładów abym mógł na nim po eksperymentować.
    Pozdrawiam
  • Pomocny post
    Poziom 11  
    Code:

        //timer 1 16bit konfiguracja (ICP1)
       TCNT1=0; //ustawienie poczatkowej wartosci timera 1
       TCCR1B |= (1<<ICES1);              //pomiar na narastajacym zboczu
       TIMSK |= (1<<TICIE1) | (1<<TOIE1); //zezwolenie na przerwanie od ICP i od overflow
       TCCR1B |= (1<<CS12) | (1<<CS10) ;  //prescaler 1024 i start timera


    icp input capture pin jezeli na pinie wystąpi akcja procek wskoczy do przerwania ponizej


    Code:

    ISR( TIMER1_CAPT_vect )  //przerwanie od icp1
       {
          cli();  //globalne zabronienie przerwan
          sygnal=ICR1;        //odczyt timera
          TCNT1=0;         //zerowanie timera
          i++;            //dodanie wartosci i
          wyskok_do_funkcji();
          sei();                         //globalne zezwolenie na przerwanie
       }   // koniec przerwania   
  • Pomocny post
    Poziom 42  
    PisorDemet napisał:

    Code:

    ISR( TIMER1_CAPT_vect )  //przerwanie od icp1
       {
          cli();  //globalne zabronienie przerwan
          sygnal=ICR1;        //odczyt timera
          TCNT1=0;         //zerowanie timera
          i++;            //dodanie wartosci i
          wyskok_do_funkcji();
          sei();                         //globalne zezwolenie na przerwanie
       }   // koniec przerwania   


    A po co to cli(); oraz sei(); w przerwaniu ????? może warto doczytać, że dzieje się to automatycznie i ręczne powielanie tego nie ma najmniejszego sensu?

    Po drugie - co ma oznaczać: wyskok_do_funkcji(); bo tu czuję coś dużo gorszego, co może pokazywać nawet, że kolega jeszcze nie do końca wie co to są i jak się obsługuje przerwania :(
  • Pomocny post
    Poziom 11  
    O to nawet nie wiedziałem ze nie trzeba używać cli(); i sei(); w przerwaniu. Dziękuję za radę. A tutaj wkleiłem jakiś przykładowy kod z mojego programu i wystąpienie przerwania wywołuje także wykonywanie funkcji, dla tego zmieniłem tylko jej nazwę na wyskok_do_funkcji() i podesłałem jako przykład. A z tym że nie wiem jak do końca się obsługuje przerwania to całkiem możliwe. Też dopiero zaczynam i nawet siedzę właśnie z Pana książką na kolanach.
  • Pomocny post
    Poziom 42  
    moons napisał:
    .... mam notę a WinAVR zainstalowałem w wtorek. Z czego przy programowaniu spędziłem 2-3 godzinny dziennie więc nie oszukujmy się, nic nie jest dla mnie zrozumiałe z tematu timerów.


    Po tak krótkim czasie spędzonym na nauce programowania w C od podstaw (jak zebrać do kupy te spędzone godziny to wyjdzie może ze 2-3 dni) to nie oszukujmy się, dosyć oczywiste jest, że niewiele będzie zrozumiałe i to nie tylko z tematu timerów. Bo tematyka jest dosyć obszerna i może jednak warto tak troszkę bardziej sukcesywnie i małymi kroczkami iść do przodu - zamiast wykonywać po chwili jeden krok milowy - bo można się wyłożyć - co widać. To chyba normalne. Pewnie, że człowiek by chciał tak od razu, dorwać jedną dwie albo nawet trzy książki i po tygodniu pisać dowolne programy. Niestety tu jeszcze poza językiem C, którego podstawy rzeczywiście można w parę dni załapać na upartego, ale trzeba się nauczyć obsługi peryferiów samych mikrokontrolerów. A to znowu dodatkowy czas i wiele godzin prób i testów.

    A przy okazji we wspomnianej książce, kolega ma w rozdziale na temat dekodowania pilotów podczerwieni, przykład z wykorzystaniem przerwania ICP i dokładnych pomiarów czasu. Tylko jak znam życie to opisowo mówiąc, zapewne nie było czasu jeszcze tego poczytać ;)

    Dodano po 4 [minuty]:

    PisorDemet napisał:
    Też dopiero zaczynam.
    ano właśnie, to trzeba uważać z tymi wyskokami do funkcji w przerwaniach ponieważ, każdy taki wyskok to kolejne zabranie cennej pamięci RAM na potrzeby stosu, a jeśli w takiej funkcji użyjemy jeszcze zmiennych lokalnych to stos jeszcze bardziej wzrośnie. Więc jakby tak jeszcze jakaś funkcja z funkcji albo kilka wyskoków w bok - to za chwilę tragedia murowana ;)

    Generalnie kod przerwania powinien być jak najkrótszy, jak najbardziej przejrzysty a funkcje jeśli już miałaby by być wywoływane to takie praktycznie typu inline albo takie gdzie piszący kod ma 100% świadomość tego co będzie działo mu się ze stosem.
  • Poziom 13  
    mirekk36 napisał:
    Po tak krótkim czasie spędzonym na nauce programowania w C od podstaw (jak zebrać do kupy te spędzone godziny to wyjdzie może ze 2-3 dni) to nie oszukujmy się, dosyć oczywiste jest, że niewiele będzie zrozumiałe i to nie tylko z tematu timerów. Bo tematyka jest dosyć obszerna i może jednak warto tak troszkę bardziej sukcesywnie i małymi kroczkami iść do przodu - zamiast wykonywać po chwili jeden krok milowy - bo można się wyłożyć - co widać.


    No właśnie chyba jednak mnie to na razie przerasta :( Przykład oczywiście w książce że znalazłem, przeczytałem i przeglądałem ale jakoś nie dotarł do mnie i nie bardzo potrafiłem przystosować go do swoich potrzeb.
    Pozdrawiam
  • Pomocny post
    Poziom 42  
    moons napisał:

    No właśnie chyba jednak mnie to na razie przerasta :(


    Gwarantuję, że nic kolegi nie przerasta ;) Tylko jak zwykle - trzeba mniejszymi kroczkami no i czasu trzeba. Tak w ogóle to zanim kolega przejdzie do rozpatrywania takich rzeczy, proponuję wrócić jeszcze do rozdziałów typu "Multipleksowanie LED". Tam są przykłady wykorzystujące i omawiające przerwania od timerów jeśli chodzi o podstawy, łącznie z wyliczaniem czasów , obsługą , doborem czasów itp itd. Jak się tego nie przejdzie z pełnym zrozumieniem to nie dziwię się, że ciężko analizować dalsze. Wbrew pozorom, ćwiczenia dobrane są bardzo starannie i ułożone w takiej kolejności żeby uczyć się po kolei. I zwykle osoby, które chciały zrobić żabi skok w przód bardzo często się poddawały szybko. A potem się okazywało, że jak wrócą do pewnych rozdziałów i spokojnie czytają jeszcze raz i jeszcze raz - do tego mnie też przecież można spokojnie pomęczyć z pytaniami - to okazywało się, że co chwilę mała eureka! i co chwilę kolejne barykady okopującej się niewiedzy padły ;)
  • Poziom 11  
    Jak już Kolega nabierze wprawy z przerwaniami i timerami to można osiągnąć zamierzony cel w następujący sposób:
    Dajemy sygnał (którego długość trwania chcemy mierzyć) na wejście INT0 oraz INT1 jednocześnie, przy czym pierwsze ustawiamy na zbocze rosnące a drugie na spadające, w przerwaniu INT0 startujemy timer1 a w przerwaniu INT1 zatrzymujemy go, potem odczytujemy wartość TCNT1 i w zależności od preskalera otrzymujemy bezpośrednio czas trwania impulsu.
    Można też dodać przerwanie dla timera na wypadek gdyby licznik się przekręcił (gdy chcemy mieć większą dokładność pomiaru czasu ustawiamy perskaler na niższe wartości lecz może to skutkować osiągnięciem TOPu i zliczaniem od nowa).
    Jakieś pytania? ;-)

    ---------------------------------------
    Kliknij pomógł jeśli pomogłem!
  • Pomocny post
    Poziom 42  
    percol napisał:
    Jak już Kolega nabierze wprawy z przerwaniami i timerami to można osiągnąć zamierzony cel w następujący sposób:
    Dajemy sygnał (którego długość trwania chcemy mierzyć) na wejście INT0 oraz INT1 jednocześnie, przy czym pierwsze ustawiamy na zbocze rosnące a drugie na spadające, w przerwaniu INT0 startujemy timer1 a w przerwaniu INT1 zatrzymujemy go, potem odczytujemy wartość TCNT1 i w zależności od preskalera otrzymujemy bezpośrednio czas trwania impulsu.


    To też oczywiście jest sposób, jak każdy tylko proszę zwrócić uwagę też na to, że identyczną funkcjonalność uzyskujemy właśnie stosując przerwanie ICP timera1, gdzie w samym przerwaniu można zmieniać bitem ICIES sposób reakcji na zbocze rosnące i opadające po kolei. A do tego wykorzystać ten sam timer - dokładnie jego rejestr przechwytujący ICR1. Co więcej - ponieważ jest to timer 16-bitowy to o wiele łatwiej mierzyć różnej długości czasu.

    Ale w sumie - ten przykład kolegi byłby może też i ciekawszy na taki pierwszy etap nauki bo dodatkowo dojdzie wykorzystanie jeszcze przerwań INTx, a tym bardziej, że nie zawsze przecież jest wolny timer1 więc warto wiedzieć i przetrenować to inaczej - w oparciu o inne przerwania.
  • Poziom 13  
    No to zacznijmy jeszcze raz:)
    Zacznę od konfiguracji Timera. Założyłem sobie że dokładność pomiaru ma być 100ms. uK Atmega8A-PU mam taktowany 1000000Hz
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Jak rozumiem po takim kawałku kodu timer zliczy 97 impulsów które będą trwały 100 ms. Timer drugi bo w nocie nie znalazłem tabelki przy Timerze0 z trybami pracy.
  • Pomocny post
    Poziom 30  
    Odliczy dokładnie:
    1/1M = 0,000001
    co 1024 tyknięcie zegara impuls czyli z racji że 100ms to 0.1s więc:
    0.1/0.001024 = 97.65625 impulsów
    Więc w rzeczywistości odliczy 99.328ms.

    Więc możesz w przerwaniu dać funkcję która co 97 przerwanie zwiększa zmienną o 1. Potem wystarczy porównać jaką wartość ma ta zmienna np. w switch() i gotowe.
  • Poziom 13  
    ADI-mistrzu napisał:
    Więc w rzeczywistości odliczy 99.328ms.


    Tak też właśnie z moich wyliczeń wychodziło że nie będzie to dokładnie 100 ms ale do moich celów dokładność i tak stanowczo za duża :)
    Pozdrawiam

    No dobra coś wysmażyłem :) ale nie kompiluje mi się "error: static declaration of '__vector_3' follows non-static declaration" znaczy się że coś źle zadeklarowałem tylko nie mam pojęcia co.
    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    Poziom 30  
    Jak ustawiasz wartości początkowe jak np. wyjścia portu w rejestrze DDR to nie musisz robić |=, wystarczy =.
    Dobry zwyczaj to także robienie tabulacji (Tab) w funkcjach, czyli:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Jest kod bardziej czytelny, ale to takie spostrzeżenia :wink:

    A Twój problem to wpisanie przerwania do głównej funkcji main(), dlatego moim zdaniem lepiej jest takie rzeczy deklarować na początku przed main(), po za tym zmienne powinny byc globalne a nie lokalne czyli także po za main(). Tak więc Twój kod powinien wyglądać tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Czyż nie łatwiej się czyta program z takimi wcięciami? :wink:

    Pozdrawiam
  • Poziom 13  
    No właśnie już do tego doszedłem że źle umieściłem fragmenty kodu. Po zamianie ruszyło jak trzeba i mój pierwszy timer uruchomiony :):) Teraz tylko muszę coś przećwiczyć żeby wynik wychodził mi też w częściach sekundy a nie tylko sekundach. Bo pomiar mi potrzebny to np 1 s i 200 ms a nie tylko 1 sekunda.
    No i jeszcze jedno, czy teraz ten timer nie będzie mi przeszkadzał w innym fragmencie kodu?
    Bo miałem napisane coś takiego że po uruchomieniu uK, procek czekał 15 sekund na impuls jeśli go nie było to wykonywał różne rzeczy ale miałem to wykonane przez _delay_ms() czy teraz to trzeba przerabiać?
    Z wcięciami faktycznie łatwiej tylko że w tym moim kodzie wychodzi więcej wcięć niż samego tekstu :):)
    Pozdrawiam
  • Poziom 42  
    ADI-mistrzu --> dlaczego nie dość, że sam popełniasz błąd wpisując w kodzie programu:

    #define F_CPU 1000000UL

    to jeszcze polecasz go innym początkującym? Jakiś czas temu udało się większości ludzi na elektrodzie wytłumaczyć, że to dosyć poważny błąd, który w ciut większych projektach przez nieuwagę przynosić może sporo zamieszania, jednak ostatnio znowu totalna plaga i prawie wszyscy wymieniają się znowu fragmentami kodów, w których widnieje ta definicja.

    Podejrzewam, ale tylko podejrzewam , że teraz wynika to z tego, że sporo osób przerzuciło się na mało niestety dopracowane AVR Studio 5 w którym nie ma już tak prostego miejsca do wpisania częstotliwości taktowania procesora jak to było w AVR Studio4 - ale zapewniam cię, że się da to zrobić i nawet w AVRS5 - tylko trzeba głęboko wejść w opcje samego kompilatora AVR GCC i tam dodać parametr do automatycznie generowanego pliku makefile -DF_CPU xxxxxxx

    ale jeśli robisz ten błąd nie z powodu AVRS5 to polecam z nim skończyć ;) .....

    Albo wrócić do AVRS4 albo jeszcze lepiej do ECLIPSE. Bo nie tylko to co wyżej napisałem stanowi o tym że AVRS5 to jeszcze nadal jest niedoróba :( .... problemy są nadal jeszcze z ich toolchain'nem. Nawet jeśli ta nazwa obco dla ciebie brzmi, to może też wyjść i odbić się czkawką w najmniej oczekiwanym momencie - co zaowocuje sporą ilością straconego czasu na szukanie błędów w swoim programie albo w procesorze i sporą ilością wyrwanych włosów z głowy z powodu frustracji ;)
  • Poziom 17  
    kolego moons:

    Też nie dawno zacząłem bawić się AVR-kami w C i powiem szczerze, że jeśli korzystasz tylko z zasobów sieci www do nauki bądź przykładów to skończ z tym i kup książkę Mirka albo kolegi tmf. Ja kupiłem i nie żałuję. Poza tym czytaj PDF-a Atmela i wszystko się wyjaśni. Po 2 tygodniach studiowania i prób czuję się mniej zestresowany i bardziej pod kontrolą pisząc prościutkie programy. Co daje mi pewność że mogę zrobić kolejny krok w przód.
  • Poziom 13  
    mirekk36 napisał:
    ADI-mistrzu --> dlaczego nie dość, że sam popełniasz błąd wpisując w kodzie programu:


    Muszę stanąć w obronie ADI-mistrza bo to wyszło ode mnie i ja pierwszy to popełniłem. Używam WinAVR bo taki był w przykładach z pierwszego kursu jaki miałem przed oczami i tak mi zostało. Ale zawsze miałem wpisywane:
    #define F_CPU 1000000
    i program ładnie się kompilował a jak sobie zrobiłem MakeFile do tego przykładu z timerem to nie chciało mi się kompilować. Zerknąłem do tego pliku i brakowało mi UL na końcu więc dopisałem.
    Nie mam pojęcia dlaczego akurat teraz utworzył się inny MakeFile.
    @Suchy, książkę jak pisałem posiadam i sobie chwalę. Choć jeśli mogę mieć jedno zastrzeżenie to tak dla całkiem początkujących to ona nie jest. Trzeba jednak trochę wiedzieć żeby ta książka pomogła.
    Pozdrawiam
  • Poziom 42  
    moons napisał:
    mirekk36 napisał:
    ADI-mistrzu --> dlaczego nie dość, że sam popełniasz błąd wpisując w kodzie programu:


    Muszę stanąć w obronie ADI-mistrza bo to wyszło ode mnie i ja pierwszy to popełniłem.


    Tylko nie odbierajcie koledzy, że ja tu kogoś atakuję. Po prostu zwróciłem uwagę i podałem wyjaśnienia. A co kto z tym zrobi to już jego sprawa. Błędy związane z takim definiowaniem w pliku F_CPU jak pisałem wcześniej wcale nie objawiają się tym, że coś się nie skompiluje - no ale widzę, że kolega troszkę chyba - albo odrobinę chaotycznie czyta, więc może i z tego samego powodu są problemy ze zrozumieniem tego co jest w książce. I tym bardziej, że w książce było o tym wyraźnie napisane i wyjaśnione, więc skoro kolega tego nie stosuje to śmiem twierdzić, że jednak książka nawet raz nie została przeczytana dokładnie i co ważniejsze po kolei :( ... jak znam życie to chciałoby się tak nauczyć programowania mikrokontrolerów w tydzień - co wynika zresztą z czasu jaki kolega podał wyżej przeznaczonego dotąd na naukę. A niestety - to może potrwać dłużej.

    Tymczasem sukcesywne czytanie i ćwiczenia krok po kroku przynoszą dużo dobry rezultatów nawet ludziom, którzy wcześniej nie mieli do czynienia z programowaniem. Wiem to hmmm no może nie z tysięcy maili ale z setek to już na pewno. Ma tu wybitnie zastosowanie znane powiedzenie: "co nagle to po diable" ;)

    A przy okazji polecam także książkę kolegi tmf, bo ich nigdy za mało, we własnej biblioteczce, a być może ona bardziej przypasuje na początek? Bo nie da rady nigdy napisać książki, która dotarłaby do 100% czytelników. Zawsze znajdzie się ktoś, kto powie, że jest zbyt zaawansowana albo mało przydatna.
  • Poziom 30  
    mirekk36, nie patrzyłem na dodane biblioteki więc nawet tego nie zauważyłem, ale przyznam się że mimo iż sam korzystam z Studio4 (5 jest chaotyczna, nie lubię Visual Studio MS które moim zdaniem jest zrypane całkowicie to jak Atmel przeszedł na to to kaplica...) i wpisuję częstotliwość w konfiguracji, to nie czytałem jeszcze o tym że nie powinno się w define tego ustawiać.
    Ale dzięki za informację, trzeba doczytać. :wink: