Eğitim Şart

Taşı delen suyun şiddeti değil sürekliliğidir!…

Arduino, Rotary Encoder ve Nokia 5110 LCD Ekranı İle Türk Sanat Müziği Usülleri…

Türk sanat müziği icrası esnasında ritm olayını düzenlemek için usûller kullanılır. Genel olarak güçlü “düm” ve zayıf “tek” seslerinden oluşan usûller en basit iki zamanlı olmak üzere günümüzün en önemli referans kaynağı olan İsmail hakkı Özkan’ın “Türk Musikisi Nazariyat ve Usûlleri” kitabında 124 zamanlıya kadar ulaşır. Tabii bu projede en çok kullanılan basit usûller çalışılmıştır. Amaç bu usûlleri zamanı ile birlikte Arduino’da “tone” komutu ile seslendirerek, eserlerin icrasında kolaylık sağlamaktır. Programda işlenen usûller:

“Nim Sofyan”;
“Semai”;
“Sofyan”;
“Turk Aksagi”;
“Yuruk Semai”;
“Sengin Semai”;
“Devr-i Hindi”;
“Devr-i Turan”;
“Duyek”;
“Musemmen”;
“Aksak”;
“Agir Aksak”;
“Evfer”;
“Raks Aksagi”;
“Oynak”;
“Curcuna”;
“Aksak Semai”;

Zaten daha fazlası Arduino’nun program belleği için zorlayıcı oluyor. Sadece yukarıdakilerle dahi pro mini 168’in 16 kByte’lık hafızasını aştı ve Atmega 328 kullanmak zorunda kaldım. Kodun uzun olmasının nedeni zorluğundan değil, tekrar eden bölümlerinin çok olmasından kaynaklanma. (Aslında her seferinde “düm” ve “tek”ler loop olarak yazılıp usûller içinde çağırılabilirdi!)Ayrıca bu projede rotary encoder ve Nokia 5110 LCD ekran kullanıldı. Menü oluşturmak da yine tekrar eden komutlardan dolayı epeyce yer işgal etti.

Kodun usul ile alakası kolay. Sadece süreleri belirleyip buzzer çıkışını bu süreler zarfında HIGH ya da LOW yapmak yeterli. Örneğin iki (sekizlik) zamanlı “Nim Sofyan” usulü için buzzer “düm” için pes tonda (60 Hertz) bir kez, “tek” için de daha tiz tonda (250 Hertz) bir kez aktif oluyor. Burada vuruş etkisi yaratmak için belirlenen sürenin sadece 1/8’inde aktif olup kalan 7/8’lik zamanda pasif oluyor. böylelikle her bir vuruş daha net anlaşılabiliyor. Zaman programın başında int time=330; komutu ile 330 ms olarak belirlendi. Dörtlük vuruşlar için time/4, sekizlik vuruşlar için time/8 zamanlaması yapıldı.

tone(sesPin,60); //düm
delay(time/8);
noTone(sesPin);
delay(time*7/8);
tone(sesPin,250); //tek
delay(time/8);
noTone(sesPin);
delay(time*7/8); 

Zaman değişkeni program yürütülürken ritmi arttırmak/azaltmak için değiştirilebiliyor. Bu değişikliği yapmak için rotary encoder kullanıldı. Tabi en başta kütüphanesini programın başında ekledik (#include <ClickEncoder.h>). Zamanı ±20ms aralıklarla değiştirmek mümkün:

void toneSpeed(){
if (up && page == 2)
{
up = false;
time = time + 20;
}
if (down && page == 2)
{
down = false;
time = time – 20;
}
}

Projenin usûllerle ilgili kısmı bu kadar. Kodun diğer bölümleri rotary encoder, Nokia5110 LCD display ve organizasyonla alakalı. LCD ile ilgili bölüm de zaten daha önce çalıştığımız bölümler. Sırasıyla; kütüphaneyi  yüklemek, LCD nesnesi (display isimli)yaratmak, kullanılacak yazı karakterlerini dahil etmek:

#include <LCD5110_Basic.h>
LCD5110 display(8,9,10,11,12);
extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];

Kontrasta hiç girmedim, varsayılan ayar benim için kafi. Arka aydınlatmayı da +Vcc ‘ye bağladım, sürekli yanıyor. Dolayısıyla LCD ile ilgili kısım sadece ekrana yazdırırken “display” nesnesini komuta eklemek kalıyor. Örneğin usul vuruken ekran görüntüsü için kullanılan kod:

void displayMenu2(String menuItem, String vurus, int value)
{
display.setFont(SmallFont);
display.clrScr();
display.print(menuItem,CENTER, 0);
display.print(vurus,CENTER, 16);
display.setFont(MediumNumbers);
display.printNumI(value,CENTER,32);
}

Buradaki menuItem, usullerin isimlerinin olduğu String değişkeni. Yani ekranda ilk satırda, merkezde, SmallFont boyutunda usûl adı, 16.satırda (normal satır sanılmasın, LCD ekran dot matrix idi!) usulün ölçüsü (3/4 gibi) ve en altta da daha büyük (MediumNumbers) karakterlerle zaman değişkeni görüntüleniyor.

menu2

Gelelim ekran menülerinin düzenlenmesine. İki ana menü var; birincisi usullerin olduğu menü ekranı (page1), ikincisi usûllerin, vuruşların ve zamanlamanın gösterildiği menü (page2). Ana menüde iken rotary encoder’in butonuna bastığımızda ikinci menüye geçiyor, ikinci menüde iken butona basıldığında ise (zaman ayarını 350 ms değerine döndürerek) ilk menüye  dönüyor.

if (middle) //Butona basıldığında…
{
middle = false;
if (page == 1 && menuitem<=17)
{
page=2;
}
else if (page == 2)
{
time = 350;
page=1;
}
}

Yalnız page1’de sadece üç usûl görüntülenebiliyor. Dördünü usûlü ekranda görebilmek için, ilk usûl ekrandan siliniyor ve ekranda 2., 3. ve 4. usûller görünüyor. 5. usûlü ekranda görebilmek için ise 2. usûl ekrandan siliniyor ve ekranda 3., 4. ve 5. usûl görünüyor. Bu böyle devam ediyor.

Bunun için  ana menü’de (page1) ekran görüntüleri pencerelere (frame) bölümlere ayrılıyor. Yani aslında ekranda ilk üç usûl varken siz 4. usûlü görmek için rotary encoder’i çevirdiğinizde, yeni bir pencere açılıyor ve ekran yenileniyor. 6., 7, ve daha sonraki usûller için de aynı şekilde bir sonraki pencere açılıyor. 17 usûl için 15 pencereye ihtiyaç var. Aşağıdaki tabloda her pencerede görüntülenen usûller gösterilmiştir.

pencere

Özetle birinci pencerede 3.usûlde rotary encoder sağa döndürüldüğünde, 2. pencere; 2.pencere 4. usûlde sağa döndürüldüğünde 3.pencere,….,14. pencerede, 16. usûlde sağa döndürüldüğünde 15. pencere açılıyor. Yani pencere numarası arttırılıyor.

if (down && page == 1) //Sonraki pencere’leri açmak için.
{
down = false;
if(menuitem==3 && pencere == 1) pencere ++;
if(menuitem==4 && pencere == 2) pencere ++;
if(menuitem==5 && pencere == 3) pencere ++;
….

Tersi durumda ise; 15. pencerede 15. usûlde iken rotary sola döndürüldüğünde 14. pencereye, 14. pencerede 14. usûldeyken sola döndürüldüğünde 13. pencereye geliniyor. Bu böyle ilk pencereye kadar pencere numarası eksiltilerek devam ediyor.

if (up && page == 1 ) // önceki pencerelere dönmek için.
{
up = false;
if(menuitem==2 && pencere ==2) pencere — ;
if(menuitem==3 && pencere ==3) pencere — ;
if(menuitem==4 && pencere ==4) pencere — ;

Uzun anlatıldığına bakmayın, uğraşınca kolaylaşıyor. Şimdi her bir penceredeki usûlü seçmek  (siyah üstü beyaz yazı: display.invertText(0); )için, her pencerede seçilen usûller “true” ve “false” kullanılarak belirleniyor. Örneğin birinci penceredeki usûllerin her biri için;

if (page==1)
{
display.setFont(SmallFont);
display.clrScr();
display.print(“USUL SEC”, 15,0);
display.print(“——–“, 15,8);
display.invertText(0);
if(menuitem==1 && pencere ==1)
{
displayMenu1(menuItem1, 20,true);
displayMenu1(menuItem2, 28,false);
displayMenu1(menuItem3, 38,false);
}
else if(menuitem == 2 && pencere == 1)
{
displayMenu1(menuItem1, 20,false);
displayMenu1(menuItem2, 28,true);
displayMenu1(menuItem3, 36,false);
}
else if(menuitem == 3 && pencere == 1)
{
displayMenu1(menuItem1, 20,false);
displayMenu1(menuItem2, 28,false);
displayMenu1(menuItem3, 36,true);
}
….

Her bir pencere için, o pencerede bulunan usûller (menuItem olarak adlandırıldı) her seferinde sadece bir tanesi “true” olarak yazılacak.

Void loop’un başında rotary encoder’ın çalışması ile ilgili kod ve bunun içinde de rotary’den veri alınmasını sağlayan readRotaryEncoder(); fonksiyonu tanımlanmış. Bunlar hazırdı. hiç dokunmadan ekledim. Ayrıca programda bir içkesme (Interrupt) fonksiyonu da eklendi. Ancak çalışmıyor. Kodun tamamına sayfanın sonunda ulaşabilirsiniz.

IMG_20190410_233534

Gelelim devremize. Bir çıkışa buzzer/hoparlör bağlamak yeterli.  Ben hoparlör kullandım. Çünkü sesi daha tok ve bilgisayar sesi gibi gelmiyor. Ayrıca 5110 ekranı ve rotary encoder bağlantılarını da unutmamak gerekiyor.

 

DENEY TAHTASI FRITZING

LCD ekran bağlantısını daha önceki gibi yapıyoruz. Yani sırasıyla: (RST, CE, DC, Din, Clk, Vcc, BL, Gnd) bacaklarını, Arduino’nun (11, 12, 10, 9, 8, 3.3V, 3.3V ve Gnd) bacaklarına bağlıyoruz. Bu modülün 3.3 volt ile çalıştığını tekrar hatırlatmak isterim. Ki ben bu devreyi Arduino pro mini ile yaptım ve 3.3 volt çıkışı olmadığından, 5 volt > 3.3 volt dönüştüren bir devre kullanmak zorunda kaldım. Rotary encoder A, B ve buton çıkışları  sırasıyla A0, A1, A2 analog girişlere bağlanıyor. (-), Gnd hattına; (+) ise 3.3V çıkışına 1kΩ direnç ile bağlandı. Bu arada modül daha pahalı olduğu için direkt rotary encoder ‘ın kendisini kullandım. Aynen çalışıyor. Bacak bağlantıları aşağıdaki gibi yapıldı:

Kullanıcının yanında taşıyacağı bir ürün olduğundan iki şey daha ekledim. Birincisi kulaklık çıkışı; herkesi rahatsız etmek istemezseniz kulaklığı takıp dinleyebilirsiniz.

IMG_20190410_231631

İkinci eklenti ise Li-Ion pil ile besleme. Görüntüsü biraz kaba oldu ama çalışıyor.

IMG_20190410_233549

Laptop’tan sökülen 18650 pilleri yuvasıyla birlikte proje kutusunun arkasına sabitledim. Oradan şarj olabilmesi, daha da önemlisi fazla akım ve kısa devre koruması için Çin’den aldığım 2S 3A Li-Ion şarj koruma devresi ekledim. Tanesi 2 TL civarında. Aşırı deşarj koruması da var. 4.25-4.35 volttan sonra şarjı kesiyor. 2.3-3.0 volt arasında da deşarjı kesiyor. Anlık 5A, sürekli 3A akım sağlayabiliyor(üretici verilerinin yalancısıyım 🙂 ). Kısa devre olduğunda akımı kesiyor. Ancak bundan sonra tekrar boot edilmesi gerekiyor. Yani P+ ve P- den gerilim uygulamalısınız.

2S 3A LiIMG_20190410_231642

Ancak bu şarj cihazı 7.4V ile 8.4V arası kullanılabiliyor. böyle bir adaptörüm olmadığı için devrenin gerilimini LM317 devresi ile 8.3 volt civarında sabitledim. Dolayısıyla 9V ve üzeri her türlü adaptörle devremiz kullanabilecek.

LM317

LM317’nin veri kağıdında çıkış gerilimi hesabı: Vout= 1.25( 1 + R2/R1) olarak veriliyor. 5.7kΩ direncim olmadığı için 4.7 ve 1 kΩ dirençleri seri bağladım. Yukarıdaki formüle göre yaklaşık 8.378 voltluk bir gerilim elde ettim. Yine ne olur ne olmaz diye girişe bir de 3A cam sigorta eklendi. Şema nasıl mı oldu?

DEVRE SEMASI pro mini

 

Bir dahaki projede görüşmek dileği ile…

 

Kodu İndir

 

kaynaklar :

Türk Musikisi Nazariyatı ve Usûlleri, İsmail Hakkı Özkan

Home

%d blogcu bunu beğendi: