Yazılım

Arduino ile Multithreading Zamanlı Röle Kontrolü (arduino millis)

Bu yazımda Arduino kullanarak 3 farklı röleyi 3 farklı butona basıldığı anda belirli bir zaman çalıştırıp daha sonra kapatacak bir uygulama yapacağız, fakat bu işlemleri aynı anda yapabilmesini sağlamak için de millis() fonksiyonunu kullanacağız. Kısacası Arduino millis nedir yazımızda 🙂

Arduino milis

Not: Gelen tepkiler nedeniyle bu uyarıyı yazmam gerekti, başlıkta multithreading yazdığım için Arduino ile multithread yapılamayacağı konusunda tepkiler vardı, evet bunun zaten mümkün olmadığını bildiğim için ve zaten bu yüzden Arduino ile nasıl birden çok işi yaptırabilirizi açıklayan bir yazıyı yazmam gerekti, multithread burada sadece birden çok işi aynı anda yapmak için kullanılan genel bir ifade olması nedeniyle kullanıldı, aksini yani çok çekirdekli işlemciler ve işletim sistemi gereksinimlerini iddia etmek zaten büyük hata olacaktır. Ayrıca zaten bu özelliklerde bir cihaz olmadığı için de aynı anda birden çok işlemi gerçekten yapamaz sadece yapıyormuş gibi görünür, bizim algılayabileceğimizden daha hızlı bir işlem hızıyla sırayla isteklerimizi yapar.

Arduino‘da örneğin bir röleyi açıp 1 dk. sonra kapatmak istediğimiz de eğer 1 dk. beklemek için delay kullanırsak bu artık bu süre bitene kadar başka hiç bir işlem yapamayacağımız anlamına geliyor, fakat biz 1. butona basıp röleyi çektikten sonra süresi bitmeden başka bir cihazı çalıştırmak için başka bir butona ile başka bir röleyi daha çektirmek isteyebiliriz, delay bunu imkansız kılar fakat millis kullandığımız da artık istediğimiz işlemi yapabilir oluruz.

Millis fonksiyonu aslında Arduino‘nun çalışma süresini milisaniye olarak tutar, Arduino çalışmaya başladığı anda zamanı tutmaya başlar ve fonksiyonu çağırdığımız da bize kaç milisaniye süresince çalıştığını döndürür.

Arduino millis

Şimdi Arduino milis kodumuzu yazmaya başlayalım, örnek senaryomuz da 3 rölemiz mevcut ve bunları kontrol edeceğimiz 3 adet butonumuz var, butonlarımız push buton.

Değişkenlerimiz;

Öncelikle Rölelerimizi kontrol edeceğimiz pinleri tanımlıyoruz;

const int RELAY1 = 12;
const int RELAY2 = 11;
const int RELAY3 = 10;

Aynı şekilde butonlarımızı Arduino‘da taktığımız pinleri tanımlıyoruz;

const int BUTTON1 = 2;
const int BUTTON2 = 3;
const int BUTTON3 = 4;

Butonlarımızın son durumu ve şimdi ki durumlarını tutacağımız değişkenleri tanımıyoruz, ayrıca röle durumlarını tutacağımız değişkenlerimizide her röle için tanımlıyoruz.

boolean lastButton1 = LOW;
boolean currentButton1 = LOW;
boolean relayOn1 = true;
boolean lastButton2 = LOW;
boolean currentButton2 = LOW;
boolean relayOn2 = true;
boolean lastButton3 = LOW;
boolean currentButton3 = LOW;
boolean relayOn3 = true;

Başlangıç durumu, çalışma durumu ve anlık çalışma süresini (yani butona basıldığı andan itibaren millis’den alacağımız değerleri) tutacağımız değişkenleri tanımlıyoruz,

boolean b1Start = false;
int b1Stage = -1;
unsigned long b1P1WorkingMillis = 0;


boolean b2Start = false;
int b2Stage = -1;
unsigned long b2P1WorkingMillis = 0;


boolean b3Start = false;
int b3Stage = -1;
unsigned long b3P1WorkingMillis = 0;

Butona basıldığında rölelerimizin ne kadar süre çekileceğini tutacak değişkenimizi tanımlıyoruz. Değer milisaniye olacaktır, ben 3000 olarak tanımladım, 3 saniye boyunca rölemiz çekili kalacak.

const long p1WorkingInterval = 3000;

Şimdi void setup() fonksiyonuna butonlarımızı input, röle pinlerimizide output olduğunu belirtiyoruz, ayrıca röle çıkışlarını başlangıç durumlarını ayarlıyoruz.

void setup(){
  Serial.begin(9600); // See the connection status in Serial Monitor
  pinMode(RELAY1, OUTPUT);
  pinMode(BUTTON1, INPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(BUTTON2, INPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(BUTTON3, INPUT);

  digitalWrite(RELAY1, true);
  digitalWrite(RELAY2, true);
  digitalWrite(RELAY3, true);
}

Buton durumlarımızı takip edip değiştiren fonksiyonlarımızı ekliyoruz;

boolean debounce1(boolean last1) {
  boolean current1 = digitalRead(BUTTON1);
  if(last1 != current1) {
    delay(5);
    current1 = digitalRead(BUTTON1);
  }
  return current1;
}
boolean debounce2(boolean last2) {
  boolean current2 = digitalRead(BUTTON2);
  if(last2 != current2) {
    delay(5);
    current2 = digitalRead(BUTTON2);
  }
  return current2;
}
boolean debounce3(boolean last3) {
  boolean current3 = digitalRead(BUTTON3);
  if(last3 != current3) {
    delay(5);
    current3 = digitalRead(BUTTON3);
  }
  return current3;
}

voip loop() fonksiyonumuzun içeriğine geçmeden önce butonlara basıldıktan sonra yapılacak işlemler için gerekli fonksiyonları yazacağız.

Fonksiyon içeriğini inceleyecek olursak nowMillis tanımlıyoruz bu millis() fonksiyonunun o anki değerini tutacağımız ve çalışma değerimize geldiğinde röleyi durdurmamızda kontrol edeceğimiz değişkendir.

Butona basıldığını anladığımız anda buton stage değiştiyor ve çalışma süresince röleyi çektikten sonra yine statüleri değiştirerek röleyi kapatıyoruz.

Bu işlemler esnasında da seri porta röle çekildi ve röle kapandı şeklinde yazdırıyoruz.

void B1Function()
{
  unsigned long nowMillis = 0;
  
  currentButton1 = debounce1(lastButton1);
  if(lastButton1 == LOW && currentButton1 == HIGH) {
    if (!b1Start)
    {
      b1Start = true;
      b1Stage = 0;
    }
  }
  lastButton1 = currentButton1;
  
  if (b1Start)
  {
    switch (b1Stage)
    {
      case 0:
        b1Stage = 1;
        digitalWrite(RELAY1, false);
        Serial.println("1.Röle Çekildi");
        b1P1WorkingMillis = millis();
        break;
      case 1:
        nowMillis = millis();
        if (nowMillis - b1P1WorkingMillis >= p1WorkingInterval)
        {
          b1Stage = -1;
          b1Start = false;
          Serial.println("1. Röle Kapandı!");
          digitalWrite(RELAY1, true);
        }
  
    }  
  }
}

void B2Function()
{
  unsigned long nowMillis = 0; 
  currentButton2 = debounce2(lastButton2);
  if(lastButton2 == LOW && currentButton2 == HIGH) {
    if (!b2Start)
    {
      b2Start = true;
      b2Stage = 0;
    }
  }
  lastButton2 = currentButton2;
  
  if (b2Start)
  {
    switch (b2Stage)
    {
      case 0:
        b2Stage = 1;
        digitalWrite(RELAY2, false);
        Serial.println("2. Röle Çekildi");
        b2P1WorkingMillis = millis();
        break;
      case 1:
        nowMillis = millis();
        if (nowMillis - b2P1WorkingMillis >= p1WorkingInterval)
        {
          b2Stage = -1;
          b2Start = false;
          Serial.println("2. Röle Kapandı!");
          digitalWrite(RELAY2, true);
        }
    }  
  }
}


void B3Function()
{
  unsigned long nowMillis = 0; 
  currentButton3 = debounce3(lastButton3);
  if(lastButton3 == LOW && currentButton3 == HIGH) {
    if (!b3Start)
    {
      b3Start = true;
      b3Stage = 0;
    }
  }
  lastButton3 = currentButton3;
  
  if (b3Start)
  {
    switch (b3Stage)
    {
      case 0:
        b3Stage = 1;
        digitalWrite(RELAY3, false);
        Serial.println("3. Röle Çekildi");
        b3P1WorkingMillis = millis();
        break;
      case 1:
        nowMillis = millis();
        if (nowMillis - b3P1WorkingMillis >= p1WorkingInterval)
        {
          b3Stage = -1;
          b3Start = false;
          Serial.println("3. Röle Kapandı!");
          digitalWrite(RELAY3, true);
        }
    }  
  }
}

Son olarak da, voip loop() fonksiyonumuz içerisine bu 3 buton için yazdığımız fonksiyonları çağırıyoruz, böylece loop içerisinde devamlı olarak buton basılmış mı diyerek kontrol ediyor ve basıldığı anda fonksiyon içerisindeki işlemleri yaptırıyoruz.

void loop()
 {
   B1Function();
   B2Function();
   B3Function();
 }

Kodlarımız en son aşağıdaki gibi görünecektir.

const int RELAY1 = 12;
const int RELAY2 = 11;
const int RELAY3 = 10;

const int BUTTON1 = 2;
const int BUTTON2 = 3;
const int BUTTON3 = 4;

boolean lastButton1 = LOW;
boolean currentButton1 = LOW;
boolean relayOn1 = true;
boolean lastButton2 = LOW;
boolean currentButton2 = LOW;
boolean relayOn2 = true;
boolean lastButton3 = LOW;
boolean currentButton3 = LOW;
boolean relayOn3 = true;

boolean b1Start = false;
int b1Stage = -1;
unsigned long b1P1WorkingMillis = 0;


boolean b2Start = false;
int b2Stage = -1;
unsigned long b2P1WorkingMillis = 0;


boolean b3Start = false;
int b3Stage = -1;
unsigned long b3P1WorkingMillis = 0;

const long p1WorkingInterval = 3000;


void setup(){
  Serial.begin(9600); // See the connection status in Serial Monitor
  pinMode(RELAY1, OUTPUT);
  pinMode(BUTTON1, INPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(BUTTON2, INPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(BUTTON3, INPUT);

  digitalWrite(RELAY1, true);
  digitalWrite(RELAY2, true);
  digitalWrite(RELAY3, true);
}

boolean debounce1(boolean last1) {
  boolean current1 = digitalRead(BUTTON1);
  if(last1 != current1) {
    delay(5);
    current1 = digitalRead(BUTTON1);
  }
  return current1;
}
boolean debounce2(boolean last2) {
  boolean current2 = digitalRead(BUTTON2);
  if(last2 != current2) {
    delay(5);
    current2 = digitalRead(BUTTON2);
  }
  return current2;
}
boolean debounce3(boolean last3) {
  boolean current3 = digitalRead(BUTTON3);
  if(last3 != current3) {
    delay(5);
    current3 = digitalRead(BUTTON3);
  }
  return current3;
}

void loop()
{
  B1Function();
  B2Function();
  B3Function();
}

void B1Function()
{
  unsigned long nowMillis = 0;
  
  currentButton1 = debounce1(lastButton1);
  if(lastButton1 == LOW && currentButton1 == HIGH) {
    if (!b1Start)
    {
      b1Start = true;
      b1Stage = 0;
    }
  }
  lastButton1 = currentButton1;
  
  if (b1Start)
  {
    switch (b1Stage)
    {
      case 0:
        b1Stage = 1;
        digitalWrite(RELAY1, false);
        Serial.println("1.Röle Çekildi");
        b1P1WorkingMillis = millis();
        break;
      case 1:
        nowMillis = millis();
        if (nowMillis - b1P1WorkingMillis >= p1WorkingInterval)
        {
          b1Stage = -1;
          b1Start = false;
          Serial.println("1. Röle Kapandı!");
          digitalWrite(RELAY1, true);
        }
  
    }  
  }
}

void B2Function()
{
  unsigned long nowMillis = 0; 
  currentButton2 = debounce2(lastButton2);
  if(lastButton2 == LOW && currentButton2 == HIGH) {
    if (!b2Start)
    {
      b2Start = true;
      b2Stage = 0;
    }
  }
  lastButton2 = currentButton2;
  
  if (b2Start)
  {
    switch (b2Stage)
    {
      case 0:
        b2Stage = 1;
        digitalWrite(RELAY2, false);
        Serial.println("2. Röle Çekildi");
        b2P1WorkingMillis = millis();
        break;
      case 1:
        nowMillis = millis();
        if (nowMillis - b2P1WorkingMillis >= p1WorkingInterval)
        {
          b2Stage = -1;
          b2Start = false;
          Serial.println("2. Röle Kapandı!");
          digitalWrite(RELAY2, true);
        }
    }  
  }
}


void B3Function()
{
  unsigned long nowMillis = 0; 
  currentButton3 = debounce3(lastButton3);
  if(lastButton3 == LOW && currentButton3 == HIGH) {
    if (!b3Start)
    {
      b3Start = true;
      b3Stage = 0;
    }
  }
  lastButton3 = currentButton3;
  
  if (b3Start)
  {
    switch (b3Stage)
    {
      case 0:
        b3Stage = 1;
        digitalWrite(RELAY3, false);
        Serial.println("3. Röle Çekildi");
        b3P1WorkingMillis = millis();
        break;
      case 1:
        nowMillis = millis();
        if (nowMillis - b3P1WorkingMillis >= p1WorkingInterval)
        {
          b3Stage = -1;
          b3Start = false;
          Serial.println("3. Röle Kapandı!");
          digitalWrite(RELAY3, true);
        }
    }  
  }
}

Buradaki Arduino milis uygulamasının .ino dosyasına Github adresimden ulaşabilirsiniz.

Ali UYSAL

IT alanında 16 sene önce donanım ile başlayan tecrübem, network ve sonrasında iş analizi, yazılım geliştirme ve proje yöneticiliği alanlarında devam etmiştir. Endüstriyel yazılımlar, sahadan veri toplama ve analizleri, otomatik etiketleme ve barkod sistemleri, otomatik tartım ve robotik konularında tecrübe sahibiyim. Sanayi 4.0 kapsamında imalat sanayinin dijital dönüşümünde çok fazla projenin hayata geçmesini sağladım.Open Source projelerle uzun süre ilgilendim, analiz ve implementasyonu konularında tecrübe edindim. Bunlar dışında hobi amacıyla başlasam da sonradan ürüne dönüşen, geliştirme kartları ile farklı çalışmalarım olmuştur.Raspberry Pi üzerinde yaptığım donanımsal ve yazılımsal işler ile çok farklı ürünler ortaya çıkartarak tecrübe edindim.

İlgili Makaleler

7 Yorum

  1. merhaba hocam,
    evimde kullanmak üzere uygulamanıza 4. buton eklenerek 1-2-3 röleninin sırayla 5er dk çalışması sağlanabilir mi?

    1. Merhaba;
      Sırasıyla çalışmasını istiyorsan millis kullanama gerek yok. delay kullanarak bir role çek 5 sn bekle, sonra diğer roleyi çek 5 sn bekle diyerek istediğiniz kadar ekleyebilirsiniz.

      millis 1 çalışmasını sürdürürken aynı zamanda başka bir butonda 2 veya 3. roleleri açıp kapatmak için kullanılmasını sağlıyor. delay ile bunu yapamıyorsunuz delay verilen süre boyunca programı o satırda bekletiyor ve işlem yapmanızı engelliyor.

      1. merhaba.
        herhangi bir sensörün HIGH olduğu zaman iki ledin yakmasını istiyorum.
        birinci ledin sensörle yanıp akabinde sönsün ama ikici ledin 10 saniye sonra yanıp sönmesini istiyorum.
        nasıl yapabilirim?

  2. aslında senaryo tam olarak şöyle hocam,
    1. butona basılırsa 5 dk’lık timer çalışacak. 5 dk dolmadan 1. butona tekrar basılırsa timer duracak.
    2. ve 3. butona basılırsa da aynı süreçler oluşacak
    fakat şöyle bir kısıtımız var. eğer bir buton timeri çalışırken başka bir butona basılırsa ilgili butonun timer i duracak ve basılan devreye girecek.
    4. butona basılırsa da sırayla 5er dk çalışacak. çok uzun zamandır bunu yapmaya çalışıyorum fakat algoritmayı bir türlü programa entegre edemedim

  3. break komutlarını inceleyin bence kesmeler le bu dediinizi kolayca yapabilirsiniz

  4. BURADA 1. BUTONA BAsILDIGINDA 1. RÖLE 1 sN CEKMEsİNİ VE 5 sN BEKLEMEsİNİ İTİYORUM 2. BUTONA BAsILDIGINDA 2. RÖLEYİ 2. sN CEKMEsİNİ VE 8 sN BEKLEMEsİNİ İsTİYORUM NAsIL BİR KOD YAZABİLİRİM
    teekkurler

  5. Üstad selamlar kolay gelsin.
    Öncelikle zihninize emeğinize sağlık.
    Nette led yak söndür dışındaki nadir paylaşımınız için Teşekkür ederim.
    Arduino ya modül olmayan basit bir mikrofon takıp, üflediğimizde ledlerin sönmesini saglayacak bir kodlama yapmaya çalışıyorum.
    Doğum günlerinde kullanılabilecek hazır kalıp 9 mumluk şamdan tarzı zarif bir malzeme var elimde.
    Buna mum efektli ledler hazırladım.
    Tepelerine şeffaf silikondan mum alev motiflerini hazırladım.
    Yapmak istediğim;
    En tepedeki gizli bir noktaya bu mikrofonu entegre edip, kişi normal mumu üfler gibi üflediğinde, mikrofonun sesi algılayıp ledlerin enerjisini kesmesi.
    Yaklaşık iki dakika civarı millis kod sayesindede kapalı vaziyette tutması.
    Lakin happy birthday diye herkes bir ağızdan bağıracağından mikrofonun bu sesleride aç kapa şeklinde komutlandıracak olduğundan mütevellit istediğim gibi çalışmayacak oluşu…
    Delay ı kullanmama gerekçeme gelecek olursakta;
    Bir adet minik hoparlör bağlayıp happy birthday melodilerini arduino ya yükleyip oynatacak olmam.
    Mikrofonla ilgili nasıl bir yol izlemeliyimki bu sorunu aşabileyim?

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Başa dön tuşu