Tuşlu Rotary Encoder Modül Yapımı

Benim enkoder üzerinde pullup dirençleri ve 100nF smd kondansatörler var. Onları söküp piconun pullup olayını yapmayı deneyeceğim.
Bende pico olmadığı için ben deneyemiyorum, gönderdiğim kodları kopyalayıp dener misiniz, pico üzerinde nasıl çalışacağını görelim...

Redmi Note 8 Pro cihazımdan Tapatalk kullanılarak gönderildi
 
Bende pico olmadığı için ben deneyemiyorum, gönderdiğim kodları kopyalayıp dener misiniz, pico üzerinde nasıl çalışacağını görelim...

Redmi Note 8 Pro cihazımdan Tapatalk kullanılarak gönderildi
Sizin kodları hiç bir şekilde çalıştıramıyorum. Serial monitöre tek satır yazmıyor.
Bendeki modül encoder yerine yalın encoder kullandım nafile.
Bu arada encoderleri de Özdisandan almışım. Nispeten kalitelidir bunlar.
 
Jumper kabloların plastiklerini söküp sıkıştırıldıkları yerlere ufak ufak lehim yaptım.
Kendi kendine sayması şimdilik yok oldu. Ama pals kaçırması devam ediyor. Özellikle saat yönüne çevirirken çok kaçırıyor. Diğer taraf daha az kaçırıyor.
 
Aşağıdaki yapıya geri döndüğümde tek bir pals bile kaçırmadan sorunsuz çalışıyor.
Bu yapıda kalsam iyi olacak sanırım. Başka türlü içinden çıkamıyorum.

C++:
void encoder() {
  boolean PinDT = digitalRead(PinDt);
  boolean PinCLK = digitalRead(PinClk);
  if (millis() - oncekiZaman > 1) {
    if (PinCLK != oncekiDurum) {
      if (PinCLK == LOW) {
        if (PinDT == HIGH) {
          sayac++;
          Serial.print(sayac);
          Serial.println(" : sag");
        } else {
          sayac--;
          Serial.print(sayac);
          Serial.println(" : sol");
        }
      }
    }
    oncekiDurum = PinCLK;
    oncekiZaman = millis();
  }
}
 
Son durumlar üzerine bazı sınamalar yaptım ve aşağıdaki durumları gördüm:
1- noInterrupt() komutu yerine detachInterrupt(digitalPinToInterrupt(Pin)) komutu kullanıldığında interrupt devre dışı kalıyor. Yeniden devreye almak için attachInterrupt() komutu ile yapılandırılması gerekiyor.
2- Kesme ile çağrılan fonksiyonda interrupt devredışı bırakılsa bile ardı ardına birkaç interrupt oluşmuş oluyor ve pals kaçırma olarak adlandırdığımız atlama meydana geliyor.
3- Interrupt kesmesi süresince, çalıştırılan fonksiyon içerisinde de delay(), delayMicroseconds() gibi komutlar işlemiyor.

SONUÇ olarak:
Paylaştığım kodların aslında hayalet bir biçimde çalıştığı... Her nasılsa encoder palslerini kaçırmadan yakalayabiliyordum. Ancak debounce süresi, delay() üzerinde değişiklikler yaptığımda bunların hiçbir etkisi olmadığını gördüm.
Bu noktada pals kaçırmanın en kesin çözümü sizin de kullandığınız şekilde interrupt zamanını millis() fonksiyonu ile kaydederek if-else bloğu içinde kontrol etmek ve uygun olmayan kesmeyi yok saymak.
Sizin kodları kullanarak birkaç deneme daha yaptıktan sonra son sonuçları paylaşacağım...
 
Son durumlar üzerine bazı sınamalar yaptım ve aşağıdaki durumları gördüm:
1- noInterrupt() komutu yerine detachInterrupt(digitalPinToInterrupt(Pin)) komutu kullanıldığında interrupt devre dışı kalıyor. Yeniden devreye almak için attachInterrupt() komutu ile yapılandırılması gerekiyor.
2- Kesme ile çağrılan fonksiyonda interrupt devredışı bırakılsa bile ardı ardına birkaç interrupt oluşmuş oluyor ve pals kaçırma olarak adlandırdığımız atlama meydana geliyor.
3- Interrupt kesmesi süresince, çalıştırılan fonksiyon içerisinde de delay(), delayMicroseconds() gibi komutlar işlemiyor.

SONUÇ olarak:
Paylaştığım kodların aslında hayalet bir biçimde çalıştığı... Her nasılsa encoder palslerini kaçırmadan yakalayabiliyordum. Ancak debounce süresi, delay() üzerinde değişiklikler yaptığımda bunların hiçbir etkisi olmadığını gördüm.
Bu noktada pals kaçırmanın en kesin çözümü sizin de kullandığınız şekilde interrupt zamanını millis() fonksiyonu ile kaydederek if-else bloğu içinde kontrol etmek ve uygun olmayan kesmeyi yok saymak.
Sizin kodları kullanarak birkaç deneme daha yaptıktan sonra son sonuçları paylaşacağım...
Evet benim de şimdiki sıkıntım kesmelerin çakışması.
encoder içindeki sayı değişkenini bir yerde çağırdığımda 10 tur çevirsem bir pals ancak atlıyor. Bu da diğer kesmeler ile çakıştığına işaret diye düşünüyorum. noInterrupt() denedim direk kartı kilitliyor. Şu detachInterrupt komutunu anlayıp uygulamaya çalışacağım.
 
Arduino IDE 1.8.13 Üzerinde Arduino UNO İçin Yazıldı:
void Encoding() {
  PinDT=digitalRead(7);
  if (millis() - sonTik > DebounceSuresi) {
    if (PinDT==HIGH) {
      Sayac++;
      Serial.print(Sayac);
      Serial.println(" : sag");
    } else {
      Sayac--;
      Serial.print(Sayac);
      Serial.println(" : sol");
    }
    sonTik = millis();
  }
}

void Bt_Pushed(){
  if (millis() - sonButton > (DebounceSuresi*2)) {
    Sayac1+=1;
    Serial.println(Sayac1);
    sonButton = millis();
  }
}

Bu şekilde kod kullandığımda DebounceSuresi = 75 iken pals atlamıyor ancak arada geri sayım yapıyor.

Arduino IDE 1.8.13 Üzerinde Arduino UNO İçin Yazıldı:
void Encoding() {
  PinDT=digitalRead(7);
  detachInterrupt(digitalPinToInterrupt(2));
  detachInterrupt(digitalPinToInterrupt(3));
  if (millis() - sonTik > DebounceSuresi) {
    if (PinDT==HIGH) {
      Sayac++;
      Serial.print(Sayac);
      Serial.println(" : sag");
    } else {
      Sayac--;
      Serial.print(Sayac);
      Serial.println(" : sol");
    }
    sonTik = millis();
  }
  attachInterrupt(digitalPinToInterrupt(2), Encoding, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), Bt_Pushed, FALLING);
}

void Bt_Pushed(){
  detachInterrupt(digitalPinToInterrupt(3));
  detachInterrupt(digitalPinToInterrupt(2));
  if (millis() - sonButton > (DebounceSuresi*2)) {
    Sayac1+=1;
    Serial.println(Sayac1);
    sonButton = millis();
  }
  attachInterrupt(digitalPinToInterrupt(2), Encoding, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), Bt_Pushed, FALLING);
}

Bu şekilde detachInterrupt() ve attachInterrupt() kullanarak kesmeleri durdurunca geri sayım ile de karşılaşmadım.
 
Bu şekilde detachInterrupt() ve attachInterrupt() kullanarak kesmeleri durdurunca geri sayım ile de karşılaşmadım.
Yarın bakayım bu kodlara. Geç oldu benim için. Yarın evdeyim, kurcalarım bayağı.
 
Arduino IDE 1.8.13 Üzerinde Arduino UNO İçin Yazıldı:
Kod:
void Encoding() {
  PinDT=digitalRead(7);
  detachInterrupt(digitalPinToInterrupt(2));
  detachInterrupt(digitalPinToInterrupt(3));
  if (millis() - sonTik > DebounceSuresi) {
    if (PinDT==HIGH) {
      Sayac++;
      Serial.print(Sayac);
      Serial.println(" : sag");
    } else {
      Sayac--;
      Serial.print(Sayac);
      Serial.println(" : sol");
    }
    sonTik = millis();
  }
  attachInterrupt(digitalPinToInterrupt(2), Encoding, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), Bt_Pushed, FALLING);
}

void Bt_Pushed(){
  detachInterrupt(digitalPinToInterrupt(3));
  detachInterrupt(digitalPinToInterrupt(2));
  if (millis() - sonButton > (DebounceSuresi*2)) {
    Sayac1+=1;
    Serial.println(Sayac1);
    sonButton = millis();
  }
  attachInterrupt(digitalPinToInterrupt(2), Encoding, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), Bt_Pushed, FALLING);
}
Günaydın.
Burada anlamadığım bir durum var.
1- attachInterrupt(digitalPinToInterrupt(2) buradaki "2" neyi ifade ediyor?
 
Arduino UNO'da iki adet external interrupt pini mevcut. Bu pinler 2 ve 3 nolu dijital pinler. 2 nolu pin 0 nolu interrupt, 3 nolu pin ise 1 nolu interrupt'a bağlı.
attachInterrupt(PinNumber, ISR, MODE) yapılandırması esnasında interrupta atanacak pin numarasının digitalPinToInterrupt(2) şeklinde belirtilmesi öneriliyor. İlgili sayfanın linki burada...
 
Son düzenleme:
Arduino UNO'da iki adet external interrupt pini mevcut. Bu pinler 2 ve 3 nolu dijital pinler. 2 nolu pin 0 nolu interrupt, 3 nolu pin ise 1 nolu interrupt'a bağlı.
attachInterrupt(PinNumber, ISR, TRIGGER) yapılandırması esnasında interrupta atanacak pin numarasının digitalPinToInterrupt(2) şeklinde belirtilmesi öneriliyor. İlgili sayfanın linki burada...
abi bir karışıklık var sanırım burda 0 yazınca d2 oluyordu
 
Aslında bu linkteki açıklamaları dikkatlice okuyunca, ki ben pek çoğunu maalesef atlamışım, millis(), micros(), delay(), delayMicroseconds() kullanımları ve ISR ile main loop arasında değişken paylaşımlarına dair bilgilendirmeler var.
 
Şimdi şöyle bir sorun yaşıyorum;
Kesmeleri sizinki gibi yapıp ekledim ama çalıştığını nasıl test ederim bilemedim.
Normal serial monitörde izlerken bir sıkıntı görünmüyor ama keypad den A tuşuna basıyorum ve page = 'a'; olarak akımın set edileceği sayfaya yönlendiriyorum. Bu işlemi yaptıktan sonra encoder 50 çevirmede 1 pals atlayacak gibi çalışıyor. (50 sayısı örnektir. bolca çevirmek gerekiyor).
page = 'i'; yaptığımda ise (index) anasayfaya yönleniyor ve burada encoder sorunsuz çalışıyor.
Ayrıca ecoder butonuda her koşulda sorunsuz çalışıyor. Sadece çevirmede problem var.

C++:
if (page == 'a') {
    u8g2.clearBuffer();
    if (digitalRead(right_btn) == 1) {
      if (kursor_konum == 0) {
        kursor_konum = 1;
      } else if (kursor_konum == 1) {
        kursor_konum = 2;
      } else if (kursor_konum == 2) {
        kursor_konum = 3;
      } else {
        kursor_konum = 0;
      }
    }
    if (digitalRead(left_btn) == 1) {
      if (kursor_konum == 0) {
        kursor_konum = 3;
      } else if (kursor_konum == 3) {
        kursor_konum = 2;
      } else if (kursor_konum == 2) {
        kursor_konum = 1;
      } else {
        kursor_konum = 0;
      }
    }
    if (kursor_konum == 0) {
      u8g2.drawLine(52, 41, 59, 41);
      u8g2.drawLine(52, 42, 59, 42);
      sayi1 = sayac;
    } else if (kursor_konum == 1) {
      u8g2.drawLine(64, 41, 71, 41);
      u8g2.drawLine(64, 42, 71, 42);
      sayi2 = sayac;
    } else if (kursor_konum == 2) {
      u8g2.drawLine(88, 41, 95, 41);
      u8g2.drawLine(88, 42, 95, 42);
      sayi3 = sayac;
    } else if (kursor_konum == 3) {
      u8g2.drawLine(100, 41, 107, 41);
      u8g2.drawLine(100, 42, 107, 42);
      sayi4 = sayac;
    }
    voltaj_akim = sayi1 * 10.0 + sayi2 * 1.0 + sayi3 * 0.1 + sayi4 * 0.01;
    //// Akım değerini ekrana yazdırma /////

    drawF(0, 0, 128, 64, 1, 1, 126, 62);
    u8g2.drawLine(5, 18, 122, 18);
    u8g2.drawLine(5, 46, 122, 46);
    u8g2.setFont(u8g2_font_VCR_OSD_tr);
    u8g2.setCursor(4, 40);
    u8g2.print("SET:");
    ival = voltaj_akim * 100;
    sprintf(buffer, "%02d.%02d", ival / 100, ival % 100);
    u8g2.setCursor(50, 40);
    u8g2.print(buffer);
    u8g2.setCursor(112, 40);
    u8g2.print(F("A"));
    u8g2.sendBuffer();

  }
 
Ben dünki denemelerde
1- detachInterrupt() kullanıp, ISR çıkışında interrupt'ı yeniden attach etmeyince kesmeler bir defa çalışıp daha çalışmadı. Demek ki kesmelere girince detachInterrupt() yapmak interruptları deaktive ediyor.
2- Kesmeden çıkarken attachInterrupt ile kesmeleri yeniden kurduğumda artık problem yaşamadan kesmelerin her çevirmede ve buttona her basmada çalıştığını gördüm, bunda da tereddüdüm kalmadı.

Buradan itibaren encoder modülünün tasarımı ve yazılım tarafındaki yapılandırma ile ilgili detaylara dikkat etmemiz gerektiğini düşünüyorum.
1- Modüldeki pull-up dirençleri 10Kohm olarak büyük gelmiş olabilir, bunları daha düşük değerlerle değiştirerek daha stabil bir durum elde edilebilir.
2- Sayın @Gokrtl sizin daha önceki Uçak Paneli çalışmanızda da rotary encoder bahsinde bu durumlar söz konusu olmuş. Orada Sayın @Endorfin35+ bir gönderisinde, Interrupt kesmesi palseleri doğru saysa bile bu palslerin serial monitöre yazdırılması esnasında meydana gelecek kaymanın aradaki bazı değerlerin atlanmasına sebep olabileceğini yazmış. Arduino attachInterrupt bilgilendirme sayfasında ISR (yani interrupt kesmesinde çalışan fonksiyon) ile main loop arasında değişken paylaşımı hakkında: "Typically global variables are used to pass data between an ISR and the main program. To make sure variables shared between an ISR and the main program are updated correctly, declare them as volatile." bildirilmiş. Yani ISR ile main loop arasında data geçişinin sağlanabilmesi için tipik global değişkenler kullanıldığı ve bu değişkenlerdeki update'in yakalanabilmesi için bunların volatile olarak tanımlanması gerektiği de eklenmiş. Öncelikle buna dikkat etmek lazım.

Yukarıdaki kodda görüldüğü kadarıyla, encoderin saydığı sayac değişkenini ilgili basamağı temsil eden değişkene aktarıyorsunuz. Şöyle düşünelim:
encoder döndükçe 4. basamağa ait değişken 0, 1, 2, 3, 4 ... 9 diye sayıyor. 10 defada bir bu sayı yeniden 0'a dönecek ve 1, 2, 3, 4 .. diye devam edecek. Siz de her defasında bu sayı 0 veya 1 ya da başka bir rakam iken aynı rakamı ekrana yazdırırsanız hiçbir şeyin değişmediği izlenimine kapılırsınız.
Nitekim encoder çok hızlı bir şekilde data üretebiliyor ancak main loop yukarıdaki kodların yoğunluğuna bağlı olarak bu hıza yetişemiyor.
Dolayısıyla ISR'de encoder palsleri üzerinden üretilen sayac değişkeninin main loop'taki daha sade bir kod bloğuna nasıl doğruca aktarılacağını tespit etmemiz lazım. Burada bir kesinlik yakaladıktan sonra devamına baksan daha doğru olacak. Çünkü Kodlamanın herhangi bir kısmından emin olmazsak problemin nereden kaynaklandığını anlamamız imkansız ya da tesadüfe bağlı hale gelecek.
 
Özellikle Interrupt tarafından işlenen değişkenlerin volatile olarak tanımlanmasına dair şu sayfa problemimizin bir kısmına belki tamamına işaret etmekte.

Buna bağlı olarak değeri interrupt içinde belirlenen değişkenleri tanımlarken başlarına volatile belirtecini eklememiz öncelikli bir çözüm olabilir.
 

Çevrimiçi üyeler

Forum istatistikleri

Konular
6,141
Mesajlar
104,842
Üyeler
2,553
Son üye
trojann

Son kaynaklar

Son profil mesajları

hakan8470 wrote on Dede's profile.
1717172721760.png
Dedecim bu gul mu karanfil mi? Gerci ne farkeder onu da anlamam. Gerci bunun anlamini da bilmem :gulus2:
Lyewor_ wrote on hakan8470's profile.
Takip edilmeye başlanmışım :D ❤️
Merhaba elektronik tutsakları...
Lyewor_ wrote on taydin's profile.
Merhabalar. Elektrik laboratuvarınız varsa bunun hakkında bir konunuz var mı acaba? Sizin laboratuvarınızı merak ettim de :)
Lyewor_ wrote on taydin's profile.
Merhabalar forumda yeniyim! Bir sorum olacaktı lcr meterler hakkında. Hem bobini ölçen hemde bobin direnci ölçen bir lcr meter var mı acaba?
Back
Top