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

Makaleyi Paylaş

Arduino / Geliştirme Kartları / Yazılım

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

Merhabalar;
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.

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.

Sponsor

Şimdi 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 uygulamanın .ino dosyasına Github adresimden ulaşabilirsiniz.

Makaleyi Paylaş

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.

Cevap bırakın