Debounce Algoritması

Endorfin35+

Kayıtsız Üye
Katılım
1 Mayıs 2020
Mesajlar
4,193
Normalde debounce kodlarımçalışıyor ancak her buton için ayrı kod yazmak zorunda kalıyorum. Yazıdığım kodu fonksiyon haline getiremedim. Fonksiyon haline getirdiğim zaman buton başına +1 boolean bir değişken tanımlamam gerekiyor ki olması gereken bu mu emin değilim.

Kurduğum temek mantık şu şekilde;

debounce aşamasında sağlıksız 10101101 veriler geliyor ve sonra 1 verisi geliyor. 1 verisi geldikten sonra 50ms gibi bir süre boyunca tekrar 0 gelmez ise debounce aşaması tamamladı kabul edip işleme geçiyorum.

C:
  if (buton == LOW) zaman=0;
 
  if (buton == HIGH)
  {
        delay(1);
        zaman++;
        
        if (zaman < 50)           // 50ms  Debounce süresi boyunca birşey yapma
        {
          
        }
        else if (zaman < 1000)       // butona basılıyor. 1. Fonksiyon (normal işlem)
        {
          foksiyon_1();
        }   
        else if (zaman >1000)       // butona basılıyor. 2. Fonksiyon (hızlı işlem)
        {
          fonksiyon_2();
        }

  }


Aslında kod içeriğinde delay yok burda mantık anlaşılsın diye basit yazım. Sıkıntı yaşadığım konu zaman sayacını sıfırlama...

Buton A aktifse say değilse sıfırla
Buton B aktifse say değilse sıfırla

Butonların hepsi aktif olmadığına göre sürekli sıfırla oluyor.... Bunu aşmanın yolu her buton için ayrı bir değişken daha tanımlama. Aklıma daha basit bir şey gelmiyor. Belki buran birşey çıkar :)
 
Ben kod yazma işinde acemiyim. Senin anlattığın kadarıyla şöyle bir deneme yaptım.

Kod:
  buton_kontrol (blooen=gelen_buton){ //butona basınca fonksiyona gönder
 
    if (gelen_buton == aktif){         //buton aktifse say
 
        say;
        
    }else{
 
    int zaman = 0;     //değilse zamanı sıfırla
 
    }
 
  }
 
 
 
    //fonksiyonu çağır...
  buton_kontrol(buton_A)
 
Ben kod yazma işinde acemiyim. Senin anlattığın kadarıyla şöyle bir deneme yaptım.

Bende senin gibi düşündüm ama bir mantık hatası var şöyleki;


Kod:
   //fonksiyonu çağır...
  buton_kontrol(buton_A)

   //fonksiyonu çağır...
  buton_kontrol(buton_B)



buton_kontrol (blooen=gelen_buton)  //butona basınca fonksiyona gönder
{

    if (gelen_buton == aktif){         //buton aktifse say

        say;
       
    }else{

    int zaman = 0;     //değilse zamanı sıfırla

    }
}

kod sürekli döngüde olduğu için sıkıntı çıkıyor. Şöyleki buton_A için fonksiyonu çağırdık saymaya başladık.
ikinci satırda buton_B için yine fonksiyonu çağırınca buton_B aktif olmadığı için sayacı sıfırlıyor... Zaten sorunda tam olarak bu :)
 
Butona 1 kere basınca aktif, ikinci basmada pasif mi oluyor?
Buton A aktifken buton B ye basılınca ikisi aynı anda aktif olabiliyor mu? yoksa buton A yı sıfıralaması mı gerekiyor?
Kaç buton var?
 
Sadece 1 buton aktif diğerleri pasif olacaksa fonksiyon içinde her buton için if döngüsü yazılabilir.


Kod:
  buton_kontrol (blooen=gelen_buton){ //butona basınca fonksiyona gönder
    if(gelen_buton == buton_A){     // gelen_buton A ise bunu yap
        if (gelen_buton == aktif){         //buton aktifse say
           
            say;
            buton_B = 0;
            buton_C = 0;
            buton_D = 0;
            boton_E = 0;
           
        }else{
     
        int zaman = 0;     //değilse zamanı sıfırla
     
        }
    }elseif(gelen_buton == buton_B){   // yok gelen buton B ise bunu yap
        if (gelen_buton == aktif){         //buton aktifse say
           
            say;
            buton_A = 0;
            buton_C = 0;
            buton_D = 0;
            boton_E = 0;
           
        }else{
     
        int zaman = 0;     //değilse zamanı sıfırla
     
        }  
    }
  }



    //fonksiyonu çağır...
  buton_kontrol(buton_A)
 
butona bastığın sürece aktif oluyor. 5 adet buton var. .butonlara aynı anda basılmıyor.

Şöyle daha anlaşılır olacak ;

C++:
if (buton_1 == aktif) //buton aktifse say
{         
    zaman++;
}
else
{
    zaman = 0;     //değilse zamanı sıfırla
}


Burda butona bastığımız anda buton arkı (debounce) nedeni ile çok kısa bir sürede buton aktif-pasif-aktif-pasif.....Aktif oluyor. Sinyal oturduktan sonra işleme alıyoruz. Bunuda süre tutarak anlıyoruz. Buton aktif olduktan sonra belli bir süre pasif olmaz ise tamam bu iş diyoruz. Ancak araya bir pasif sinyal daha girer ise zaman sayacını sıfırlıyap tekrar baştan sayıyoruz.

Bu kod bir buton için çalışıyor.

Şimdi bunu 3 buton için yazalım;

C++:
if (buton_1 == aktif) //buton aktifse say
{         
    zaman1++;
}
else
{
    zaman1 = 0;     //değilse zamanı sıfırla
}

if (buton_2 == aktif) //buton aktifse say
{         
    zaman2++;
}
else
{
    zaman2 = 0;     //değilse zamanı sıfırla
}

if (buton_3 == aktif) //buton aktifse say
{         
    zaman3++;
}
else
{
    zaman3 = 0;     //değilse zamanı sıfırla
}

Bu kodda çalışıyor ancak hem bir sürü kod yazdık. hemde 3 tane zaman değişkeni oldu...

Bir sürü kod yazman yerine bunu fonksiyon yapma mantığını kuramadım. Sıkıntı çıkartan zamanı sıfırlama...
 
Bu da mı gol değil? :katil1:

Kod:
    //fonksiyonu çağır...
  buton_kontrol(buton_1)
 

buton_kontrol(blooen, gelen_buton)   //Butonu al.
{   
    if(gelen_buton == buton_1)  // Eğer gelen buton 1 ise buton_islem fonksiyonuna gönder
    {   
        buton_islem(buton_1);
    }
    elseif(gelen_buton == buton_2)    // Eğer gelen buton 2 ise buton işlem fonksiyonuna gönder
    { 
        buton_islem(buton_2);
    }
    elseif(gelen_buton == buton_3)
    {
        buton_islem(buton_3);
    }
    elseif(gelen_buton == buton_4)
    {
        buton_islem(buton_4);
    }
    else
    {
        buton_islem(buton_5);
    }
}

buton_islem(blooen, buton_X){

    if (buton_X == aktif) //buton aktifse say
    {   
        zaman++;
    }
    else
    {
    zaman = 0;     //değilse zamanı sıfırla
    }
}
 
Son düzenleme:
Böyle olur. : ) Bende buna benzer birşey yaptım şöyle ;

C++:
int aktif_buton;
if(gelen_buton == buton_1) // Eğer gelen buton 1 ise buton_islem fonksiyonuna gönder
{   
        aktif_buton=1;
    buton_islem(buton_1);
}
else if (aktif_buton==1)
{
    buton_islem(buton_1);
}
    



if(gelen_buton == buton_2) // Eğer gelen buton 2 ise buton_islem fonksiyonuna gönder
{   
        aktif_buton=2;
    buton_islem(buton_2);
}
else if (aktif_buton==2)
{
    buton_islem(buton_2);
}
        
        

buton_islem(buton_X){
    if (buton_X == aktif) //buton aktifse say
    {     
        zaman++;
    }
    else
    {
    zaman = 0;     //değilse zamanı sıfırla
    }
}


bunun daha şık bir yolu olmalı. Biraz daha kafa yorayım...
 
toplam 33 Satırda 5 butonu da kontrol ettirip işlem yaptırdım. O da senin yazdığın usülle.
Ben köşeli parantezleri else'lerin önüne arkasına koymaya alıştım. Öyle yaparsam 21 Satır oluyor.
Eğer 33 satırdan daha küçük yaparsan çay ısmarlarım sana :D
 
Her bir buton için bir struct tanımlarsan daha modüler oluyor. Böylece 10 buton varsa, bu struct ları içeren bir array yaparsın, array deki buton sayısını tanımlarsın. Yani istediğin sayıda butonu işleyebilirsin.

Debounce için ben şöyle bir algoritma kullandım hep:

Buton durumlarını sabit periyotlarla oku. Eğer bir butonun değeri belli bir okuma sayısında aynı kaldı ise (hep ON veya hep OFF) o zaman butonun debounce edilmiş yeni durumunu güncelle.

Butonu sabit peryotlarda okutmak için de ya bir kesme kullanabilirsin (mesela saniyede 10 kere çağrılan), veya ana kodun döngü süresi sabit ve bu sürenin de ne olduğu belli ise, ana döngüde de yapılabilir bu iş.
 
debounce içine press&hold eklediğim için çıkıyor sıkıntı... Az daha kasıyım bakalım ne olcek :cheeky2:
 
Mesela şöyle bir kod olabilir (test etmedim, konsept anlaşılması için koyuyorum)

C:
typedef struct
{
   int port;
   int count;
   int prev;
   int curr;
   int status;

} BUTTON;

/* kac tane buton isleyecegiz */
#define NUM_BUTTONS 5

/* kac kere ayni buton durumunu gorunce butonun stabil hale geldi
* diyecegiz */
#define DEBOUNCE_THR 3

static BUTTON buttons[NUM_BUTTONS];

void process_buttons(void)
{
   for (unsigned int i = 0; i < NUM_BUTTONS; ++i)
   {
      BUTTON* b = &buttons[i];

      b->prev = b->curr;
      b->curr = read_button_status(b->port);

      if (b->curr == b->prev)
      {
         ++b->count;

         if (b->count >= DEBOUNCE_THR)
         {
            b->count = 0;
            b->status = b->curr;
         }
      }
      else
      {
         b->count = 0;
      }
   }
}

Burada process_buttons fonksiyonunu örneğin 10 ms de bir kesmenin içerisinden çağırabilirsin. Veya 1 ms de bir çağırırsın ve one göre bir debounce eşiği seçersin.

Sonra da artık ana kod debounce edilmiş buton değeri olan BUTTON->status e göre hareket edebilir.
 
Mesela şimdi bu koda "çift tıklama" veya süreli basma gibi özellikler ekleyeceksen, bunun için tamamen bağımsız bir fonksiyon yazıp BUTTON->status e göre işlem yapmasını sağlayabilirsin. Mesela çift tık için OFF ON geçiş zamanını kaydedersin. Sonra ya yeni bir OFF ON geçişinde önceki kaydedilen süre ile arasındaki farka bakıp, yeterince kısa ise bunu "çift tık" kabul edersin.

Veya basılı tutma için de OFF ON zamanını kaydedip, şimdiki zaman ile arasındaki farka bakarsın. Buradan da belli bir süre basılı olduğunu anlarsın.
 
Abi ben struct kullanmadım hiç. Ancak fırsattan istifade öğrenmek istiyorum. Anlayamadığım bir kaç nokta var yardımcı olur musun? Debounce değil struct tan bahsediyorum.

Kod:
typedef struct
{
   int port;
   int count;
   int prev;
   int curr;
   int status;

} BUTTON;

Burada BUTTON yapısını oluşturmuşsun burası tamam.

Kod:
#define NUM_BUTTONS 5

static BUTTON buttons[NUM_BUTTONS];

Burda buton sayısı kadar BUTTON yapısında dizi oluşturulmuş. burasıda tamam..


Kod:
      BUTTON* b = &buttons[i];

Anlamadığım yer burası.

1. BUTTON* neyi ifade ediyor. b nerden geldi.
2. &buttons derken neden başa & yazıyoruz.

Atamaları tam anlamadım :S
 
Anlamadığım yer burası.

1. BUTTON* neyi ifade ediyor. b nerden geldi.
2. &buttons derken neden başa & yazıyoruz.

BUTTON* demek, BUTON tipinde bir pointer demek. Yani BUTTON tipinde bir veri yapısının adresini tutar. & ile de bir verinin adresini alırsın
 
Kendimce en az karmaşa ile kodu istediğim hale getirdim.

Son durum şöyle;

C++:
// Global değişkenler.
int zaman        = 0;
byte durum        = 0;
byte aktif_btn    = 0;


void loop()
{

        // 1. Buton a basılıyor ise durumu nedir?
        if (buton_oku(BUTTON_1,1) and aktif_btn == 1)
        {
            Serial.print("Buton 1 Durumu : ");Serial.println(durum);
        }

        // 2. Buton a basılıyor ise durumu nedir?
        if (buton_oku(BUTTON_2,2) and aktif_btn == 2)
        {
            Serial.print("Buton 2 Durumu : ");Serial.println(durum);
        }

}



// Buton okuma fonksiyonu.
byte buton_oku(bool buton, byte hangi_buton )
{

  // Hangi butona basıldığını tespit ediyoruz.
  if (buton == HIGH)
  {
        aktif_btn = hangi_buton;
  }

  // İlgili buton ile işlem için ek şart koyuyoruz
  if (buton == LOW and aktif_btn == hangi_buton)
  {
    zaman=0;
    durum=0;
  }

  // İlgili buton ile işlem için ek şart koyuyoruz
  if (buton == HIGH and aktif_btn == hangi_buton)
  {
        aktif_btn = hangi_buton;
        delay(1);
        zaman++;
       
        if (zaman < 50)           // 50ms  Debounce süresi boyunca birşey yapma
        {
          durum=0;
        }
        else if (zaman < 1000)       // butona basılıyor. 1. Fonksiyon (normal işlem)
        {
          durum=1;
        }  
        else if (zaman >1000)       // butona basılıyor. 2. Fonksiyon (hızlı işlem)
        {
          durum=2;
        }

  }
  return durum;
}
 

Forum istatistikleri

Konular
5,788
Mesajlar
99,006
Üyeler
2,464
Son üye
s4met

Son kaynaklar

Son profil mesajları

cemalettin keçeci wrote on HaydarBaris's profile.
barış kardeşim bende bu sene akıllı denizaltı projesine girdim ve sensörleri arastırıyorum tam olarak hangi sensör ve markaları kullandınız yardımcı olabilir misin?
m.white wrote on Altair's profile.
İyi akşamlar.Arabanız ne marka ve sorunu nedir.Ben araba tamircisi değilim ama tamirden anlarım.
* En mühim ve feyizli vazifelerimiz millî eğitim işleridir. Millî eğitim işlerinde mutlaka muzaffer olmak lâzımdır. Bir milletin hakikî kurtuluşu ancak bu suretle olur. (1922)
Kesici/Spindle hızı hesaplamak için SpreadSheet UDF'leri kullanın, hesap makinesi çok eski kalan bir yöntem :)
Dr. Bülent Başaran,
Elektrik ve Elektronik Mühendisi
Yonga Tasarım Özdevinimcisi
Üç güzel "çocuk" babası
Ortahisar/Ürgüp/Konya/Ankara/Pittsburgh/San Francisco/Atlanta/Alaçatı/Taşucu...

Back
Top