AVR ile Rotary Encoder Uygulamaları
Bu başlıkta kısaca yaptığım iki farklı rotary encoder uygulamasından bahsedeceğim.
Rotary encoder mekanik olarak dönüş yönüne göre iki ayağından farklı sinyaller çıkarmakta ve bu sinyaller mikrodenetleyici tarafından okunup yorumlanmaktadır. Rotary encoder’in nasıl çalıştığına dair şu makalede yer alan animasyonu izleyebilirsiniz.
https://lastminuteengineers.com/rotary-encoder-arduino-tutorial/
Ben burada doğrudan uygulamaya geçeceğim ve bunu nasıl yaptığımızı anlatacağım.
İlk uygulamayı seri port ekranı üzerinden yapacağız. O yüzden Arduino UNO kartına sadece encoder modülünün bağlantısının yapılması yeterlidir. Bağlantı şu şekilde olmalıdır.
- VCC → 5V
S1 → D2
S2 → D3
GND → GND
Eğer modül kullanıyorsanız kart üzerinde pull-up dirençlerinin olduğunun farkına varabilirsiniz. Encoderi tek başına kullandığınızda bunu eklemeniz gerekir.
Şimdi kodu inceleyelim.
Burada öncelikle encoder_oku() fonksiyonu ile okunan değeri val değişkenine aktarıyoruz. Bu değer okuma işleminin nasıl yapıldığına bakalım.
Burada val değişkeninin değerini PD2 ve PD3 ayaklarından okunan değerler belirlemekte. PD2 ayağından okunan değer ikinci bitte, PD3 ayağından okunan değer ise ilk bitte saklanmaktadır. Bu durumda val değişkeni 0–3 arasında değer alacaktır.
val_tmp = encoder_oku();
Encoderden okuduğumuz değer tampon değişkene aktarılmaktadır. Bu okunan ilk değer referans alınarak değerdeki değişimleri kontrol edip buna göre işlem yapacağız.
if(val != val_tmp)
Buradaki karar yapısı oldukça önem arz etmektedir. Biz değişimleri ele alıp işlem yapmamız gereklidir, tek başına değer bir anlam ifade etmemekte. Bu yüzden ancak yeni okunan değer referans değerinden farklı olduğu zaman bir işlem yapacağız.
if( (val==3 && val_tmp==1) || (val==0 && val_tmp==2))
{
sayac++;
sprintf(buffer,"%i",sayac);
uart_string(buffer);
uart_string("\n");
}
Burada val değeri 0b01'den 0b11'e geçtiğinde ya da 0b10 değerinden 0b00 değerine geçtiğinde sayaç değişkenini bir artırmaktayız.
else if( (val==2 && val_tmp==0) ||(val==1 && val_tmp==3))
Aynı şekilde sayaç değişkenini de azaltmak için bunun tersini yapmaktayız. Bu tamamen encoderin çalışma prensibinden dolayı bu şekildedir. Şimdi kodumuzu çalıştırsdığımızda ve encoderi çevirdiğimizde şöyle bir görüntü elde edebiliriz.
Şimdi yaptığımız uygulamayı biraz daha üst seviyeye çıkaralım ve gerçek hayat uygulamalarına yaklaştıralım. Gerçek hayatta rotary encoderlar kullanıcı arayüzünde oldukça pratiklik sağlayacaktır. Örneğin bir değer aralığını (+) ve (-) düğmeleri ile kontrol etmek isteseniz kullanıcı sürekli bu düğmelere basacak ve oldukça yorulacaktır. Bunu potansiyometre ile kontrol etmek isterseniz elde edeceğiniz değer sayısal olmayacak ve bunu ADC ile dönüştürmek zorunda kalacaksınız. Bu durumda gürültülerden dolayı değeriniz sürekli sapacaktır. Potansiyometrelerin sıcaklıktan da etkileneceğini unutmayınız. Üstelik hassas ayar yapmak istediğinizde işiniz iyice zorlaşacaktır. Çok turlu potansiyometrelerle bir çözüm getireceğinizi düşünseniz de aynı zamanda ADC’nin çözünürlüğü de bunda etkili olacak ve gereksiz yere masraf çıkaracaktır.
Yalnız burada encoderle adımların birer birer arttığını görebilirsiniz. Uygulama bu haliyle bir “tık” çevirimi +-2 olarak okumaktadır. Bazen kullanıcının girmesi gereken değerler +-400–500 civarında olabilir. Bu durumda kullanıcı bu şekilde çevirmeye devam ederse oldukça yorulacaktır. Buna nasıl bir çözüm getirebiliriz?
Bu encoderlarda aynı zamanda bir düğme bulunmakta ve şafta bastığınız zaman düğmeye basmış oluyorsunuz. Bu düğmeye basılı tutup çevirdiğiniz zaman artış miktarı 10 kat artabilir. Bu uygulamayı size bırakıyorum.
Bir sonraki uygulamamızda Nextion ekran kullanacağız. İlgili uygulamanın klasöründe ekran ile ilgili dosyaları bulabilirsiniz. Hazır dosyayı kullansanız dahi öncelikle bunun nasıl yapıldığını öğrenelim.
Öncelikle Photoshop, Fireworks ve benzeri bir programda şu tarz bir arka plan resmi oluşturdum. Skala resmini çizecek grafik tasarımla meşgul olmadığım için internetten hazır alıp zaman kazandım.
Sonrasında Nextion Editor’de yeni bir proje açıp bunu arka plan resmi olarak belirledim. Sonrasında ise alet kutusundan “gauge” adlı aleti seçtim.
Gauge adından anlaşılacağı üzere bir saat kadranı gibi belli değerlere göre açısal olarak konumlanan bir ibredir. Bunun aldığı değerler de açı değerleri olmaktadır. Yalnız bu ibre ham hali ile göze pek hoş görünmemektedir. Biz skalayı ayarladığımız için sadece ibreyi kullanacağız bu yüzden arka planı “crop image” yapmaktayız.
Sonrasında elementi bizim resmimize tam uyacak şekilde konumlandırmamız ve boyutlandırmamız gereklidir.
Kullandığımız ekran ufak ve düşük çözünürlüklü olduğu için bir pikselin bile büyük önemi vardır. Ben bazı projelerde 2.4'’ bazılarında ise 3.5'’ ekran kullandım ve ikisini karşılaştırdığımda küçük ekranda çalışmayı her zaman daha zor buldum.
Şimdi kodu inceleyelim ve ne değişiklik yaptığımıza bakalım. Uygulamayı daha önceki uygulamanın üzerine yazdım bu yüzden sadece yaptığım değişiklikleri göstereceğim. Uygulamanın tamamını diğerleri gibi Github deposunda bulabilirsiniz.
Burada yukarıda okuduğum sayma değerinin altına bu değeri ekrana uyarlamak için gerekli kodları yazdım. Öncelikle ibrenin asgari ve azami değerlerini bulmak gerekli. Bu değerler de skalanın en sol kenarı ile en sağ kenarı olmaktadır. Programda debug yaparken bu değerleri saptadım.
Yalnız bu değerler 0–100 arası gibi doğrusal değerler değildi. İbre solu gösterdiğinde 0 değerinde en yukarıda olduğunda 90 değerinde en sağda olduğunda ise 180 değerindeydi. Ama elimizdeki skala 0'dan itibaren başlamıyordu. Bu skalanın 325'den başlayıp 220'de bittiğini tespit ettim. Bu durumda bizim 0 değerimiz aslında 325 olacak bu 360'a kadar devam edecek, 360'dan sonra sıfırlanıp 220'ye kadar artmaya devam edecek. Bu şekilde yapmazsak asla ibre doğru değerleri göstermeyecektir.
Bir diğer sorun ise ibre en son sınır olan 220'den büyükse daha fazla artmasın dersek bu sefer 0 noktasında yani 325 değerinden itibaren olunca da artmamaya başlamaktaydı. Yani başı ile sonunu bir şekilde sınırlamak gerekliydi. Bu yüzden 0 dereceyi sıfır noktası kabul ettim ve sıfır noktasından önce ve sıfır noktasından itibaren diye iki ayrı durum belirledim. Bu durumu ise ibre_pozitif değişkeninde sakladım.
Yukarıda uygulamanın çalışma videosunu görebilirsiniz.