cze 042011
 

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