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

[Atmega32][Avr-assembler] - Timer1 w trybie porównania przerwanie co 1s

emacs 06 Maj 2016 09:19 1266 22
  • #1 06 Maj 2016 09:19
    emacs
    Poziom 6  

    Cześć, działam sobie nad zadaniem: program Timer1 działa w trybie porównania( CTC). Licznik T/C1 taktowany jest wewnętrznym sygnałem zegarowym. Wpisz odpowiednią wartość do rejestru OCR1A. Licznik zlicza od 0 do odpowiedniej wartości i po jej osiągnięciu generuje przerwanie. Proszę ustawić preskaler. Dioda podłączona do PA.7 mruga w takt licznika co 1s.

    I to co mam do tej pory:

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    czy ktoś mógłby zerknąć czego jeszcze mi tutaj brakuje? Wiem, że muszę ustawić preskaler na 34285 aby uzyskać przerwanie co 1 sekundę ale nie mogę go ustawić poprzez rejestr TEMP bo dostaję błąd

    error: Operand(s) out of range in 'ldi r17,0x85ed'

    Ktoś podpowie? Dzięki

    0 22
  • #2 06 Maj 2016 09:38
    Andrzej__S
    Poziom 28  

    Do wprowadzenia wartości 16-bitowej do rejestru 16-bitowego (jakim jest OCR1A) musisz użyć analogicznej techniki, jak przy ustawianiu wskaźnika stosu (SP).

    Dokładniej mówiąc, rejestr TEMP (r17) jest ośmiobitowy. Liczba 34285 wykracza poza zakres liczby 8-bitowej, więc się w nim nie zmieści. Należy ją rozdzielić na dwa bajty za pomocą funkcji low(34285) i high(34285) i wprowadzić odpowiednio do rejestrów OCR1AL i OCR1AH (kolejność jest istotna).

    0
  • #3 06 Maj 2016 09:57
    emacs
    Poziom 6  

    Masz na myśli instrukcję out zamiast ldi?
    Gdy zrobię tak:

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    to teraz z kolei dostaję błąd Invalid number.

    0
  • #4 06 Maj 2016 10:00
    Andrzej__S
    Poziom 28  

    Mam na myśli technikę analogiczną do ustawiania wskaźnika stosu:

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    0
  • #5 06 Maj 2016 10:23
    emacs
    Poziom 6  

    Dziekuję, faktycznie mogę tak wpisać większą liczbę ale mam 2 pytania

    - dlaczego nazwa rejestrów do których ją wpisuje to OCR1AL a nie OCIE1AL? i OCR1AL zamiast OCIE1AH?

    i drugie za co odpowiada ta wartość w rejestrze OCIE1A? to jest ustawianie tego preskalera?

    Kod się kompiluje ale nadal dioda nie reaguje

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    Dodano po 5 [minuty]:

    Chciałbym zrozumieć jak działa takie najprostsze przerwanie timera1 w trybie porównania i w jaki sposób ustawiać odpowiedni interwał ale większość kodów które są w sieci dotyczą języka C a tutaj mam assemblera.

    0
  • #6 06 Maj 2016 10:34
    2rs232
    Poziom 17  

    Brakuje w kodzie konfiguracji rejestru TCCR1B.

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    I jeszcze kolejność zapisu, najpierw starszy bajt. (w dokumentacji rozdział "Accessing 16-bit Registers")
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    0
  • #7 06 Maj 2016 10:56
    Andrzej__S
    Poziom 28  

    emacs napisał:
    dlaczego nazwa rejestrów do których ją wpisuje to OCR1AL a nie OCIE1AL? i OCR1AL zamiast OCIE1AH?

    Myślę, że powinieneś poczytać datasheet mikrokontrolera, bo mylisz pojęcia.
    OCIE1A to nie rejestr tylko nazwa bitu w rejestrze TIMSK, który to bit (ustawiony na wartość 1) zezwala na przerwania od porównania wartości licznika/timera1 (czyli rejestru TCNT1) z rejestrem OCR1A.

    emacs napisał:
    i drugie za co odpowiada ta wartość w rejestrze OCIE1A? to jest ustawianie tego preskalera?

    Nie. Ustawienie preskalera to bity CS2:CS1:CS0 w rejestrze TCCR1B. Ich wartość należy ustawić w zależności od potrzeb zgodnie z tabelką na stronie 110.

    Kolega powyżej podał przykład, jak w asm ustawiać poszczególne bity w rejestrach oraz wprowadzać wartości do rejestrów 16-bitowych. Mam tylko uwagę: preskaler o wartości 1 będzie raczej za mały, aby uzyskać opóźnienie 1 sekundy, chyba że taktujemy procesor kwarcem zegarkowym.

    EDIT:
    Uzupełniając to, co zauważył kolega 2rs232, do ustawienia trybu CTC służą bity WGM13:WGM12:WGM11:WGM10 zgodnie z tabelką na stronie 109. Część z nich znajduje się w rejestrze TCCR1A, a część w TCCR1B.

    0
  • #8 06 Maj 2016 11:12
    2rs232
    Poziom 17  

    Jeszcze takie błedy:
    jest

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    powinno być
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    jest
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    powinno być
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    0
  • #9 06 Maj 2016 12:18
    emacs
    Poziom 6  

    Dzięki wam za odpowiedzi, ale gdy zamieniam

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    na

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    to dostaje błąd
    Use of undefined or forward referenced symbol 'OC1ADDR' in .org

    Mój kod po poprawkach wygląda teraz tak :

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    program się kompiluje, uruchamia ale nie widzę w symulacji żadnej zmiany diod na PORTA.

    0
  • #10 06 Maj 2016 13:06
    Andrzej__S
    Poziom 28  

    emacs napisał:
    Use of undefined or forward referenced symbol 'OC1ADDR' in .org

    Powinno być OC1AADDR.

    Nie wiem czy czytasz uważnie, ale zwróć też uwagę na to co napisałem wcześniej:
    Andrzej__S napisał:
    preskaler o wartości 1 będzie raczej za mały, aby uzyskać opóźnienie 1 sekundy, chyba że taktujemy procesor kwarcem zegarkowym


    Jeśli nic nie zmieniałeś w fusebitach, to fabrycznie mikrokontroler jest ustawiony na taktowanie wewnętrzne 1MHz. Dla tej częstotliwości powinieneś mieć ustawiony preskaler na 64, a rejestr OCR1A na 15625, aby przerwanie pojawiło się co 1 sekundę. Z preskalerem równym 1 tylko przy bardzo niskim taktowaniu (np. kwarcem zegarkowym) będziesz widział jakieś miganie, czyli dla "fabrycznego" taktowania:

    zamiast:
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    powinno być:
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    zamiast:
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    powinno być:
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    zamiast:
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    powinno być:
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    Nie gwarantuję, że zauważyłem wszystkie błędy.

    EDIT:
    Właściwie to nie wiem też, dlaczego masz w przerwaniu zliczanie do 125. Chciałeś w ten sposób uzyskać okres zapalania/gaśnięcia diody co 125 sekund?

    0
  • #11 06 Maj 2016 13:07
    2rs232
    Poziom 17  

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    Jedno "A" za mało ;-)
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    OC0ADDR to wektor dla przerwania od Timer0.

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    edit:
    Zastosuj poprawki które podał Andrzej__S, z przerwania możesz wtedy wywalić dodatkowy "licznik"
    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    0
  • #12 06 Maj 2016 13:59
    emacs
    Poziom 6  

    Cytat:
    Właściwie to nie wiem też, dlaczego masz w przerwaniu zliczanie do 125. Chciałeś w ten sposób uzyskać okres zapalania/gaśnięcia diody co 125 sekund?


    Chciałem to zrobić według treści z zadania jako że miał to być tryb porównania do zadanej wartości i teraz ustawiłem 125 ale sprawdzałem też na innych. W momencie gdy wartość timera jest równa tej zadanej ( co ma następować co ok 1 sekunde ) to dioda się zapala a następnym razem gaśnie.

    Tutaj kod z poprawkami i komentarzami co do ostatniej cześci przerwania w której najprawdopodobniej mam błąd i dlatego dioda " nie mruga".

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    dodaje również zrzut z symulacji avr studio 4 pokazujące że stan PORTA nie zmienia się podczas symulacji.
    [Atmega32][Avr-assembler] - Timer1 w trybie porównania przerwanie co 1s

    Dodano po 19 [minuty]:

    Wywaliłem z przerwania dodatkowy licznik, czyli w tej chwili przerwanie następuje co 1 sekundę i dioda powinna się zapalać co sekundę ale nadal nic.

    Aktualny kod:

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #13 06 Maj 2016 14:50
    2rs232
    Poziom 17  

    Działa ;-)
    Ustaw Breakpoint na linijce (prawy myszy Toggle Breakpoint)

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod

    naciśnij F5 (Run)
    jak zatrzyma się na Breakpoint wykonaj kod przerwania krokowo F11
    naciśnij F5 (Run)
    jak zatrzyma się na Breakpoint wykonaj kod przerwania krokowo F11
    itd.

    Zamiast 15625 ładuj do OCR1A 15624.
    Wieczorem wrzucę inny sposób migania tym ledem.

    0
  • #14 06 Maj 2016 14:55
    Andrzej__S
    Poziom 28  

    Napisz jaką masz faktyczną częstotliwość taktowania procesora, bo w symulatorze masz ustawioną 4MHz, a w takim przypadku trzeba dobrać inne parametry konfiguracyjne timera.
    Jeśli sprawdzasz to w symulatorze, to mam nadzieję, że nie wykonujesz programu krok po kroku. Zdajesz sobie chyba sprawę, że program musi wykonać ponad 1mln kroków, abyś zauważył efekt (Cyckle Counter w okienku procesora musi być większy od 1mln).

    0
  • #15 06 Maj 2016 15:11
    emacs
    Poziom 6  

    Cytat:
    naciśnij F5 (Run)
    jak zatrzyma się na Breakpoint wykonaj kod przerwania krokowo F11
    naciśnij F5 (Run)
    jak zatrzyma się na Breakpoint wykonaj kod przerwania krokowo F11
    itd.


    Tak faktycznie widać zmiany na PORTA, myślałem, że mogę odpalić auto step i będę widział zmiany diody w czasie rzeczywistym co 1 sekundę.

    Cytat:
    Napisz jaką masz faktyczną częstotliwość taktowania procesora, bo w symulatorze masz ustawioną 4MHz


    Tak na prawdę nie wiem ;( Bo program mam wykonać w ramach nauki a na zajęciach dostajemy różne urządzenia (Atmega32 ) i nie jestem w stanie powiedzieć jaką będę miał częstotliwość. Ale chodzi o to abym zrozumiał w jaki sposób dostosować Timer1 do wymogu "przerwania co jedną sekunde" do odpowiedniej częstotliwości. Czy możecie mi to jeszcze wytłumaczyć?

    Np jeżeli częstotliwość to 8MHz to żeby uzyskać przerwanie co 1 sekundę to w jaki sposób wyliczyć odpowiedni preskaler i wartośc OCR1A?

    0
  • #16 06 Maj 2016 15:57
    Andrzej__S
    Poziom 28  

    emacs napisał:
    Np jeżeli częstotliwość to 8MHz to żeby uzyskać przerwanie co 1 sekundę to w jaki sposób wyliczyć odpowiedni preskaler i wartośc OCR1A?

    Zapewne tak, jak jest napisane w dokumentacji mikrokontrolera.
    Wartość dla 1 sekundy:
    OCR1A=((częstotliwość procesora)/preskaler)-1
    Preskaler należy wybrać z listy dostępnych (szczegóły w dokumentacji) tak, aby wartość OCR1A nie była większa niż 65535.

    0
  • #17 06 Maj 2016 17:22
    emacs
    Poziom 6  

    Proszę o odpowiedź czy dobrze rozumiem te obliczenia i zależności między częstotliwością, czasem
    przerwania a preskalerem.

    TIMER1

    Wartość dla 1 sekundy
    OCR1A=((częstotliwość procesora)/preskaler)-1

    Zgodnie z tabelką na stronie 110 mamy do wyboru preskaler:

    - 8
    - 64
    - 256
    - 1024

    więc obliczam według wzoru wartości dla każdego preskalera i biorę ten
    którego wartośc jest najwyższa a jednocześnie nie przekracza 65535 dla
    TIMERA1 ( który jest 16 bitowy ) i 255 dla TIMERA0 ( który jest 8 bitowy ) np

    Dla 1MHz

    preskaler 8
    OCR1A = (1000000 / 8 ) - 1 = 125000 - 1 = 124999 - odpada, przekracza 16 bitów

    preskaler 64
    OCR1A = (1000000 / 64 ) - 1 = 15625 - 1 = 15624 - pasuje,

    preskaler 256
    OCR1A = (1000000 / 256 ) - 1 = 3906,25 - 1 = 3905,25 - odpada bo.. liczba nie
    jest cakowita i dlatego że można znaleźć wartość wyższą dobrze mówię?

    więc wybieram preskaler 64 i zapisuję

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    i ustawienie OCR1A

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    -----------------------------------------
    Wartość dla 4 sekund
    OCR1A=((częstotliwość procesora)/preskaler)-4

    preskaler 64
    OCR1A = (1000000 / 64 ) - 4 = 15625 - 4 = 15621

    i analogicznie


    --------------------------------------------
    Dla częstotliwości 8MHz


    Wartość dla 1 sekundy

    preskaler 8
    OCR1A=((częstotliwość procesora)/preskaler)-1

    OCR1A = (8000000 / 8 ) - 1 = 1000000 - 1 = za dużo ;)


    preskaler 64
    OCR1A = (8000000 / 64 ) - 1 = 125000 - 1 = 124999 - za dużo

    preskaler 256
    OCR1A = (8000000 / 256 ) - 1 = 31250 - 1 = 31249 - ok, znam preskaler więc

    assembler

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    i ustawienie OCR1A

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod



    Czy dobrze to zrozumiałem?

    0
  • #18 06 Maj 2016 17:40
    2675900
    Użytkownik usunął konto  
  • #19 06 Maj 2016 18:01
    emacs
    Poziom 6  

    O to tego nie rozumiem, jeszcze raz poproszę ;)

    Dlaczego dla przerwania "co jedną sekundę" odejmuje 1 a dla przerwania "co 4 sekundy" mnożę przez 4?

    Dodano po 5 [minuty]:

    Bo w takim wypadku dla 1 sekundy powinno być razy 1 a nie minus jeden bo w przypadku 4 sekund też zliczam od zera.

    0
  • Pomocny post
    #20 06 Maj 2016 18:03
    Andrzej__S
    Poziom 28  

    Andrzej__S napisał:
    Wartość dla 1 sekundy:
    OCR1A=((częstotliwość procesora)/preskaler)-1


    emacs napisał:
    Wartość dla 4 sekund
    OCR1A=((częstotliwość procesora)/preskaler)-4


    Jedynka w podanym przeze mnie wzorze nie oznacza 1 sekundy.
    Jeden trzeba odjąć z innych względów. Po prostu licznik nie zaczyna liczyć od 1 tylko od 0, więc odliczanie np. do 5 oznacza (0 1 2 3 4 5), czyli 6 impulsów.

    Wzór ogólny wygląda tak:
    Code:
    OCR1A = ( t * ( f / p ) ) - 1
    
    gdzie:
    t - czas między przerwaniami [s]
    f -częstotliwość taktowania mikrokontrolera [Hz]
    p - preskaler

    Tam, gdzie wartość OCR1A jest duża, a oczekiwana precyzja odliczania mała (jak np. w przypadku migania diodą), odjęcie tej jedynki niewiele zmieni, ale w niektórych sytuacjach jest to bardzo istotne.

    0
  • #21 06 Maj 2016 18:51
    emacs
    Poziom 6  

    Dziękuje za wyjaśnienie ;) A więc raz jeszcze, wersja poprawiona:

    OCR1A = ( t * ( f / p ) ) - 1
    gdzie:
    t - czas między przerwaniami [s]
    f -częstotliwość taktowania mikrokontrolera [Hz]
    p - preskaler


    TIMER1
    Zgodnie z tabelką na stronie 110 mamy do wyboru preskaler:

    - 8
    - 64
    - 256
    - 1024

    Wartość dla przerwania co 1 sekundę


    Dla częstotliwości 1MHz

    preskaler 8, MAX = 65535
    OCR1A = (1 * ( 1000000 / 8 ) - 1 = 125000 - 1 = za dużo ;)


    preskaler 64
    OCR1A = (1 * ( 1000000 / 64 ) - 1 = 109375 - 1 = 109374 = za dużo ;)


    preskaler 256
    OCR1A = ( t[s] * ( f[MHz] / p ) ) - 1 = (1 * ( 1000000 / 256 ) - 1 = 3906,25 - 1 = 3905,25

    Mieści się ale nie jest to liczba całkowita więc wybieram i zaokrąglam do 0,5?
    więc tutaj byłoby to 3905 zgadza się?


    więc wybieram preskaler 256 i zapisuję

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod


    i ustawienie OCR1A

    Kod: avrasm
    Zaloguj się, aby zobaczyć kod



    Dobrze kombinuje?

    0
  • #22 06 Maj 2016 19:06
    Andrzej__S
    Poziom 28  

    emacs napisał:
    preskaler 64
    OCR1A = (1 * ( 1000000 / 64 ) - 1 = 109375 - 1 = 109374 = za dużo

    Jak to policzyłeś?
    Według moich obliczeń ( 1 * ( 1000000 / 64 ) - 1 = 15625 - 1 = 15624

    0
  • #23 06 Maj 2016 19:29
    emacs
    Poziom 6  

    Aż sam się dziwię xd Muszę spokojniej pukać w te cyferki na kalkulatorze ;)
    Ale co w tym wypadku? Bo preskaler 256 daje ( jeżeli się nie pomyliłem ;) )
    3905,25 czyli po zaokrągleniu ( można? ) do 3905 też mieści się w OCR1A i daje wartość bliższa ogólnie możliwej.

    W takim wypadku wybieramy tą najbliższą max dla OCR1A? Czy niecałkowite odrzucamy?

    Dodano po 12 [minuty]:

    Nie bliższą a dalszą miało być ;) Mylę się coś za często ;)

    Dodano po 1 [minuty]:

    Wybieramy zawsze tą NAJBLIŻSZĄ możliwej dla OCR1A, teraz rozumiem. Dzięki wielkie Panowie!

    0