DIY Devir Sayaci

gumush

Uye
Katılım
13 Şub 2014
Mesajlar
183
Tepkime puanı
111
Yaş
47
Bir cok amacla kullanilabilecek bir hall effect sensor uygulamasindan bahsetmek istiyorum. Sensorumuz hall effect sensor US1881 , sensore miknatis yaklastiginda devreyi aciyor bu sekilde donen cisim uzerine takilacak ufak bir miknatis ile devir saymak mumkun olabiliyor.

Modelcilikte kullanimi daha kisitli olabilir , pervane vs uzerine miknatis yerlestirmek balans sorunlarina neden olabileceginden genelde IR olan modelleri kullaniliyor.

Temel uygulama 5V ile Signal arasina 10k'lik bir direnc koyuyoruz. Signal pinini 2.digital pine bagliyoruz. Sensor 3.5-24V araliginda calisabiliyor. Biz arduino'nun 5v cikisina bagliyoruz.Devre oldukca basit.

Eger iki miknatis kullaniyorsak her sinyal yarim tur olacaktir.

Kod:
volatile byte yarimtur;

 unsigned int tur;

 unsigned long zaman;


 void setup()
 {
   Serial.begin(9600);
   attachInterrupt(0, tursay, RISING);
   yarimtur = 0;
   tur = 0;
   zaman = 0;

 }

 void loop()
 {
   if (yarimtur >= 20) { 
     tur = 30*1000/(millis() - zaman)*yarimtur;
     zaman = millis();
     yarimtur = 0;
Serial.print("Devir =");     Serial.println(tur,DEC);
   }
 }

 void tursay()
 {
   yarimtur++;
 }

seklinde yapiyoruz. Oldukca kisa ve basit bir uygulama.
 
Sistemi biraz gelistireyim istedim ama algoritma kisminda biraz takildim.

Ikinci hall effect sensoru eklemek istiyorum. Bu durumda bir sorun ortaya cikiyor. Interrupt ile kesme geldiginde digerinin milis saymasi calismiyor olacak , birde o if dongusune girdiginde cikana kadarki surede digerini isleyemeyecek.

Ben hesaplama icin 20tur donmesi sonrasinda hesaplamayi guncellemistim.

Bu durumda 20tur yerine 1sn olarak ayarlar isem bu sure icinde rahatlikla iki sensoru okuyabilirim diye dusunuyorum. Denemeye zamanim olmadi.
 
DIY Devir Sayaci

İki ayrı devir mi ölçmek istiyorsun? Eğer öyle ise belki bir tanesini tam oturtup sonra ikinciyi eklemeye çalışmak uygun olur gibime geldi. Ben aynı işi biraz tersten yapıyorum şu sıra. Aynen sendeki gibi 2 No'lu digital bacağa giriş yapıyorum. Bu arada ekstra pullup direnci gerekmiyor biliyorsun. pinMode(2, INPUT_PULLUP) komutu o işi zaten yapıyor.
int.0 kullanıyorum ve FALLING (RISING de olur aslında herhangi bir fark olmaz) seçeneğini seçiyorum. İki tane timer (volatile unsigned long x1, volatile unsigned long x2) değişkenim var. Her interrupt geldiğinde x2 = x1, ve x1 = micros() (belki millis() de kullanılabilir ama micros() bana hep daha çekici geliyor) yapıp geri dönüyorum.
Ana loop içinde x1 ile x2'yi interruptları kapatıp y1 ve y2'ye kopyalıyorum. Burası önemli, çünkü long integer kullanıyoruz. Dört byte yer tutuyorlar. Biz birini okurken bir interrupt gelir de arada değer değişir ise çok saçma sapan değerler okunabiliyor.
Bütün bunlar tamamlandıktan sonra y1 ile y2'nin farkını alıyorum. Giriş sinyali için ateşlemenin hall sensörü çıkışını aldığım için her devir bir darbe demek. O zaman on, yirmi ya da daha fazla darbe saymak yerine iki darbe arasıdaki süreden dervi hesaplıyorum. Yani devir = 60000000 / (y1 - y2) oluyor.
Bunun avantajı devri daha ilk turda hesaplayabilmemiz. Dezavantajı ise ölçümün çok hassas ve asabî olması. Sürekli değişen bir değer okuyoruz çünkü. Ama onu daha sonra farklı yaklaşımlarla stabilize etmek mümkün.
Şu an uğraştığım konu ise şu: Motor durursa ne olacak? Interrupt gelmeyecek. x2 ve x2, dolayısıyla y1 ve y2 son halinde kalacak. Ben de sürekli son devri okuyor olacağım. Şu an onu çözmekle meşgulüm. :)
 
DIY Devir Sayaci

İşin algoritma kısmından önce, US1881'nin datasheet'ine biraz göz gezdireyim dedim.

10 Unique Features
The US1881 exhibits latch magnetic switching characteristics. Therefore, it requires both south and north poles to operate properly. The device behaves as a latch with symmetric operating and release switching points (BOP=|BRP|). This means magnetic fields with equivalent strength and opposite direction drive the output high and low.
Output pininin durum değiştirmesi için, miknatısın uzaklaştırılması yetmiyor. Tamamen ters kutuplanmış bir miknatısın, sensöre yaklaştırılması gerekiyor.
 
DIY Devir Sayaci

Ben tam aksini düşünüyorum. :) Algoritmayı oturtalım bir şekilde bir sensörü adapte ederiz. Optik olur, manyetik olur...
 
DIY Devir Sayaci

Sumer hocam , pullup gerekmedigini bilmiyordum ama ogrenmis oldum cok tesekkur ederim.

Zafer hocam haklisiniz , elimde birden cok hall effect sensor var devrede hangisi kaldi hatirlayamadim , 1881 latching tipinde oldugu icin bir yaklastigin aktif olup tekrar ters kutup ile duzelmesi gerekiyor. Iki miknatisim farkli oldugu icin onu cozebiliyorum. Bu kisimda sorun yok.

hmm interrupti aktarirken kapatma isine dikkat etmeliyim onun icinde tesekkur ederim.

Ancak sadece iki devir arasi ile devri bulmak hataya yada gurultuye cok acik olacaktir diye dusunuyorum. Her X gecisde bir yada her X ms'de bir bilgiyi derleyip olusturmak daha mantikli geldi bana. Sizinki gibi yapilip kayan ortalamalar ile smoothing filtreside uygulanabilir tabii.

Endustriyel bir sistem degil ise motor bir anda durmayacaktir. Mutlaka yavaslayarak duracaktir. Bu nedenle devir son kaldigi yuksek degerde kalmaz diye dusunuyorum. Her devir yerine belirli bir zaman araligi kullanmakda bu isi cozecektir. O zaman diliminde yeni gecis olmadiginda sistem 0 olarak gosterecektir. Kopyalandigi buffer alanindaki degeride her dongunun basinda sifirlar isek o zaman sorun kalmayabilir ( ama tabi arada 0 degerlerinide gorebiliriz o zaman ikinci bir buffera tasimakda mantikli olabilir boylece sorunuz sifirlama yapilabilir. )

Interruptin geldigi anda baska islem yapiyor ise onu yarim birakacaktir , anladigim kadari ile kapatma kismi bu nedenle onemli ama buradaki sorun islem uzun surerse bir devri kacirabilecegi gercegi ( sd'karta yazma , kablosuz gonderme vs ... ) , buna nasil bir cozum olabilir emin degilim.
 
DIY Devir Sayaci

Önce bir Arduino Uno kullanarak potansiyometre kontrollü basit bir darbe üreteci hazırladım.

Kod:
const int potin = 0;
const int pulseout = 2;
const int ledpin = 13;
unsigned int value = 0;

void setup() 
{
  pinMode(ledpin, OUTPUT);
  pinMode(pulseout, OUTPUT);
  
}

void loop() 
{
  value = analogRead(potin);
  value = 5 + value / 10;
  digitalWrite(ledpin, HIGH);
  digitalWrite(pulseout, HIGH);
  delay(10);
  digitalWrite(ledpin, LOW);
  digitalWrite(pulseout, LOW);
  delay(value);

}

Bu kod 8 - 66 Hz arası bir frekansta sabit 10 mS darbe üretiyor. Bu rakamlar 480 ile 3960 devir/dakika aralığına denk düşüyor.

İkinci bir Arduino Unoya ise şu kod yüklendi:
İlk Arduino'nun sinyal çıkışı 2 No'lu digital pinde. Sayıcı Arduino'nun girişi de 2 numarada. Yani artılar eksiler birleştirildikten sonra bir de 2 numaralı digital pinler birleştirildi.
Kodun içinde görsel geribildirim için 13 No'lu onboard LED ile ilgili satırlar da var.

Kod:
//Devir sayacı

const int senspin = 2;
volatile unsigned long x1 = 0;
volatile unsigned long x2 = 0;
unsigned long y1;
unsigned long y2;
unsigned long devir = 0;
volatile byte engineon = 0;
unsigned long timer;
volatile byte ledstate = 0;


void setup()
{
  Serial.begin(9600);
  pinMode(senspin, INPUT);
  pinMode(13, OUTPUT);
  attachInterrupt(0, readrev, FALLING);
}

void loop()
{
  timer = millis();
    noInterrupts();
    y1 = x1;
    y2 = x2;
    interrupts();
    if (y1 == y2)
    {
      devir = 0;
    }
    else if(engineon == 1)
    {
      devir = (60000 / (y1 - y2));
      if((y1 - y2) > 100) engineon = 0;
    }
    else
    {
      devir = 0;
    }
    Serial.print(y1 - y2);
    Serial.print("  ");
//    Serial.print(y2);
//    Serial.print("  ");
    Serial.println(devir);

}

void readrev()
{
  x2 = x1;
  x1 = millis();
  if((x1 - x2) <= 100) engineon = 1;
}

Seri porttan anlık devir sayısını okumak mümkün. Devir 750'nin altına inince motor durdu diye sıfır gösteriyor. Bu çalışmaya başlamamın amacı, motor rölanti koruması yapmak olduğu için bu yolu seçtim. Yoksa bu özelliğe gerek yok ya da alt devri çok daha aşağıya çekmek mümkün.
 
DIY Devir Sayaci

Bu kodla da peşpeşe gelen beş devir değerinin ortalaması alınıyor.

Kod:
//Devir sayacı

const int senspin = 2;
volatile unsigned long x1 = 0;
volatile unsigned long x2 = 0;
unsigned long y1;
unsigned long y2;
unsigned long devir = 0;
volatile byte engineon = 0;
unsigned long timer;
volatile byte ledstate = 0;
int devirler[5];
int ortalama;


void setup()
{
  Serial.begin(9600);
  pinMode(senspin, INPUT);
  pinMode(13, OUTPUT);
  attachInterrupt(0, readrev, FALLING);
}

void loop()
{
  timer = millis();
    noInterrupts();
    y1 = x1;
    y2 = x2;
    interrupts();
    if (y1 == y2)
    {
      devir = 0;
    }
    else if(engineon == 1)
    {
      devir = (60000 / (y1 - y2));
      if((y1 - y2) > 100) engineon = 0;
    }
    else
    {
      devir = 0;
    }
    ortalama = 0;
    for(int n = 0; n < 4; n++)
    {
      devirler[n+1] = devirler[n];
      ortalama = ortalama + devirler[n];
    }
    devirler[0] = devir;
    ortalama = (ortalama + devir) / 5;
    Serial.print(y1 - y2);
    Serial.print("  ");
//    Serial.print(y2);
//    Serial.print("  ");
    Serial.println(ortalama);

}

void readrev()
{
  x2 = x1;
  x1 = millis();
  if((x1 - x2) <= 100) engineon = 1;
}
 
DIY Devir Sayaci

16 X 2 LCD ekranı da bağladım. Devir sayacı tamam. :D

Bu VIDEOYU görmek için izniniz yok. Giriş yap veya üye ol

Kod:
//LCD Devir sayacı

/*
LCD RS digital 12
LCD Enable digital 11
LCD D4 digital 6
LCD D5 digital 5
LCD D6 digital 4
LCD D7 digital 3

LCD R/W 0V
*/

#include <LiquidCrystal.h>


const int senspin = 2;
volatile unsigned long x1 = 0;
volatile unsigned long x2 = 0;
unsigned long y1;
unsigned long y2;
unsigned long devir = 0;
volatile byte engineon = 0;
unsigned long timer;
volatile byte ledstate = 0;
unsigned int devirler[10];
unsigned int ortalama;
volatile byte flag = 0;
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);

void setup()
{
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);

  lcd.begin(16, 2);
  lcd.home();
  lcd.print("Sumer Yamaner");
  pinMode(senspin, INPUT);
  pinMode(13, OUTPUT);
  attachInterrupt(0, readrev, FALLING);
}

void loop()
{
  timer = millis();
  noInterrupts();
  y1 = x1;
  y2 = x2;
  interrupts();
  if (y1 == y2)
  {
    devir = 0;
  }
  else if (engineon == 1)
  {
    devir = (60000 / (y1 - y2));
    if ((y1 - y2) > 100) engineon = 0;
  }
  else
  {
    devir = 0;
  }
  ortalama = 0;
  for (int n = 0; n < 9; n++)
  {
    devirler[n + 1] = devirler[n];
    ortalama = ortalama + devirler[n];
  }
  devirler[0] = devir;
  ortalama = (ortalama + devir) / 10;
  if (flag == 1)
  {
    flag = 0;
    lcd.setCursor(0, 1);
    lcd.print("                ");
    if (ortalama > 9999)
    {
      lcd.setCursor(1 , 1);
    }
    else if (ortalama > 999)
    {
      lcd.setCursor(2 , 1);
    }
    else if (ortalama > 99)
    {
      lcd.setCursor(3 , 1);
    }
    else if (ortalama > 9)
    {
      lcd.setCursor(4 , 1);
    }
    else
    {
      lcd.setCursor(5, 1);
    }
    ortalama = (ortalama / 10) * 10;
    lcd.print(ortalama);
    delay(100);
  }
}

void readrev()
{
  x2 = x1;
  x1 = millis();
  if ((x1 - x2) <= 100) engineon = 1;
  flag = 1;
}
 
DIY Devir Sayaci

Bu konu uykuda kalmış biraz canlandıralım.
Banggood'dan bir ara deneme amaçlı almış olduğum 0.96 inch OLED ekranı test etmeye başladım. Başlar başlamaz da birkaç tane daha sipariş verdim. :)
Minik bir devir göstergesi yapıyorum (benzinli motorlar için).
İlk örnek burada...

Bu VIDEOYU görmek için izniniz yok. Giriş yap veya üye ol
 
DIY Devir Sayaci

OLED ekran sürme isi de çözümlenmis gördüğüm kadarı ile abi. Bu durumda biten bazı projeler küçük bir revizyona uğrayacak gibi hissediyorum :D


Sent from my iPhone using Tapatalk
 
DIY Devir Sayaci

OLED ekranla ilgili de bazı gelişmeler var. Normalde bu ekran için Adafruit'in kütüphaneleri işlemcinin RAM'inde 128 * 64 bit (yani 128 * 8 byte = 1024 kB) bir buffer oluşturuyorlar. Ayrıca fontlar için işlemci hafızasına gereksinim duyuyorlar. Böyle olunca ancak Atmega işlemcilerde çalışabiliyorlar.
Attiny85 gibi minik işlemcilerin bu kadar RAM'leri yok. O nedenle bunlar için hazırlanmış bazı kütüphaneler sadece bitmap işlemler yapacak kadar basit tasarlanmış. Yani ekrana bir piksel yazabiliyoruz ya da çok basit işlemler yapabiliyoruz. Entegre fontları olmadığı için yazı yazamıyoruz.
Devir göstergesi için bana tam tekmil bir font seti gerekmiyor. Sadece 0 - 9 arası rakamlar yeterli. Ben de 16 x 32 boyutunda rakam karakterleri tasarlayıp onları programa aktarmaya karar verdim. Dün birkaç saatim bunun için gitti. Ne yazık ki var olan kütüphanelerin dokümantasyonu çok iyi değil. Bende de acemilik var. O nedenle deneme yanılma ile ielrlemem gerekiyordu. Her seferinde Attiny'yi breadboarddan sök, programlayıcıya tak, tekrar geri tak ve dene... Neyse sonunda yüzüm güldü. İstediğim karakterleri istediğim yerlere yazdırmayı becerdim. Gece bir gibi o aşamada bıraktım. Bugün de devir sayacı algoritmasına bu OLED yazma işlevini entegre ettim. Akşama test ve debugging sonrası minik devir göstergemizin hazır olacağını sanıyorum.
Sonuçta benzinli motorun ateşlemesinin sensörüne Y kablo ile ya da doğrudan devir sayacı çıkışına (eğer varsa) bağlanacak, beslemeyi oradan alacak, yaklaşık 2 cm * 2 cm boyutunda bir modül şeklinde planlıyorum. Şimdiki tek derdim buna uygun plastik bir kutu bulmak.