Sesja się zbliża, więc tradycyjnie zacząłem już prokrastynować (a Wy? 😉 ). Ostatnio zacząłem pisać bibliotekę do obsługi klawiatury PS/2 w C dla AVR i postanowiłem na szybko w godzinkę lub dwie stworzyć jakiś praktyczny projekt w celu jej przetestowania. Początkowo nie planowałem tego publikować, ale pokazałem to kilku osobom i się spodobało, więc być może spodoba się i Wam. Mi zabawa tym wynalazkiem sprawia radochę jak dziecku 😉 .
Oto moje elektroniczne „pianino” z komputerowej klawiatury PS/2.
Od strony elektronicznej układ jest bardzo prosty – mikrokontroler ATMega, kondensatory, głośnik, gniazdo PS/2, które barbarzyńsko wyciąłem wraz z kawałkiem uszkodzonej płyty głównej, gdyż nie chciało mi się go wylutowywać i klawiatura PS/2 ze złomu, którą wspaniale oznakowałem zielonym markerem i powyciągałem kilka klawiszy by układ klawiszy przypominał klawiaturę pianina.
Na zdjęciach widać moją uniwersalną płytkę, w której siedzi m.in. Mega32 i programator USB DIY – USBAsp. Głośnik pochodzi z obudowy komputerowej.
Czas wspomnieć coś o softwarze, który jest główną częścią projektu. Być może kogoś to zainteresuje.
Jak już wspomniałem, napisałem go w C i skompilowałem pod AVR-GCC. Program dzieli się na dwie części – obsługa PS/2 i właściwy program – pianino.
Warstwa fizyczna PS/2 jest bardzo prosta. W przypadku klawiatury oprócz VCC/GND wykorzystywane są jedynie linie DATA i CLK. Opis można znaleźć m. in.
[TUTAJ] . W chwili naciśnięcia/puszczenia przycisku klawiatura przesyła 11 bitów (start, data(8), parity, stop) generując przy tym zegar na linii CLK. Zegar połączyłem z wejściem INT0 mikrokontrolera i włączyłem zewnętrzne przerwanie. Dane można odebrać na dwa sposoby – w momencie wystąpienia przerwania można odebrać wszystkie 11 bitów lub odbierać po 1 bicie w każdym przerwaniu. Ja zastosowałem drugą opcję. Dlaczego? Dzięki temu nie marnuję czasu pomiędzy bitami. Jeśli odbierałbym cały bajt, musiałbym czekać na aż klawiatura prześle wszystkie 11, a że działoby się to w przerwaniu zablokowałbym inne przerwania aż do zakończenia odczytu, co mogłoby być niepożądane w przypadku korzystania innych często występujących przerwań. Minusem jest możliwość utraty synchronizacji, kiedy na linii CLK pojawi się jakiś „śmieć” (moja klawiatura ze złomu jest lekko upośledzona i czasem je wysyła 😉 ) – można to wyeliminować wywołując co jakiś czas funkcję synchronizującą.
Po odebraniu 11-go bitu, bajt trafia do kolejki klawiatury – struktury zawierającej bufor o definiowalnej wielkości i flagi. Dzięki zastosowaniu bufora główna pętla nie musi „interesować się” życiem klawiatury – wystarczy jedynie ściągnąć z kolejki klawisz (o ile tam się znajduje). Ponadto takie podejście umożliwia podłączenie dwu lub więcej klawiatur – wystarczy tylko stworzyć dodatkową strukturę i przerobić funkcje tak, by operowały na wskaźnikach zamiast na globalnej strukturze (stworzyłem globalną dla zwiększenia wydajności/wygody).
Co do algorytmu pianina – mikrokontroler generuje proste tony (przebiegi prostokątne) za pomocą wbudowanego sprzętowego timera. W momencie, gdy chcę wygenerować dźwięk, przeliczam wartość docelowej częstotliwości na odpowiednią wartość wpisywaną do rejestru (właściwie rejestrów, bo jest to liczba 2-bajtowa) timera, zależną od częstotliwości taktowania i zmieniam stan wyjścia, do którego podłączony jest głośnik przy każdym przerwaniu.
Pianino posiada własną kolejkę klawiszy – dzięki niej program „pamięta”, jakie klawisze są aktualnie wciśnięte i zmienia ton w odpowiedni sposób.
Niestety mając tylko jeden kanał niewiele można zdziałać, ale przy zastosowaniu pewnego triku można nieco urozmaicić dźwięk. Zastosowałem taki sam trik jak w starych DOSowych grach (to były czasy, nie? ;-D ) – w momencie wciśnięcia dwu klawiszy częstotliwość jest przełączana z jednego tonu na drugi 20-50ms, co daje (przynajmniej częściowe) wrażenie dwóch tonów jednocześnie. Tryb dwutonu można wyłączyć/wyłączyć za pomocą odpowiednich klawiszy.
Na koniec najciekawsza opcja – nagrywanie sampli. Pozwala ona nagrać 4 sample o długości do 65 nut (w przypadku, gdy wszystkie dźwięki/przerwy są krótsze od 4 sek.). Podczas nagrywania zapisuję w pamięci zdarzenie (wciśnięcie/puszczenie klawisza N) i odstęp od poprzedniego zdarzenia w rozdzielczości około 16ms (1/64) do zajmuje 2B. Jedna nuta to wciśnięcie i puszczenie klawisza. 65*2*2B*4 sample daje 1040B potrzebnej pamięci na sample. oczywiście, można by to bardziej skompresować, ale nie było sensu marnować czasu na pisanie efektywniejszego algorytmu, bo nie taki był cel tego projektu. W przypadku ATMegi8/16 trzeba by zmniejszyć ten obszar o połowę – potrzebna jeszcze miejsca na kolejki, zmienne pomocnicze i stos (no końcu). Sample możnaby też zapisywać na EEPROMie – były by trwałe.
Sample można odtwarzać i jednocześnie grać drugą linię. Algorytm odtwarzania ma małe niedociągnięcia, które widać przy przełączaniu oktaw, ale jak już pisałem, celem projektu była biblioteka PS/2.
A teraz najważniejsze – 2 filmiki: na jednym demonstracja działania tryby dwutonowego i sampli na znanej piosence polskiego zespołu a na drugim… marsz turecki 😉 .
Jeśli będą chętni, to udostępnię kod programu/bibliotekę PS/2 jak tylko ją dokończę i napiszę dokumentację – pisać.
Jak mi się zechce, to dopiszę obsługę myszki – można by modulować nią dodatkowo tony klawiszy (coś na zasadzie wajchy w keyboardach ).
Jeśli ktoś chciałby się pobawić, to załączam skompilowany program dla ATMegi32 (8MHz). Schemat połączenia (tak jak było mi wygodnie na mojej płytce testowej):
ATMEGA.PORTD.2 (INT0) - PS2.CLK
ATMEGA.PORTC.1 - PS2.DATA
ATMEGA.PORTD.6 - SPEAKER
Do tego oczywiście głośnik do masy, VCC=5V dla atmegi i klawiatury i do tego jakiś elektrokit filtrujący miedzy VCC a GND i kondensatory do kwarcu 8MHZ około 27-30p. Program dodatkowo wysyła dane pomocne w debugowaniu po RS232 i czasem się przywiesi na starcie co jest powodem synchronizacji PS/2, której w bibliotece jeszcze nie ma .
Link do mojego tematu w serwisie elektroda.pl:
http://www.elektroda.pl/rtvforum/viewtopic.php?p=9574045#9574045
Firmware v. 0.1 (alpha):
Pobierz plik: avrpiano/arvpiano_aplha_0_1_m32_8MHz.hex
Rozmiar: 25.62 KB
Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in /home/ebiwptr/silent/home/filedb.php on line 99
wow man. that’s cool
Hello, nice work. It’s was very interesting to see and listening result. It’s really cool project)
I see you don’t monetize your blog, don’t waste your traffic, you
can earn additional bucks every month because you’ve got high quality content.
If you want to know how to make extra money, search for: Mrdalekjd methods for $$$
To jest jak ta strona wiedza tajemna Paweł inżynierem 😉
Can you show your Simulation on Proteus ? please ><
KC
KOCHAM
Hello,
Very excellent blog post from you
Thanks.
maan, that’s fkcn perfect.))
Dzień dobry,
Znalazłem Pana projekt pianina z wykorzystaniem klawiatury na PS2 na elektrodzie.
Pisze prace Inżynierska, która polega na pobieraniu sygnału z akcelerometru i sterowaniu kursorem PC przez port PS_2 wykorzystując AVR32. Mam do Pana pytanie, czy nie pomógł by mi Pan i pokazał algorytm obsługi w C portu PS_2.
Z góry bardzo dziękuje za odpowiedź.
Pozdrawiam.
Witam. Właśnie próbuję zrobić coś PODOBNEGO na ATmega16 i nie mogę poradzić sobie z obsługą zwalniania klawisza oraz graniem dwutonu. Przesłałby kolega kod źródłowy projektu? Tylko na moją potrzebę 🙂
Rad bym zobaczyć kod żródłowy.
Nice job! Congratulation!