Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Bir adım daha ilerledik. Her ne kadar çok turlu trimpotlar kullanılmış olsa da titreşime bağlı sorun riski devam ediyordu. Ben de ayarlamalar için trimpot yerine butonlar kullanmaya karar verdim. Butonlarla ayarlanan alt devir hassasiyeti ve tepki miktarı ise chip üzerindeki EEPROM'a yazılıyor ve oradan okunuyor. Yani elektrik gittiğinde yok olmuyor. Mekanik risk de yok. Tabii şu anki kodda en önemli özellik olan "key debounce" yok. Ona bir çözüm üreteceğim. Yine de test için yeterli bir kod. Tabii binbir hata ve sorun çıkacak ama adım adım debug edeceğiz. :D
Plaket artık böyle:

[attachimg=1]

Kodun son hali de burada:

Kod:
// Motor devrini sürekli gözleyip belirli bir değerin altına inmeye başladığında gaz verecek program

#include <EEPROM.h>

const int throttlein = 4; // Alıcıdan throttle sinyali girişi
const int ignin = 3; // Alıcıdan kill switch girişi
const int sensorin = 2; // Ateşlemeden gelen sinyal girişi

const int throttleout = 5; // Gaz servosu çıkışı
const int ignLED = 9; // Ateşleme LED göstergesi çıkışı
const int ign = 12; // Ateşleme optokuplör çıkışı

//const int steppin = 0; // Devir düştüğünde gazın ne kadar açılacağını belirleyen trimpot girişi
//const int mindevirpin = 2; // Alt devir sınırını ayarlamak için trimpot girişi
const int sensup = 15; // A01
const int sensdn = 19; // A05
const int respup = 16; // A02
const int respdn = 18; // A04

const int revpin = 6; // Gaz servosu reverse jumper girişi
const int jumper = 7; // Reverse pin jumperi için HIGH level sağlıyor

int motorstop = 0; // Motorun stop etmiş olduğunu gösteren değişken. 0 ise motor çalışıyor 1 ise stop etmiş
unsigned int mindevir;
int devir;
int ignPWM;
int rxPWM;
unsigned int thrstep = 15;

unsigned long timer;
unsigned long frame;
unsigned long timer2;
int n;
int x;
int sensupbuton = 1;
int sensdnbuton = 1;
int respupbuton = 1;
int respdnbuton = 1;
int senschanged = 0;
int respchanged = 0;



void setup()
{
  pinMode(throttleout, OUTPUT);
  pinMode(ign, OUTPUT);
  pinMode(ignLED, OUTPUT);
  pinMode(jumper, OUTPUT);
  digitalWrite(jumper, HIGH);

  pinMode(sensup, INPUT); //Sensitivite + butonu
  pinMode(sensdn, INPUT); //Sensitivite - butonu
  pinMode(respup, INPUT); //Response + butonu
  pinMode(respdn, INPUT); //Response - butonu
  digitalWrite(sensup, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(sensdn, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(respup, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(respdn, HIGH); // Pullup direnci aktive ediliyor

  ignPWM = pulseIn(ign, HIGH, 25000);
  while (ignPWM <= 1500) //Burada ateşlemenin açık komutunu bekliyoruz
  {
    ignPWM = pulseIn(ign, HIGH, 25000);
  }
  digitalWrite(ignLED, HIGH);
  digitalWrite(ign, HIGH); //Ateşlemeyi açtık
}


void loop()
{
  rxPWM = pulseIn(throttlein, HIGH, 25000);
  ignPWM = pulseIn(ignin, HIGH, 25000);
  while (ignPWM > 1500)
  {
    frame = micros();
    ignPWM = pulseIn(ignin, HIGH, 25000);
    rxPWM = pulseIn(throttlein, HIGH, 25000);
    devirhesapla();
    if (devir > 0)
    {
      mindevir = 1000 + 4 * EEPROM.read(0);
      thrstep = EEPROM.read(1) / 4;
      if (devir < mindevir)
      {
        if (digitalRead(revpin) == HIGH)
        {
          rxPWM = rxPWM + thrstep;
        }
        else
        {
          rxPWM = rxPWM - thrstep;
        }
        if (rxPWM > 2200)
        {
          rxPWM = 2200;
        }
        if (rxPWM < 800)
        {
          rxPWM = 800;
        }
        for (int i = 0; i < 50; i++)
        {
          throut();
          while ((micros() - frame) < 20000)
          {
          }
          frame = micros();
        }

        
          throut();
          while ((micros() - frame) < 20000)
          {
          }
        }
      
    }
  }
  digitalWrite(ignLED, LOW);
  digitalWrite(ign, LOW); //Ateşlemeyi kapattık
}


void devirhesapla()
{
  motorstop = 0;
  n = digitalRead(sensorin);
  timer2 = micros();

  while (motorstop == 0)
  {

    while (n == 0)
    {
      n = digitalRead(sensorin);
      if ((micros() - timer2) > 60000)
      {
        motorstop = 1;
        devir = 0;
      }
    }
    timer = micros();
    while (n > 0)
    {
      n = digitalRead(sensorin);
      if ((micros() - timer2) > 60000)
      {
        motorstop = 1;
        devir = 0;
      }
    }
    while (n == 0)
    {
      n = digitalRead(sensorin);
      if ((micros() - timer2) > 60000)
      {
        motorstop = 1;
        devir = 0;
      }
    }
  }
  if (motorstop == 0)
  {
    x = micros();
    n = x - timer;
    devir = 60000000 / n;
  }
  else
  {
    devir = 0;
  }
}


void throut()
{
  digitalWrite(throttleout, HIGH);
  timer = micros();
  while ((micros() - timer) < rxPWM)
  {
    sensupbuton = digitalRead(sensup);
    sensdnbuton = digitalRead(sensdn);
    respupbuton = digitalRead(respup);
    respdnbuton = digitalRead(respdn);
    if (sensupbuton != sensdnbuton)
    {
      if (sensupbuton == 0)
      {
        mindevir++;
        senschanged = 1;
        if (mindevir > 255)
        {
          mindevir = 255;
          senschanged = 0;
        }
        else
        {
          mindevir--;
          senschanged = 1;
          if (mindevir < 1)
          {
            mindevir = 1;
            senschanged = 0;
          }
        }

      }
    }
    if (senschanged == 1)
    {
      EEPROM.write(0, mindevir);
      senschanged = 0;
    }
    if (respupbuton != respdnbuton)
    {
      if (respupbuton == 0);
      {
        thrstep++;
        respchanged = 1;
        if (thrstep > 63)
        {
          thrstep = 63;
          respchanged = 0;
        }
        else
        {
          thrstep--;
          respchanged = 1;
          if (thrstep < 1)
          {
            thrstep = 1;
            respchanged = 0;
          }
        }
      }
    }
    if (respchanged == 1)
    {
      EEPROM.write(1, thrstep * 4);
      respchanged = 0;
    }
  }
  digitalWrite(throttleout, LOW);
}

Temel mantık yaklaşımını özetlemek istiyorum. Bu şekilde sizlerden gelecek öneri ve eleştiriler ile daha iyi bir şey yapabilirim diye umuyorum.

* İlk çalışmada butonlara pullup dirençleri üzerinden logic HIGH veriliyor. Yani butonlar aktifken LOW değeri veriyorlar.
* Engine kill kanalından gelen sinyal izlenip ignition ON yapılıyor. Burada akıllı kill switch algoritmasına henüz giremedim. O daha ileriki bir versiyonda belki...
* Ana loopta önce devir hesaplanıyor. Bunu yapmak için iki ateşleme arasındaki süreyi mikrosaniye olarak sayıyoruz. Sonra bundan devri hesaplıyoruz. Motorun stop etmiş olma olasılığına karşın bir de timeout var burada. Eğer iki ateşleme arası 60 milisaniyeden uzunsa motorun stop ettiğine karar veriyoruz.
* Loop içinde devir hesaplandıktan sonra bu, butonlarla belirlenmiş ve EEPROM'a yazılmış olan bir değerle karşılaştırılıyor. EEPROM'da toplam iki byte kullanmak istedim. 0 numaralı adreste asgari devir sınırı var. 1 numaralı adreste ise ne kadar tepki verileceği kayıtlı.
* Asgari devrin 1000 - 2000 devir arasında ayarlanmasını uygun gördüm. EEPROM'da bir byte kullanacaksak ancak 0 - 255 arası bir değerimiz olacak. Bu nedenle orada kayıtlı değeri 4 ile çarpıp 1000'e ekliyoruz.
* Aktüel motor devri ayarlanmış olan asgari devrin altında ise ne kadar gaz vereceğimizi belirleyen thrstep değişkeni EEPROM'da 1 numarada kayıtlı. Servo range'i 1000 - 2000 mikrosaniye (ya da 800 - 2200 mikrosaniye) olmalı. Burada bizim ekleyeceğimiz en fazla gaz miktarı da bence en fazla 64 mikrosaniye olmalı Bu nedenle EEPROM'daki 0 - 255 arasındaki değeri dörde bölerek kullanıyorum.
* Ana loop içinde sık sık "throut()" işlevi çağrılarak servoya çıkış sinyali gönderiliyor. Eğer devir düştü ve sistem devreye girdiyse bir saniye boyunca o konumda kalıp sonra normale dönüyor.
* "Throut()" işlevi içinde butonlar kontrol ediliyor. "Mindevir" ve "thrstep" değişkenlerinde değişiklik olursa yeni değerler EEPROM'a yazılıyor.
 

Ekli dosyalar

  • Rölanti Guard Butonlu.jpg
    Rölanti Guard Butonlu.jpg
    138.7 KB · Görülme: 127
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Kodda ilerliyoruz. Bazı düzenlemeler yapmak gerekti.
İki ayrı zaman kritik görev var. Birisi servo çıkışı. Onun hiç aksamaması lazım. O nedenle MsTimer2 kütüphanesi kullanılarak throut() işlevinin her 20 milisaniyede bir çağrılması sağlandı.
Bu işlevde üç farklı görev yerine getiriliyor:
1- Throttle servosuna güncel rxPWM değeri kadar mikrosaniyelik bir darbe gönderiliyor. Bu yaklaşık 1 ile 2 milisaniyelik bir iş.
2- Tuşlar okunuyor. Her bir tuş çiftinin sadece biri basılı ise ona göre değer değişikliği yapılıyor ve değer değişti ise EEPROM'daki değer güncelleniyor.
3- Akıllı kill switch işlevinde kullanılan ve ateşleme tuşunun daha önce kapalı konuma alınmış olduğunu kaydeden armed parametresi kontrol ediliyor. Önce armedcount bir artırılıyor. Eğer değeri 150 olduysa bu demektir ki 20 mS * 150 = 3 saniyedir armed aktif. Artık timeout olması lazım. Bu durumda armed değişkeni sıfırlanıyor. Yani ateşleme anahtarı bir kez OFF yapıldıktan sonra üç saniye içinde tekrar OFF yapılmazsa motor stop ettirilmiyor.

Ana loop içinde ise şunlar yapılıyor:
Tabii ki her döngüde ateşleme ve gaz sinyalleri okunuyor. Devirhesapla() işlevi çağrılıyor. Buradan eğer 0 geldiyse motor çalışmıyor demektir. Herhangi bir şey yapılmıyor. Gaz servo çıkışı her 20 mS'de bir otomatik sürdüğü için giriş değeri çıkış değerine eşit kalıyor. Yani biz dışarıdan herhangi bir şey hissetmiyoruz. Eğer devir hesaplandıktan sonra bizim butonlarla belirleyip EEPROM'a kaydetmiş olduğumuz devir değerinden düşük ise gaz açmamız lazım. Bunun için yine butonlarla ayarlanıp EEPROM'a kaydedilmiş thrstep değerini kullanacağız. Tabii bu iki değer de gerektiği şekilde ölçeklendiriliyor o detayı daha önce açıklamıştım. Bu aşamada rxPWM değerini güncelliyoruz. Bu da otomatik olarak gaz servosu çıkışına yansıyor. Ancak nasıl güncelleyeceğiz? Artı yönde mi eksi yönde mi? Sonuçta uçaktaki throttle geometrisi bunu belirliyor. İşte bu amaçla devrede bir reverse jumper var. Bu jumperin konumuna göre motora gaz vermek için rxPWM değeri thrstep kadar ya azaltılacak ya da artırılacak. Bu jumper devrenin uçağa montajı sırasında bir kez denenerek ayarlanıp öylece bırakılacak.
Güncellenmiş rxPWM değeri ise her 20 mS'de bir otomatik olarak gaz servosuna gönderiliyor.
Bitti mi? Hayır!
Eğer devre böyle bir durumda araya girdi ise yaklaşık 1.5 saniye boyunca bu konumu muhafaza etmesini istiyoruz. Bu da bir gecikme loop'u ile mümkün ama burada da bir ayrıntı var.
Diyelim ki son yaklaşmadayız. Rölantide geliyoruz. Devir çok düştü. Devremiz araya girip gaz açtı. Tam da o sırada pas geçmeye karar verdik ve gazı tam açtık. Birbuçuk saniye boyunca uçak gaz komutuna tepki vermeyecekti. İşte bu nedenle 1.5 saniyelik bekleme süresinde throtlle kanalını okumaya devam ediyoruz. Eğer gelen sinyal bizim güncel rxPWM değerinden farklı ise (reverse durumuna göre yüksek ya da alçak olabilir) o zaman gelen değeri servoya gönderiyoruz. Yani pas geçeceksek gazı tam açma şansımız oluyor.

Kod syntax açısından sorunsuz. Ama tabii göremediğim ne hatalar çıkacak bilmiyorum. Üzerinde çalışmaya devam edeceğim. Bir katkı gelirse de memnuniyetle değerlendireceğim.


Kod:
// Motor devrini sürekli gözleyip belirli bir değerin altına inmeye başladığında gaz verecek program

#include <EEPROM.h>
#include <MsTimer2.h>


const int throttlein = 4; // Alıcıdan throttle sinyali girişi
const int ignin = 3; // Alıcıdan kill switch girişi
const int sensorin = 2; // Ateşlemeden gelen sinyal girişi

const int throttleout = 5; // Gaz servosu çıkışı
const int ignLED = 9; // Ateşleme LED göstergesi çıkışı
const int ign = 12; // Ateşleme optokuplör çıkışı

const int sensup = 15; // A01
const int sensdn = 19; // A05
const int respup = 16; // A02
const int respdn = 18; // A04

const int revpin = 6; // Gaz servosu reverse jumper girişi
const int jumper = 7; // Reverse pin jumperi için HIGH level sağlıyor

unsigned int motorstop = 0; // Motorun stop etmiş olduğunu gösteren değişken. 0 ise motor çalışıyor 1 ise stop etmiş
unsigned int mindevir;
unsigned int devir;
unsigned int ignPWM; // Ateşleme sinyali değeri
volatile unsigned int rxPWM; // Throttle servo değeri
unsigned int rxPWM2;
unsigned int thrstep;
volatile int armed = 0; // Akıllı kill switch işlevi için kullanılacak
volatile int armedcount = 0; // Akıllı kill switch işlevi için kullanılacak

unsigned long timer;
volatile unsigned long frame; // Servo pulse oluşturmak için kullanılıyor
unsigned long timer2;

int n;
int x;

int sensupbuton = 1;
int sensdnbuton = 1;
int respupbuton = 1;
int respdnbuton = 1;
int senschanged = 0;
int respchanged = 0;


void setup()
{
  pinMode(throttleout, OUTPUT);
  pinMode(ign, OUTPUT);
  pinMode(ignLED, OUTPUT);
  pinMode(jumper, OUTPUT);
  digitalWrite(jumper, HIGH);

  pinMode(sensup, INPUT); //Sensitivite + butonu
  pinMode(sensdn, INPUT); //Sensitivite - butonu
  pinMode(respup, INPUT); //Response + butonu
  pinMode(respdn, INPUT); //Response - butonu
  digitalWrite(sensup, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(sensdn, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(respup, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(respdn, HIGH); // Pullup direnci aktive ediliyor

  rxPWM = pulseIn(throttlein, HIGH, 25000);
  MsTimer2::set(20, throut);
  MsTimer2::start();

  ignPWM = pulseIn(ign, HIGH, 25000);
  while (ignPWM <= 1500) //Burada ateşlemenin açık komutunu bekliyoruz
  {
    ignPWM = pulseIn(ign, HIGH, 25000);
  }
  digitalWrite(ignLED, HIGH);
  digitalWrite(ign, HIGH); //Ateşlemeyi açtık
}


void loop()
{
  ignPWM = pulseIn(ignin, HIGH, 25000);
  if (ignPWM > 1500)
  {
    digitalWrite(ignLED, HIGH);
    digitalWrite(ign, HIGH); //Ateşlemeyi açtık
    ignPWM = pulseIn(ignin, HIGH, 25000);

    rxPWM = pulseIn(throttlein, HIGH, 25000);
    devirhesapla();
    if (devir > 0)
    {
      mindevir = 1000 + 4 * EEPROM.read(0);
      thrstep = EEPROM.read(1) / 4;
      if (devir < mindevir)
      {
        if (digitalRead(revpin) == LOW)
        {
          rxPWM = rxPWM + thrstep;
        }
        else
        {
          rxPWM = rxPWM - thrstep;
        }
        if (rxPWM > 2200)
        {
          rxPWM = 2200;
        }
        if (rxPWM < 800)
        {
          rxPWM = 800;
        }

        timer = micros();
        while ((micros() - timer) < 1500000)
        {
          rxPWM2 = pulseIn(throttlein, HIGH, 25000);
          if ((digitalRead(revpin) == HIGH))
        {
          if (rxPWM2 < rxPWM)
            {
              rxPWM = rxPWM2;
            }
          }
          else
          {
            if (rxPWM2 > rxPWM)
            {
              rxPWM = rxPWM2;
            }
          }
        }
      }

    }
  }
  else
  {
    if (armed == 1)
    {
      digitalWrite(ignLED, LOW);
      digitalWrite(ign, LOW); //Ateşlemeyi kapattık
      armed = 0;
      armedcount = 0;
    }
    else
    {
      armed = 1;
    }
  }
}


void devirhesapla()
{
  motorstop = 0;
  n = pulseIn(sensorin, HIGH, 60000);
  if (n == 0)
  {
    motorstop = 1;
    devir = 0;
  }
  else
  {
    devir = 60000000 / n;
  }
}


void throut()
{
  digitalWrite(throttleout, HIGH);
  frame = micros();
  while ((micros() - frame) < rxPWM)
  {
  }
  digitalWrite(throttleout, LOW);
  sensupbuton = digitalRead(sensup);
  sensdnbuton = digitalRead(sensdn);
  respupbuton = digitalRead(respup);
  respdnbuton = digitalRead(respdn);

  if (armed == 1) // Burada akıllı kill switch işlevi için armed değişkeni kontrol ediliyor
  {
    armedcount++; // Eğer sistem "armed" ise armedcount bir artırılıyor
    if (armedcount > 150) // armedcount 150'yi geçince yani 3 saniye geçmiş ise armed durumu iptal ediliyor
    {
      armedcount = 0;
      armed = 0;
    }
  }
  else
  {
    armedcount = 0;
  }

  if (sensupbuton != sensdnbuton)
  {
    if (sensupbuton == 0)
    {
      mindevir++;
      senschanged = 1;
      if (mindevir > 255)
      {
        mindevir = 255;
        senschanged = 0;
      }
      else
      {
        mindevir--;
        senschanged = 1;
        if (mindevir < 1)
        {
          mindevir = 1;
          senschanged = 0;
        }
      }

    }
  }
  if (senschanged == 1)
  {
    EEPROM.write(0, mindevir);
    senschanged = 0;
  }
  if (respupbuton != respdnbuton)
  {
    if (respupbuton == 0);
    {
      thrstep++;
      respchanged = 1;
      if (thrstep > 63)
      {
        thrstep = 63;
        respchanged = 0;
      }
      else
      {
        thrstep--;
        respchanged = 1;
        if (thrstep < 1)
        {
          thrstep = 1;
          respchanged = 0;
        }
      }
    }
  }
  if (respchanged == 1)
  {
    EEPROM.write(1, thrstep * 4);
    respchanged = 0;
  }
}
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Sümer abi, ilk açlışta, EPROM'u okuyup, 0. ve 1. adresteki değerler 255 ise kırmızı bir led yakıp, çalışmayı durduran bir alt program eklemek sanki faydalı olabilir gibi geldi.
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Zafer SAHIN' Alıntı:
Sümer abi, ilk açlışta, EPROM'u okuyup, 0. ve 1. adresteki değerler 255 ise kırmızı bir led yakıp, çalışmayı durduran bir alt program eklemek sanki faydalı olabilir gibi geldi.

Tam olarak ne gibi bir faydası olacak bunun? Azıcık daha açabilir misin?
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

EEPROM değerleri 255 ise, altprogram(ya da kırmızı ışığı gören kullanıcının ta kendisi) aşağıdaki durumları varsayacak.

- 0. ve 1. adresler 255 olduğuna göre EEPROM'a hiç bir değer yazılmadı. Yani gerekli değerleri yazmak ve cihazın ilk ayarlarını yapmak gerekiyor.
- Daha önce yazılmışsa bile EEPROM'un içeriği silindi, EEPROM'un silinmesine yol açacak bir elektriksel arıza olup olmadığını kontrol edin.
- EEPPROM'a yazılamıyor, EEPROM'un sağlıklı durumda olup olmadığını, ya da butonların işlevlerini kontrol edin ...

gibi durumlar sözkonusu olabilir ...
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Zafer SAHIN' Alıntı:
EEPROM değerleri 255 ise, altprogram(ya da kırmızı ışığı gören kullanıcının ta kendisi) aşağıdakiler durumları varsayacak.

- 0. ve 1. adresler 255 olduğuna göre EEPROM'a hiç bir değer yazılmadı. Yani gerekli değerleri yazmak ve cihazın ilk ayarlarını yapmak gerekiyor.
- Daha önce yazılmışsa bile EEPROM'un içeriği silindi, EEPROM'un silinmesine yol açacak bir elektriksel arıza olup olmadığını kontrol edin.
- EEPPROM'a yazılamıyor, EEPROM'un sağlıklı durumda olup olmadığını, ya da butonların işlevlerini kontrol edin ...

gibi durumlar sözkonusu olabilir ...

Evet doğru ama...

Örneğin "mindevir" değişkenini (daha doğrusu değişkeni ürettiğimiz değeri) EEPROM'da 0 no'lu adrese yazıyoruz. Bu değişken 0 - 255 arası oluyor ve 0 ise mindevir 1000, 255 ise mindevir 2020 oluyor. Bu güvenlik değerlendirmesi için değişkeni 0 - 254 arası kısıtlamak lazım. Yapılabilir... Diğer değişkenin alacağı en yüksek değer zaten 252.
Peki...
O zaman setup() içinden çağrılan bir altprogram EEPROM testi yapsın. 0 ve 1 no'lu adreslerde 255 varsa oralara bir değer yazmayı denesin (örneğin 12:coolxf:. Sonra yazılanı kontrol etsin. Yazılan okunabiliyor ise normal akışa geri dönsün. EEPROM hatası sonucuna varırsa kırmızı LED'i yakıp söndürsün ve programı kilitlesin. Ya da bir flag set etsin ve ana program bu flagı gördüğünde giriş sinyalini çıkışa yazarak sadece akıllı kill switch olarak çalışsın. Yanıp sönen LED ise bir uyarı olarak devam etsin. Olur mu?
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Tanımladığım işlevi ekledim... Normalde 255 okunan bir EEPROM hücresini test etmenin en kolay yolu "0" yazmaktır diye düşündüm.

Kod:
// Motor devrini sürekli gözleyip belirli bir değerin altına inmeye başladığında gaz verecek program

#include <EEPROM.h>
#include <MsTimer2.h>


const int throttlein = 4; // Alıcıdan throttle sinyali girişi
const int ignin = 3; // Alıcıdan kill switch girişi
const int sensorin = 2; // Ateşlemeden gelen sinyal girişi

const int throttleout = 5; // Gaz servosu çıkışı
const int ignLED = 9; // Ateşleme LED göstergesi çıkışı
const int ign = 12; // Ateşleme optokuplör çıkışı
const int errorled = 13; // Hata için plaketteki LED kullanılıyor

const int sensup = 15; // A01
const int sensdn = 19; // A05
const int respup = 16; // A02
const int respdn = 18; // A04

const int revpin = 6; // Gaz servosu reverse jumper girişi
const int jumper = 7; // Reverse pin jumperi için HIGH level sağlıyor

unsigned int motorstop = 0; // Motorun stop etmiş olduğunu gösteren değişken. 0 ise motor çalışıyor 1 ise stop etmiş
unsigned int mindevir;
unsigned int devir;
unsigned int ignPWM; // Ateşleme sinyali değeri
volatile unsigned int rxPWM; // Throttle servo değeri
unsigned int rxPWM2;
unsigned int thrstep;
volatile int armed = 0; // Akıllı kill switch işlevi için kullanılacak
volatile int armedcount = 0; // Akıllı kill switch işlevi için kullanılacak

unsigned long timer;
volatile unsigned long frame; // Servo pulse oluşturmak için kullanılıyor
unsigned long timer2;
int flag = 0;

int n;
int x;

int sensupbuton = 1;
int sensdnbuton = 1;
int respupbuton = 1;
int respdnbuton = 1;
int senschanged = 0;
int respchanged = 0;


void setup()
{
  pinMode(throttleout, OUTPUT);
  pinMode(ign, OUTPUT);
  pinMode(ignLED, OUTPUT);
  pinMode(jumper, OUTPUT);
  digitalWrite(jumper, HIGH);
  pinMode(errorled, OUTPUT);

  pinMode(sensup, INPUT); //Sensitivite + butonu
  pinMode(sensdn, INPUT); //Sensitivite - butonu
  pinMode(respup, INPUT); //Response + butonu
  pinMode(respdn, INPUT); //Response - butonu
  digitalWrite(sensup, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(sensdn, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(respup, HIGH); // Pullup direnci aktive ediliyor
  digitalWrite(respdn, HIGH); // Pullup direnci aktive ediliyor

  rxPWM = pulseIn(throttlein, HIGH, 25000);
  MsTimer2::set(20, throut);
  MsTimer2::start();
  eepromcheck();
  ignPWM = pulseIn(ign, HIGH, 25000);
  while (ignPWM <= 1500) //Burada ateşlemenin açık komutunu bekliyoruz
  {
    ignPWM = pulseIn(ign, HIGH, 25000);
  }
  digitalWrite(ignLED, HIGH);
  digitalWrite(ign, HIGH); //Ateşlemeyi açtık
}


void loop()
{
  ignPWM = pulseIn(ignin, HIGH, 25000);
  if (ignPWM > 1500)
  {
    digitalWrite(ignLED, HIGH);
    digitalWrite(ign, HIGH); //Ateşlemeyi açtık

    ignPWM = pulseIn(ignin, HIGH, 25000);

    rxPWM = pulseIn(throttlein, HIGH, 25000);

    digitalWrite(errorled, flag);

    if (flag == 0);
    {
      devirhesapla();
      if (devir > 0)
      {
        mindevir = 1000 + 4 * EEPROM.read(0);
        thrstep = EEPROM.read(1) / 4;
        if (devir < mindevir)
        {
          if (digitalRead(revpin) == LOW)
          {
            rxPWM = rxPWM + thrstep;
          }
          else
          {
            rxPWM = rxPWM - thrstep;
          }
          if (rxPWM > 2200)
          {
            rxPWM = 2200;
          }
          if (rxPWM < 800)
          {
            rxPWM = 800;
          }

          timer = micros();
          while ((micros() - timer) < 1500000)
          {
            rxPWM2 = pulseIn(throttlein, HIGH, 25000);
            if ((digitalRead(revpin) == HIGH))
            {
              if (rxPWM2 < rxPWM)
              {
                rxPWM = rxPWM2;
              }
            }
            else
            {
              if (rxPWM2 > rxPWM)
              {
                rxPWM = rxPWM2;
              }
            }
          }
        }

      }
    }
  }
  else
  {
    if (armed == 1)
    {
      digitalWrite(ignLED, LOW);
      digitalWrite(ign, LOW); //Ateşlemeyi kapattık
      armed = 0;
      armedcount = 0;
    }
    else
    {
      armed = 1;
    }
  }
}


void devirhesapla()
{
  motorstop = 0;
  n = pulseIn(sensorin, HIGH, 60000);
  if (n == 0)
  {
    motorstop = 1;
    devir = 0;
  }
  else
  {
    devir = 60000000 / n;
  }
}


void throut()
{
  digitalWrite(throttleout, HIGH);
  frame = micros();
  while ((micros() - frame) < rxPWM)
  {
  }
  digitalWrite(throttleout, LOW);
  sensupbuton = digitalRead(sensup);
  sensdnbuton = digitalRead(sensdn);
  respupbuton = digitalRead(respup);
  respdnbuton = digitalRead(respdn);

  if (armed == 1) // Burada akıllı kill switch işlevi için armed değişkeni kontrol ediliyor
  {
    armedcount++; // Eğer sistem "armed" ise armedcount bir artırılıyor
    if (armedcount > 150) // armedcount 150'yi geçince yani 3 saniye geçmiş ise armed durumu iptal ediliyor
    {
      armedcount = 0;
      armed = 0;
    }
  }
  else
  {
    armedcount = 0;
  }

  if (sensupbuton != sensdnbuton)
  {
    if (sensupbuton == 0)
    {
      mindevir++;
      senschanged = 1;
      if (mindevir > 255)
      {
        mindevir = 255;
        senschanged = 0;
      }
      else
      {
        mindevir--;
        senschanged = 1;
        if (mindevir < 1)
        {
          mindevir = 1;
          senschanged = 0;
        }
      }

    }
  }
  if (senschanged == 1)
  {
    EEPROM.write(0, mindevir);
    senschanged = 0;
  }
  if (respupbuton != respdnbuton)
  {
    if (respupbuton == 0);
    {
      thrstep++;
      respchanged = 1;
      if (thrstep > 63)
      {
        thrstep = 63;
        respchanged = 0;
      }
      else
      {
        thrstep--;
        respchanged = 1;
        if (thrstep < 1)
        {
          thrstep = 1;
          respchanged = 0;
        }
      }
    }
  }
  if (respchanged == 1)
  {
    EEPROM.write(1, thrstep * 4);
    respchanged = 0;
  }
}

void eepromcheck()
{
  x = EEPROM.read(0);
  if (x == 255)
  {
    EEPROM.write(0, 0);
    x = EEPROM.read(0);
    if (x != 0)
    {
      flag = 1;
    }
    x = EEPROM.read(1);
    if (x == 255)
    {
      EEPROM.write(1, 0);
      x = EEPROM.read(1);
      if (x != 0)
      {
        flag = 1;
      }
    }
  }
}
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Sümer abi, adresleri sıra ile değil de aynı anda 255'mi diye değerlendirsen, olur mu ?
Kod:
void eepromcheck() {
    int x = EEPROM.read(0) + EEPROM.read(1); // 0. ve 1. adresler 255 ise, yani yazılmamış gözüküyorsa toplamları 510 olacaktır
    if ((x == 510) {                         // Eger EEPROM yazılmamış pozisyonda ise hata kontrolü başlat.
        EEPROM.write(0, 0);                  // 0. adresi test et, yazamıyorsan, hata vardır, flagı set et.
        x = EEPROM.read(0);
        if (x != 0) {
            flag = 1;
        }
        EEPROM.write(1, 0);                  // 1. adresi test et, yazamıyorsan, hata vardır, flagı set et.
        x = EEPROM.read(1);
        if (x != 0) {
            flag = 1;
        }
    }
}

Bir de bu cihazın yüzbin defa açılıp kapatılma durumu nedir ?

- Haftada bir uçuş günü.
- Her uçuş gününde 3 uçuş.
- Her uçuşta cihazı 3 defa açıp kapattığımızı varsayarsak.
- (100000 / 9) / 54 ~= 200 yıl boyunca EEPROM bozulana kadar kullanılabilir :D.
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Valla o şekilde de güzel olmuş Zafer'ciğim. Bu şık çözümü kullanmayı tercih edeceğim. :)
Bu arada, hesabın hatalı bence. :p Çünkü butonlarla yapılacak ayarlamada her butona basışta bir write cycle olacağı için chip ömrü kısalacak. Bence 20 senede falan biter ömrü. :) Dur dur... Bi saniye. EEPROM bozuk değil ise ve herhangi bir ayar da yapılmazsa EEPROM yazma döngüsü olmuyor hiç. Okumayla da doluyor mu bu meretin ömrü?
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

En fazla iki üç defa ayar yapılacağını, dolayısı ile butonlarla yapılan işlemin çok da ömre etkilemeyeceğini düşündüm. Ama errorcheck'de tamamen yanlış bir şekilde, her seferinde yazma testi yapılacağını varsayarak ömrü hesapladım :). Okuma kısmı ise ömrü çok etkilemiyor....
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Zafer SAHIN' Alıntı:
En fazla iki üç defa ayar yapılacağını, dolayısı ile butonlarla yapılan işlemin çok da ömre etkilemeyeceğini düşündüm. Ama errorcheck'de tamamen yanlış bir şekilde, her seferinde yazma testi yapılacağını varsayarak ömrü hesapladım :). Okuma kısmı ise ömrü çok etkilemiyor....

Errorcheck'de ancak ikisi de 255 ise yazma yapılıyor. Aaa bir dakika. İkisinin toplamını kontrol ediyoruz ya. Bir hücre bozuk diğeri sağlamsa o şekilde bunu farkedemeyiz ki. Bence yine tek tek okumak lazım.

Henüz çözemediğim sorun şu: Tuşları saniyede elli kez tarıyoruz. Tuşa bir kez basıldığında saniede elli adım ilerleyecek. Şimdi oturup bunu halletmem lazım. Yoksa bir tuşa bir saniye bastığımda EEPROM'a elli kez yazma işlemi yapılacak. 100000 / 50 = 2000!!! Ömür epey bir kısalıyor...
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Sümer abi kodunu okudukça kafam karışıyor :). Niye buton pinleri olarak analog pinleri kullandığını anlamadım. Sayısal pinlerde var ama analog pinlerde konfigüre edilebilir pullup direnci olup olmadığından da çok emin değilim. Hatta analog pinlerde pinmode komutunun işlevi olduğunu da sanmıyorum.



"quick'n dirty" button çözümü.

Kod:
void loop() {
    buttonVal = digitalRead(buttonPin); // Dugmeye basili olup olmadigini oku
    if (buttonVal == 1) {
        delay(200); // 200 milisaniye beklenerek, dugme degerinin araliksiz olarak degismesi ya da gönderilmesi engellenir.
    }
    birseyleryap(buttonVal);
}
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Plakette fiziksel olarak en uygun pinler analog pinlerdi. Pullup konusunu araştırırım. Gerekirse dışarıdan direnç kullanırım. Verdiğin örnek koda gelince... Her 20 milisaniyede bir çağrılacak alt programda delay(200) pek uygun olmaz. :)
 
Yeni proje: Motor rölanti devri emniyeti ve kill switch kombinasyonu

Sümer Yamaner' Alıntı:
Plakette fiziksel olarak en uygun pinler analog pinlerdi. Pullup konusunu araştırırım. Gerekirse dışarıdan direnç kullanırım. Verdiğin örnek koda gelince... Her 20 milisaniyede bir çağrılacak alt programda delay(200) pek uygun olmaz. :)

Düğme ile ayar yapmak devamlı kullanılacak bir özellik değil. Kartın ömrü hayatında belki de 20 - 30 defa kullanılacak düğmenin, kodu 200ms bekletmesi kabul edilebilir gibi geldi bana. Tabii delay yerine timer kullanılarak "quick&dirty" yerine "dirty" hale getirilebilir. "dirty" kısmını temizlemeyi henüz düşünmedim :).

Sümer Yamaner' Alıntı:
Varmış. :)

Analog pinleri okumayı çok ihmal etmişim ...