Arduino ile Rotary Encoder Kullanımı

Arduino ile Rotary Encoder kullanımı, dönme hızının sıklıkla kullanıldığı projelerde mutlaka karşınıza çıkmıştır. Bu yazımızda Arduino ve diğer mikrodenetleyiciler ile kullanabiliceğiniz rotary encoder’ı anlatıyoruz.

Rotary Encoder Nedir?

Şaft kodlayıcı olarak da adlandırılan rotary encoder, bir şaftın veya aksın açısal pozisyonunu veya hareketini analog veya dijital çıkış sinyallerine dönüştüren bir elektro-mekanik cihazdır. İki ana döner kodlayıcı türü vardır: mutlak ve artımlı.

Rotary Encoder Türleri

İki genel döner kodlayıcı türü vardır.

Mutlak Döner Kodlayıcı/Absolute Rotary Encoder

Daha pahalı olan mutlak tip, önceki tüm pozisyonlarını takip edebilir. Temel olarak, döner kodlayıcı üzerindeki düğmenin tüm konumları bir değere sahiptir. Değerin okunma şekli, kodlayıcının kullandığı sensöre bağlıdır: manyetik, optik veya mekanik.

Aşağıdaki optik kodlayıcıyı göz önünde bulundurun:

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

Disk, her biri karşılık gelen ikili veya gri kod değerine sahip olan 16 alana bölünür. Mevcut konumu belirlemenin yolu, disk üzerindeki bir ışık kaynağından geçmektir. Gösterildiği gibi, her alan veya konumun dört penceresi vardır; bu pencerelerin her birine bir ışık kaynağı ve alıcı yerleştirilmiştir.

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

Örneğin, mevcut konum 1110’da olduğunda, birinci pencereye kadar olan üçüncü pencereler şeffaf olduğundan ışık alacaktır. Sonuç olarak, opak olan son pencere hiç ışık almayacak. Işık alıcıları daha sonra aldıkları ışığa göre sinyal verecektir, Her pencerenin benzersiz bir kombinasyonu olduğundan, düğmenin mevcut konumu bilinebilir.

Artımlı Döner Kodlayıcı/Incremental Rotary Encoder

Diğer bir kodlayıcı türü, artımlı türdür. Mutlak gibi, artımlı kodlayıcı da sensör tipine göre daha fazla kategorize edilir. Aşağıda gösterilen elektromekanik tip, elektronik devreler için ortaktır:

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

Elektromekanik kodlayıcı, elektrik kontakları 90 derece aralıklı olan dönen bir diskten oluşur. Elektrik kontakları “+” pini üzerinden bağlanırken, alanın geri kalanı “GND” pinine bağlanır. DT ve CLK pininin disk üzerindeki konumu aşağıda gösterilmiştir.

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

Not: SW pini, orta kısımda olan şafta bağlanır.

Şaftı döndürdüğünüzde ve disk döndüğünde, DT veya CLK pini elektrik kontaklarıyla temas eder.

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

Yukarıdaki şekilde, disk saat yönünün tersine döner ve DT pini elektrik kontağına bağlar. Bu pindeki voltaj, “+” pinindeki uygulanan voltaja eşittir.

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

Disk tekrar saat yönünün tersine dönerse, hem DT hem de CLK pinleri “+” pinine eşit voltaja sahip olur.

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

DT pini bir sonraki dönüşte elektrik kontağını bırakır ve voltaj seviyesi 0 V’a geri döner.

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

CLK pini de şimdi elektrik kontağından ayrılır ve her iki pin de başlangıç konumlarındaki gibidir.

Dönme Yönü

Diskin dönüşü hem DT hem de CLK pinlerinde darbeler üretir. Ancak, dönüş yönüne bağlı olarak, bir pimin darbesi diğerini her zaman 90 derece (elektriksel temas aralığına eşit) önündedir.

Orijinal konumundan iki farklı şey olabilir: disk ya saat yönünün tersine ya da saat yönünde döner. Dönmeyi algılamak için pinlerden birinin durum değişip değişmediğini kontrol etmeliyiz.

Arduino ile Rotary Encoder Kullanımı arduino ile rotary encoder,rotary encoder arduino,rotary encoder,arduino rotary encoder kullanımı,rotary encoder kullanımı

Yukarıdaki resimde, DT’nin durumu saat yönünün tersine değiştirmesi veya CLK’nın durumu saat yönünde değiştirmesi için iki aşama alacaktır.

Burada DT’ye bakacağız. DT yüksekten düşüğe gittiyse ve CLK DT’ye eşitse, dönüş saat yönündedir. Öte yandan, saat yönünün tersine döndürürsek, DT durumu değiştirmeyecektir. Ama bundan sonra, tekrar saat yönünün tersine döndüğümüzde, DT yüksekten alçağa gider ve CLK yüksek olur. Bu, DT ve CLK’nın orijinal konumundan bağımsız olarak gerçekleşir. Bu, dönme yönünü belirlemek için bir algoritma kullanmamız kodlama esnasında bize oldukça yardımcı olur.

Rotary Coder Konumunu Öğrenme

Dönme yönüne göre azalan veya artan bir kodlayıcı_degeri değişkeni atarız.

int kodlayici_degeri

Sonra DT ve CLK pinlerinin durumunu kontrol ederiz (onları giriş pinleri olarak tanımladığımızı varsayarak):

if (DT_pindurumu != son_DT_pindurumu) { //DT durum değiştirdi mi?
  if (digitalRead(CLK_pin) == DT_pindurumu) { // DT durumu değiştirirse, CLK'yı kontrol et

    kodlayici_degeri--; // dönüş saat yönünde, değeri azalt
  }
else {
    kodlayici_degeri++; // dönüş saat yönünün tersine, değeri arttır
  }
  son_DT_pindurumu = DT_pindurumu; //DT'nin son konumunu kaydet

}

Encoder konumunu seri porttan yazdırıldığı Arduino kodu:

int kodlayici_degeri = 0;
int DT_pini = 6;
int CLK_pini = 7;
int DT_pin_durumu;
int son_DT_pin_durumu;

void setup() {
  pinMode (DT_pini, INPUT);
  pinMode (CLK_pini, ,INPUT);

  Serial.begin (9600);

  son_DT_pin_durumu = digitalRead(DT_pini);
}

void loop() {
  if (DT_pin_durumu != son_DT_pin_durumu) { 
    if (digitalRead(CLK_pini) == DT_pin_durumu) { 
       kodlayici_degeri--; 
    }else{
       kodlayici_degeri++; 
    }
  son_DT_pin_durumu = DT_pin_durumu; 
  Serial.print("Konum: ");
  Serial.println(kodlayici_degeri);
  }

  son_DT_pin_durumu = DT_pin_durumu; 
}

Kesmelerin Kullanımı

Üstte verilen kod çalışırken, DT’nin durum değişikliğinin kaçırıldığı ve kodlayıcı_değerinin değiştirilmesinde gecikmeye neden olduğu durumlar olabilir. Başka bir durum, kodunuzun döngü() içinde başka önemli şeyler yapması gerektiğidir. Bu nedenle, kesmeler kullanarak kodumuzu daha da geliştirebiliriz.

Arduino UNO üzerindeki D2 ve D3 pinleri harici kesme pinleridir. Bu pinlere DT ve CLK atadık, böylece loop() içinde digitalRead() kullanmadan durumdaki değişikliği algılayabiliriz.

Ardından, DT’nin durumu her değiştirdiğinde tetiklenen bir kesme işleyicisi oluştururuz.

Hızı Ölçmek

Belirli bir süre boyunca tam bir dönüş için attığı adımları sayarak kodlayıcının dönüş hızını ölçebilirsiniz. Bu, kesintileri kullanmamaktan çok daha verimlidir çünkü eksik darbeleri önleyebiliriz.

İşte hızı rpm ve açısal hız olarak gösteren kod:

// 360 derece dönüş başına motor kodlayıcı çıkış darbeleri (manuel olarak ölçülür)
#define ENC_COUNT_REV 620

volatile long encoder_degeri = 0;

// ölçüm için aralık
int aralik = 1000;

// Aralik sırasında milisaniye için sayaç
long oncekiMillis = 0;
long anlikMillis = 0;

// RPM ölçümü için değişken
float rpm = 0;

// Açısal hız ölçümü için değişken
float acisal_hiz = 0;
float acisal_hiz_derecesi = 0;

const float rpm_radyan_cevirme = 0.10471975512;
const float radyan_derece_cevirme = 57.29578;

int DT_pini = 2;
int CLK_pini = 3;

void setup() {
  pinMode(DT_pini , INPUT_PULLUP);
  pinMode(CLK_pini , INPUT);

  Serial.begin(9600);

  // Pin her yükseldiğinde, darbe
  attachInterrupt(digitalPinToInterrupt(DT_pini), interrupt_on_pulse, RISING);

}

void loop() {

  // zamanı kaydet
  anlikMillis = millis();

  // Bir saniye geçtiyse, darbe sayısını yazdırı
  if (anlikMillis - oncekiMillis > aralik) {

    oncekiMillis = anlikMillis;

    // dakikadaki devir sayısını hesaplar
    rpm = (float)(encoder_degeri * 60 / ENC_COUNT_REV);
    acisal_hiz = rpm * rpm_radyan_cevirme;
    acisal_hiz_derecesi = acisal_hiz * radyan_derece_cevirme;

    Serial.print(" Darbe: ");
    Serial.println(encoder_degeri);
    Serial.print(" Hiz: ");
    Serial.print(rpm);
    Serial.println(" RPM");
    Serial.print(" Acisal Hiz: ");
    Serial.print(acisal_hiz_derecesi);
    Serial.println(" derece/saniye");
    Serial.println();

    encoder_degeri = 0;
  }
}

//Darbe sayısını 1 artır
void interrupt_on_pulse() {

  // 
  int deger = digitalRead(CLK_pini);

  if (deger == LOW) {
    encoder_degeri++;
  }
  else {
    encoder_degeri--;
  }
}

Yukarıdaki kodda, bir dönüş için darbe sayısını 620’ye ayarladık. Bu, burada sunulan artımlı döner kodlayıcı için tipiktir. Kodlayıcınız farklı görünüyorsa, düğmeyi tam tur döndürmeyi deneyin ve seri monitörde görülen kodlayıcı değerini (ilk olarak verdiğimiz kısa kodu kullanın) not edin.

Arduino Rotary Encoder Kütüphanesi

Rotary encoderleri kütüphane olmadan kullanmak tamamen mümkün olsa da, kütüphane kullanırsanız zamandan ve emekten tasarruf edersiniz. Buradaki rotary encoder kütüphanesi ile daha iyi görev yönetimi için kesme kullanımı da dahil olmak üzere temel kullanım için yeterlidir.

RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
void setup()
{
  Serial.begin(115200);
  while (! Serial);
  Serial.println("RotaryEncoder kutupahensi testi.");

void loop()
{
  static int pos = 0;
  encoder.tick();
  int newPos = encoder.getPosition();
  if (pos != newPos) {
    Serial.print("pozisyon:");
    Serial.print(newPos);
    Serial.print(" yon:");
    Serial.println((int)(encoder.getDirection()));
    pos = newPos;
  } 
} 

Kesme kullanılarak yapılan örnek:

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  Serial.println("otaryEncoder kütüphanesi.");
  encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

  attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);
} 
void loop()
{
  static int pos = 0;
  encoder->tick(); 
  int newPos = encoder->getPosition();
  if (pos != newPos) {
    Serial.print("pozisyon:");
    Serial.print(newPos);
    Serial.print(" yon:");
    Serial.println((int)(encoder->getDirection()));
    pos = newPos;
  } 
} 

Ayrıca bu kütüphane, ESP8266 ve ESP32 içinde desteklendiğini belirtelim.

Buraya kadar anlamadığınız bir durum varsa ya da sorun yaşıyorsanız, yorum kısmında belirtebilirsiniz.