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

[ATtiny2313][C] generowanie beepów przez CTC PWM

bozar88 23 Sty 2012 13:22 1721 6
REKLAMA
  • #1 10436802
    bozar88
    Poziom 13  
    Witam wszystkich.
    Kilka dni temu zacząłem przygodę z AVR i dziś trafiłem na problem nie do pokonania.

    Chcę mieć możliwość generowania tonów ostrzegawczych (beepów) za pomocą Timera1, wyjścia OC1A i trybu CTC.

    Kod wygląda tak:

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


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



    Oczekiwany rezultat
    Powinno być słychać 3 krótkie, oddzielone od siebie beepy, o rosnącej częstotliwości

    Co się dzieje:
    Po naciśnięciu przycisku następuje 1 z 4 wariantów:
    1. Nic nie słychać
    2. Słychać 2 pierwsze beepy
    3. Słychać 2 ostatnie beepy
    4. Słychać pierwszy beep

    Dlaczego tak się dzieje?
    Timer wydaje mi się naturalnym sposobem generowania beepów. Próbowałem na delay'ach, ale wyszło to koszmarnie. Jestem początkujący, więc pewnie o czymś zapomniałem. Może trzeba wyzerować jakiś rejestr timera? Proszę o pomoc.
  • REKLAMA
  • #2 10437088
    Electix
    Poziom 21  
    A czy do programu włączyłeś odpowiednią funkcję realizującą debouncing przycisku, albo ewentualnie czy zadbałeś o sprzętowe usunięcie tego efektu?

    Każdy przycisk po naciśnięciu, lub zwolnieniu przez kilka do kilkunastu ms (w zależności od jakości wykonania) generuje impulsy wynikające z drgań zestyków. I to może być powód dla którego Twój program nie do końca działa tak jak byś się tego spodziewał.

    Nie analizowałem dokładnie Twojego listingu, bo AVR'kami już od dawna się nie bawię, musiałbym sięgnąć do User Manualu żeby sprawdzić czy dobrze to poustawiałeś. Zastanawiam się tylko dlaczego akurat tak rozwiązałeś pętlę opóźniającą? Nie można było wykorzystać bezpośrednio _delay_ms?
  • REKLAMA
  • #3 10437234
    bozar88
    Poziom 13  
    Tak, debouncing to te 4 linijki zaraz po while'u.

    Ale nie w tym rzecz. Umieściłem instrukcje
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    bezpośrednio w pęlti while programu, usuwając wszystko inne. Efektem są dźwięki odgrywane w dość losowy sposób - czasem 2 pierwsze, czasem tylko pierwszy i długa przerwa, czasem 2 ostatnie, czasem 2 3 1 2...

    Zupełnie tego nie rozumiem.

    Cytat:
    Zastanawiam się tylko dlaczego akurat tak rozwiązałeś pętlę opóźniającą? Nie można było wykorzystać bezpośrednio _delay_ms?

    _delay_ms może przyjmować jako argument stałą, max. 262ms. Gdy chcę aby opóźnienie było uzależnione od zmiennej, muszę zastosować dodatkową funkcję.
  • REKLAMA
  • #4 10437451
    Electix
    Poziom 21  
    bozar88 napisał:
    Cytat:
    Zastanawiam się tylko dlaczego akurat tak rozwiązałeś pętlę opóźniającą? Nie można było wykorzystać bezpośrednio _delay_ms?

    _delay_ms może przyjmować jako argument stałą, max. 262ms. Gdy chcę aby opóźnienie było uzależnione od zmiennej, muszę zastosować dodatkową funkcję.


    Jak byś zajrzał do avr libc to w opisie funkcji _delay_ms() znalazłbyś taką oto treść:

    When the user request delay which exceed the maximum possible one, _delay_ms() provides a decreased resolution functionality. In this mode _delay_ms() will work with a resolution of 1/10 ms, providing delays up to 6.5535 seconds (independent from CPU frequency). The user will not be informed about decreased resolution.
  • #5 10437579
    gaskoin
    Poziom 38  
    Dodatkowa funkcja nie jest potrzebna po to, żeby się dało używać zmiennych opóźnień, tylko po to, żeby biblioteka zmiennoprzecinkowa nie zeżarła Ci całego flasha :)
  • REKLAMA
  • Pomocny post
    #6 10437722
    Electix
    Poziom 21  
    Spróbuj może jeszcze zamiast używać funkcji beep(), w pętli głównej programu po prostu jej treść wpisać i zobaczyć co będzie. Na początek pojedyncze bipnięcie, potem dwa, a jak to będzie działać to trzy i tak do tyle ile chcesz. Zwróć też uwagę że rejestr OCR1A jest 16 bitowy, a rdzeń Twojego AVR jest 8 Bitowy. Czyli zapis tego rejestru nie odbywa się w jednej instrukcji. Jeżeli masz włączone przerwania, to mogą one pojawić się w trakcie zapisu do rejestru OCR1A i w ten sposób zakłócić działanie timera.

    Nie wiem czasem, czy nie powinieneś też wpisać najpierw wartość do OCR1A a dopiero potem stratować timer.
  • #7 10437771
    bozar88
    Poziom 13  
    Miałeś rację :)

    Gdy wpisywałem do OCR1A wartość niższą niż obecna, była duża szansa, że licznik timera już miał wartość większą od wpisanej, więc trzeba było czekać na jego przepełnienie i w tym czasie żaden dźwięk nie był odgrywany. Przynajmniej tak to sobie wyobrażam.

    Zrobiłem tak:
    1. Zatrzymuję timer
    2. Licznik timera ustawiam na 0
    3. Ustawiam OCR1A
    4. Włączam timer, ustawiając odpowiedni preskaler
    5. Robię delay taki, jak długi ma być beep
    6. Zatrzymuję timer
REKLAMA