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

Zaawansowane sztuczki z PWM - Cyfrowy syntezator dźwięków

TechEkspert 22 Mar 2015 18:00 4335 0
  • Zaawansowane sztuczki z PWM - Cyfrowy syntezator dźwięków
    Dzisiaj fragment książki "Programowanie układów AVR dla praktyków" Autor: Elliot Williams, materiał został bezpłatnie udostępniony dla użytkowników elektroda.pl przez grupę Helion S.A.

    W udostępnionym fragmencie możecie zapoznać się z dość ambitnym zagadnieniem DDS (bezpośredniej syntezy cyfrowej). W skrócie opanowanie sterowania PWM pozwoli na generowanie sygnału o modulowanej obwiedni, który po podłączeniu do głośnika pozwoli na uzyskanie efektów akustycznych. Oczywiście DDS można wykorzystać do innych celów np. budowy prostego generatora funkcyjnego opartego np. o mikrokontroler AVR.

    Zaczynamy od dość trudnego zagadnienia z dziedziny mikrokontrolerów oraz cyfrowego przetwarzania sygnałów, niebawem zaprezentujemy kolejne udostępnione materiały dot. innego obszaru techniki.

    Poniżej udostępniony dla Was przez Helion fragment książki:

    ----------------------------------------------------------------------------------------
    Rozdział 13. Zaawansowane sztuczki z PWM

    Cyfrowy syntezator dźwięków

    Aby generować dźwięki nieco bardziej interesujące od fal prostokątnych, musimy wykorzystać technikę PWM, żeby szybko zmieniać wartość średnią napięcia, które będzie wyznaczało wybraną przez nas obwiednię. Na razie zadowolimy się tradycyjnymi obwiedniami syntezatorów (fala sinusoidalna, piłokształtna lub trójkątna), ale zbudujemy też podstawy pod późniejsze odtwarzanie nagranych próbek dźwięku. (Gdy już będziemy mieli wystarczającą ilość pamięci - w Rozdział 18. - użyjemy tych samych technik do zbudowania gadającego woltomierza). Będziemy też mogli zmieniać głośność generowanych dźwięków, a nawet miksować ze sobą kilka różnych fal. Jeżeli lubisz kosmiczne dźwięki w stylu drone albo po prostu wolisz bardziej muzyczne odgłosy od dźwięków fali prostokątnej, jakie tworzyliśmy do tej pory, to w tym rozdziale nie będziesz się nudzić!

    Przy okazji wyciśniemy ostatnie soki z układu generującego modulowane impulsy. Licznik będziemy taktować bez żadnego podzielnika (8 MHz) i ta szybkość naprawdę będzie potrzebna. Generowanie dowolnych obwiedni w czasie rzeczywistym z częstotliwością 31,25 kHz wymaga również obliczeń, do których będziemy potrzebować całej mocy procesora. Odkryjemy, że są pewne rzeczy, których nie jesteśmy w stanie łatwo zrealizować. Moim zdaniem, połowa przyjemności z pracy z tak małymi urządzeniami, jakimi są mikrokontrolery, polega na sprawdzaniu, jak wiele można osiągnąć tak skromnymi środkami. Mam nadzieję, że będziecie pozytywnie zaskoczeni tym, co naprawdę jest możliwe.
    Na początek zbudujemy prosty, syntezatorowy generator fali sinusoidalnej. Niemodulowana fala sinusoidalna jest na tyle nudna, że w następnym projekcie spróbujemy miksować ze sobą różne przebiegi syntezatorowe. Wybierzemy kilka (2, 4, 8 albo 16) fal piłokształtnych i będziemy je miksować. Żeby nie było nudno, wszystkie te obwiednie będą powoli przesuwane z różnymi prędkościami. Powstanie w ten sposób trochę dziwny dźwięk w stylu muzyki drone. W latach 90. ubiegłego wieku takie efekty używane były jako odtwarzane rytmicznie podkłady basowe. Na koniec, w ostatnim projekcie dodamy jeszcze dynamiczną kontrolę głośności, dzięki czemu nasz układ AVR stanie się całkiem nieźle brzmiącym "pianinem". No, w każdym razie brzmiącym lepiej niż fala prostokątna.





    CZEGO POTRZEBUJESZ?

    W tym rozdziale oprócz zestawu podstawowego będziemy potrzebować:
    -głośnika z kondensatorem podłączonym do mikrokontrolera,
    -(opcjonalnie) pary oporników i kondensatora do budowy filtru dolnoprzepustowego, jeżeli zechcesz podłączyć wyjście do zewnętrznego wzmacniacza,
    -adaptera USB-port szeregowy, żeby pograć na pianinie z klawiatury swojego komputera.

    CZĘSTOTLIWOŚCI W CZĘSTOTLIWOŚCIACH

    Podczas pracy z techniką bezpośredniej cyfrowej syntezy (Direct Digital Synthesis - DDS) dobrze jest myśleć o wartościach PWM wpisywanych do rejestru OCR0A jak o bezpośrednim odwzorowaniu poziomu napięcia. Będziemy tu zmieniać wartość tego napięcia w czasie, tworząc tym samym zaplanowaną wcześniej obwiednię. A zatem gdy mówię o "częstotliwości danej obwiedni", mam na myśli liczbę cykli przebiegu napięcia mieszczącą się w jednej sekundzie.

    Oczywiście teraz już wiemy, że w zasadzie "poziom napięcia" PWM jest tylko kolejnym, znacznie szybszym, ciągiem impulsów powtarzanych z częstotliwością procesu modulacji. Poszczególne impulsy są wygładzane tak, żeby w skali częstotliwości audio sprawiały wrażenie niemal stałego napięcia średniego. Zazwyczaj nie trzeba się zajmować pojedynczymi impulsami, o ile zastosowana częstotliwość jest na tyle wysoka, żeby filtr był w stanie odpowiednio je wygładzić i uśrednić.

    Z drugiej strony, jeżeli na wyjściu zamienisz powolny element, taki jak głośnik, na coś o krótszym czasie reakcji, np. na wzmacniacz albo słuchawki, możesz usłyszeć szum o wysokiej częstotliwości, którego wcześniej nie było. W takiej sytuacji rozwiązaniem może być zwiększenie wartości opornika i kondensatora tworzącego filtr dolnoprzepustowy, co zmniejszy szybkość zmian napięcia i tym samym stłumi wyższą częstotliwość modulowanych impulsów.

    Bezpośrednia synteza cyfrowa

    Podstawą dla naszej aplikacji stanie się technika znana pod nazwą bezpośredniej syntezy cyfrowej (DDS - direct digital synthesis). Jeżeli np. chcielibyśmy odtworzyć falę sinusoidalną, musimy próbkować taką falę w równych odstępach czasu. Z kolei podczas odtwarzania konieczne jest podawanie na wyjście zarejestrowanych wcześniej wartości napięcia. W tablicy umieszczonej w pamięci zapamiętujemy wszystkie wartości próbek opisujących jeden pełny cykl, a potem możemy tworzyć różne wysokości dźwięku, odtwarzając poszczególne próbki wybrane z tablicy.
    Całkiem prosto można sobie wyobrazić sposób odtwarzania podstawowego dźwięku. Wystarczy ze stałą prędkością przejść przez wszystkie elementy tablicy, zapisując każdy z nich do rejestru porównującego licznika generującego impulsy PWM i w ten sposób wygenerować wartości napięć. Zmiana wysokości dźwięku wymagać będzie dopasowania szybkości, z jaką przebiegamy wartości w tablicy. Najłatwiejszym sposobem byłoby tu przyspieszenie szybkości odtwarzania, ale w tym przypadku nie mamy dostatecznie szybkiego sprzętu. Zegar procesora pracuje ze stałą częstotliwością, a przyspieszenie szybkości modulowania impulsów wymagałoby zmniejszenia ich dokładności. Musi zatem istnieć inny sposób.
    Zamiast zmieniać częstotliwość zegara, czyli szybkość przechodzenia do kolejnych kroków odtwarzanego cyklu, możemy zmienić liczbę kroków wykonywanych przy każdym tyknięciu zegara. Dla niższych dźwięków, o większej długości fali, możemy niektóre kroki odtwarzać przez czas dłuższy niż jeden cykl PWM. W przypadku wyższych dźwięków możemy z kolei pomijać niektóre próbki z tablicy. Chodzi o to, żeby zmniejszać lub zwiększać ilość czasu potrzebną do przejścia przez całą tablicę z próbkami, co w efekcie spowoduje wygenerowanie niższego lub wyższego dźwięku.
    Oczywiście to nie wszystkie szczegóły implementacji takiego rozwiązania, ale na początek wyobraź sobie, że po prostu przechodzimy przez tablicę z próbkami, odtwarzając każdą z nim przy kolejnych cyklach PWM. Taką procedurę można zapisać w poniższym pseudokodzie.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Jeżeli chcesz odtworzyć dźwięk o oktawę wyższy, przebiegasz tę samą tablicę z próbkami, ale przy każdym obiegu pętli pomijasz jedną próbkę, a napięcie na wyjściu będzie miało dwukrotnie większą częstotliwość. W pseudokodzie oznaczałoby to dwukrotne zwiększenie wartości zmiennej waveStep przy każdym obiegu pętli (patrz Rysunek 13-1). W tym przypadku nasza tabela składa się z 40 próbek. Pominięcie co drugiej z nich pozostawia 20 próbek, które nadal tworzą pełen cykl. Można też powiedzieć, że w czasie potrzebnym na odtworzenie całego przebiegu zrobiliśmy to dwa razy, bo pominęliśmy co drugą próbkę. Jakby na to nie patrzeć, pomijanie próbek pozwoliło na podwojenie wyjściowej częstotliwości.
    Jeżeli chcesz odtworzyć dźwięk o oktawę niższy, musisz znaleźć sposób na zwiększanie wartości zmiennej waveStep o 1/2 przy każdym obiegu pętli. Na tym właśnie polega bezpośrednia synteza cyfrowa. Zamiast modyfikowania szybkości odtwarzania próbek zmieniamy tylko liczbę kroków wykonywanych przy każdym z cykli PWM.
    Odtwarzanie dźwięków o oktawę wyższych jest całkiem proste - wystarczy zwiększać licznik o dwa - ale sprawy się komplikują, gdy chcemy uzyskać częstotliwości różniące się o inną wartość niż oktawa. W znanej nam skali składającej się z 12 tonów częstotliwość każdego klawisza na klawiaturze różni się od sąsiadów o pierwiastek dwunastego stopnia z dwójki, czyli o mniej więcej 1,059463. Niestety, posługując się liczbami całkowitymi, nie możemy pomnożyć wartości zmiennej waveStep przez 1,06. Musimy znaleźć inny sposób na zwiększenie dokładności obliczeń.
    Okazuje się, że zwiększenie dokładności jest całkiem proste - wystarczy wykorzystać więcej bitów. Tajemnicą szybkiego i skutecznego zwiększenia dokładności jest uświadomienie sobie, że można łatwo przekształcić liczbę 16-bitową w 8-bitową, przesuwając ją o 8 bitów w prawo. Wszystkie obliczenia będziemy prowadzić na liczbach 16-bitowych, ale nadal będziemy korzystać z 256-elementowej tablicy próbek. Przejście z większej precyzji do mniejszej polegać będzie na przesunięciu kilku bitów, żeby otrzymać pozycję próbki w tabeli. W języku stosowanym przez techników pozycję w tabeli śledzimy za pomocą 16-bitowego akumulatora, ale do pobrania próbki wystarcza jego 8 najstarszych bitów.
    Przypomina to sztuczkę, jakiej użyliśmy w celu utrzymania dokładności obliczeń średniej kroczącej w Rozdział 12. i tak rzeczywiście jest. W tamtym przypadku obliczaliśmy średnią kroczącą, mnożąc i dodając wartości zwracane przez 10-bitowy konwerter AC, i czekaliśmy do ostatniej chwili na wykonanie dzielenia.

    Zaawansowane sztuczki z PWM - Cyfrowy syntezator dźwięków
    Rysunek 13-1. Próbki fali sinusoidalnej

    Innym sposobem wyjaśnienia, w jaki sposób działa ta metoda, jest wyobrażenie sobie, że na każdą z 256 pozycji w tabeli próbek musimy odliczyć do 256 przed przejściem do kolejnej próbki. To pozwala na sterowanie szybkością odtwarzania próbek z dokładnością do 1/256 pierwotnej dokładności. Aby odtwarzać dźwięk z jego oryginalną częstotliwością, musimy dodać do akumulatora liczbę 256, żeby przejść do następnej próbki. Odtwarzanie dźwięku o oktawę niższego (czyli wykonywanie pół kroku na każdy cykl) polega po prostu na dodawaniu do akumulatora liczby 128 przy każdym cyklu. Z kolei odtwarzanie dźwięku o ton wyższego oznacza zwiększanie akumulatora o wartość 271. W efekcie przy niemal każdym cyklu będziemy przechodzić do następnej próbki, ale niektóre z nich będziemy pomijać, przez co dźwięk będzie nieco wyższy. Doskonale!
    Teraz nasz pseudokod będzie wyglądał tak:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    PODSUMOWANIE: PODSTAWY BEZPOŚREDNIEJ SYNTEZY CYFROWEJ

    Chcesz wygenerować złożony analogowy sygnał o dowolnej częstotliwości? Jak to zrobić? Stosując bezpośrednią syntezę cyfrową, musimy przygotować w pamięci tablicę z próbkami opisującymi ten sygnał. Za każdym razem gdy musimy zmienić wartość napięcia (zakładam, że stosujemy technikę PWM), należy wykonać określoną liczbę kroków przez tablicę i zapisać pobraną z niej wartość do rejestrów sterujących wartością napięcia.
    W celu uzyskania wyższej rozdzielczości, co przekłada się na lepsze możliwości dopasowania dźwięków, należy przechowywać informację o aktualnym kroku w tabeli próbek z dokładnością sporo większą od dokładności samej tabeli. Dzięki temu do pobrania próbki z tabeli 8-bitowej wystarczy wykorzystać 8 najstarszych bitów zmiennej wyznaczającej pozycję, przesuwając jej wartość w prawo tak, żeby usunąć mniej znaczące bity.
    W każdym cyklu PWM do 16-bitowego akumulatora dodajemy względnie dużą wartość, następnie jego kopię przesuwamy w prawo o 8 bitów i w ten sposób uzyskujemy 8-bitowy numer próbki do pobrania z tablicy. Pobraną wartość wpisujemy do rejestru sterującego współczynnikiem wypełnienia cyklu modulowanego impulsu.

    Tworzenie fali sinusoidalnej

    Zapisz teraz w pamięci mikrokontrolera pierwszy przykład zastosowania techniki DDS, czyli programdds.c. Na początku nic się nie będzie działo, ale jeżeli do układu AVR podłączysz przycisk i głośnik, przy każdym naciśnięciu przycisku zostanie wygenerowana fala sinusoidalna o częstotliwości około 440 Hz. Przyjrzyjmy się programowi z Przykład 13-1.
    Przykład 13-1. Kod programu dds.c

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Licznik numer 0 został skonfigurowany do szybkiego trybu PWM, dlatego w tym przypadku można uznać wartość wpisywaną do rejestru porównującego OCR0A za wartość reprezentującą średnie napięcie, jakie chcemy uzyskać w cyklu PWM. Zauważ, że podzielnik zegara dla tego licznika ustaliliśmy na 1, czyli działa on bez żadnego spowolnienia. W przypadku próbkowania sygnału audio potrzebujemy maksymalnej szybkości procesora.
    W pętli zdarzeń sprawdzamy, czy przycisk został naciśnięty. Jeżeli tak jest, włączane jest wyjście na głośnik i uruchamiana procedura syntezatora zapisana wewnątrz instrukcji if. Podobnie jak w naszym pierwszym przykładzie, akumulator zostanie zwiększony o liczbę kroków wyznaczającą wysokość dźwięku, następnie 16-bitowa wartość z akumulatora jest dzielona przez 256 (za pomocą operacji przesuwania bitów), co wyznacza pozycję w tablicy próbek. Potem z tablicy pobierana jest wartość całkowita ze znakiem i zapisywana do zmiennej pwmValue. Tę zmienną definiuję jako liczbę ze znakiem, ponieważ później ułatwia to prace przy miksowaniu kilku sygnałów albo przy skalowaniu za pomocą mnożników wyznaczających głośność.

    LICZBY CAŁKOWITE ZE ZNAKIEM

    Pamiętaj, że w tablicy z próbkami zapisane są liczby całkowite ze znakiem. Dlaczego? Po prostu ułatwia to miksowanie sygnałów i sterowanie głośnością. Jeżeli wartości próbek mogą zmieniać się w zakresie od -128 do 127, to po podzieleniu ich przez 2 uzyskamy wartości z zakresu od -64 do 63, który również jest prawidłowo wycentrowany. Poza tym, takie wartości można do siebie dodawać i tworzyć nowe przebiegi. Dopiero w ostatnim momencie, przed wysłaniem ich do rejestru PWM musimy przekształcić te wartości tak, żeby dopasować do zakresu od 0 do 255, co pozwala na wpisanie ich do rejestru OCR0A.
    Później zapisujemy wartość do rejestru OCR, choć najpierw musimy poczekać na zakończenie aktualnego cyklu PWM. Dzięki temu zyskujemy pewność, że nowa wartość znajdzie się w rejestrze najwyżej raz w każdym cyklu, co zapewnia stałą częstotliwość odtwarzania próbek. Do rejestru OCR trafia wartość pwmValue + 128. Liczba 128 została tutaj wybrana, ponieważ liczby całkowite ze znakiem przyjmują wartości od -128 do 127, dodanie wartości 128 sprawia, że zakres ten przesuwa się od 0 do 255 i pasuje do rejestru. Na zakończenie kasowany jest znacznik przepełnienia PWM przez zapisanie do niego jedynki. Zgodnie z informacjami z arkusza danych pozwala to na późniejsze wykrycie zakończenia kolejnego cyklu PWM.

    CZĘSTOTLIWOŚĆ PRÓBKOWANIA

    W tym przypadku używamy 8-bitowego rejestru PWM do wygenerowania nowego średniego napięcia przy każdym kolejnym cyklu. Ale czy da się ocenić, jak często wprowadzamy zmiany poziomu napięcia? Tutaj musimy wykonać kilka obliczeń.
    Skoro sam procesor mikrokontrolera działa już z maksymalną prędkością 8 MHz i wyłączyliśmy podzielnik zegara dla licznika numer 0, znaczy to, że i dla niego zegar tyka z częstością ośmiu milionów razy na sekundę. Każdy cykl PWM trwa w tym przypadku 256 cykli zegara, ponieważ używamy tu 8-bitowego licznika. To wszystko pozwala na wyznaczenie częstotliwości PWM wynoszącej 31250 Hz.
    Jedna z najważniejszych zasad cyfrowego przetwarzania sygnałów mówi, że do odtworzenia prostej sinusoidy trzeba próbkować ją przynajmniej dwa razy w ciągu jej cyklu. Oznacza to, że nasz aktualny system jest w stanie odtworzyć sygnał o maksymalnej częstotliwości 15625 Hz. Całkiem niezły wynik.
    ----------------------------------------------------------------------------------------

    Tutaj kończy się fragment, który możemy zaprezentować dzięki współpracy z Helion S.A.

    Zrozumienie całości zagadnienia DDS na podstawie fragmentu może być trudne, jednak materiał jest na tyle wartościowy, że powinien wprowadzić zainteresowanych w podstawy DDS oraz zachęcić do własnych prób.

    Napiszcie co myślicie o zaprezentowanym fragmencie, może udało się Wam wykonać praktyczne próby ?

    Książkę "Programowanie układów AVR dla praktyków" Autor: Elliot Williams zawierającą powyższy materiał, oraz inne pozycje książkowe wydawnictwa Helion możecie nabyć tutaj: Link.
    Korzystając z powyższego linku wspieracie wortal elektroda.pl :spoko:

    źródło: materiały udostępnione przez Helion S.A. dla użytkowników wortalu elektroda.pl


    Fajne! Ranking DIY
  • Metal Work Pneumatic
  Szukaj w 5mln produktów