Buton ve anahtar uygulamalarında göz önünde bulundurulması gereken bir konu da buton veya anahtar kontaklarının istenilen konuma gelmesi sırasında kontaklar arasında oluşan ark 'dır. Kontaklar çok kısa sürede istenilen konuma gelirler, bu kısa süre içersinde ark oluşur ve insanın bunu algılaması zordur.
Aşağıdaki gibi bir pull-up buton bağlantısında butona basılmadığı sürece mikrodenetleyici pini lojik 1 seviyesindedir. Butona basılınca pin lojik 0 seviyesinde olacaktır. Her butona basılışta böyle devam edecektir.

Biz bu 1-0-1 geçişlerini resimdeki gibi zannederiz. Gerçekte ise aşağıdaki gibidir.


yaptığımız deney
Lojik 1 seviyesinden lojik 0 seviyesine geçiş hemen olmaz. Çok kısa bir süreliğine (yukarıdaki şekilde 250mikro saniye ) ark oluşur. Oluşan bu arkları mikrodenetleyici fark eder ve yanılır. Yukarıdaki şekilleri ve deney videomuzu incelerseniz sinyalin ark kısımlarında bir kaç tane 1-0-1-0-1 geçişleri yaşanır. Mikrodenetleyici bu durumları butona basıldı olarak algılar ve ona göre tepki verir. Yaptığı işlem hatalı olur.
Bu sorunun çözümü iki şekilde olur.
1- Donanımsal çözüm
2- Yazılımsal çözüm .
1- Donanımsal Çözüm
Ark istenmeyen bir sinyaldir. Elektronik devrelerde istenmeyen sinyaller donanımsal olarak filtreleme ile bastırılır. Biz de donanımımızda gerekli filtrelemeyi yaparsak ark'ı etkisiz hale getirebiliriz. Sinyal içindeki ark kısmında değişim sinyale göre fazladır. Yani sinyale göre frekansı yüksektir. Alçak geçiren bir filtre yaparsak yüksek frekanstaki ark sinyalini bastırmış , istenilen sinyali geçirmiş oluruz. Bunun en basit yolu buton uçlarına paralel kondansatör bağlamaktır.

Botuna basılmadığı anlarda kondansatör (C), R pull-up direnci üzerinden şarj olur. Mikrodenetleyici pini girişinde kondansatör üzerindeki gerilim değeri görülecektir. ve lojik 1 seviyesindedir .
Butona basılınca kondansatörün iki ucu kısa devre olarak GND'ye bağlanmış olur ve kondansatör hemen deşarj olur. Giriş gerilimi kondansatör üzerindeki gerilim değeri olduğundan giriş anında 0V olur. Elimizi butondan çekitiğimizde kondansatör şarj olmaya başlayacaktır. Kondansatörün üzerindeki gerilim Atmega 328p'yi lojik 0 seviyesinde tutacak gerilim değerine ulaşana kadar giriş pini lojik 0 seviyesinde kalır. Bu gerilim değerine ulaşıncaya kadar geçen süre içersinde ark oluştuğu anda arkın 1 seviyeleri kondansatör şarjını fazla etkilemeyeceğinden mikrodenetleyici pini lojik 0 seviyesini algılar. Böylece giriş pini ark durumundan fazla etkilenmemiş olur.
Atmega 328p'nin lojik 0 ve lojik 1 gerilim değeri aralıkları datasheet'te sayfa 303'te DC Characteristics başlığı altında tablo 29-1de belirtilmiştir.. Burada
Atmega 328p'nin lojik 0 ve lojik 1 gerilim değeri aralıkları datasheet'te sayfa 303'te DC Characteristics başlığı altında tablo 29-1de belirtilmiştir.. Burada
Vcc= 5V kullandığımızı farz edersek tabloya göre;
Lojik 0 aralığı -0.5V--------0.3Vcc aralığıdır. bu durumda
0.3Vcc =0.3*5V=1.5V olur ve -0.5V- ------ 1.5V arası Atmega 328p için lojik 0 kabul edilir.
Lojik 1 aralığı ise 0.6Vcc-------Vcc+0.5V'tur. bu durumda Vcc=5V oduğundan
3V----------5.5V arası atmega 328p için lojik 1 kabul edilir.
Giriş pinindeki gerilim değeri kondansatör üzerindeki gerilim değeri olduğuna göre, kondansatör üzerindeki gerilim 1.5V'tu geçmediği sürece giriş Lojik 0 olacaktır. Kondansatörün belli bir gerilim değerine ulaşması için geçen süre şu formülden elde edilir

buradan gerekli değerleri girerek istediğiniz hesaplamayı yaptırabilirsiniz. Örneğin yukarıdaki grafikte ark süresi 25mikrosaniyeydi. isteğimiz bu süre içinde kondansatör üzerindeki gerilim 1.5V seviyesine ulaşmalı. Direnç değerimiz zaten belli 10Kohm pull-up direnci. Bu değerlere göre hesaplama yaparsanız yaklaşık 8 nf'lık bir kondansaör değeri elde edilir. Bu teorik olanı.
Peki pratikte ne yapacağız. 25 mikrosaniye bizim için az bir süre . işimizi garantiye almak için biz bu süreyi daha yüksek tutatabiliriz. örneğin 250 mikro saniye. tekrar hesaplarsak bu sefer kondansatör değeri yaklaşık 70nf olur ki biz kolayca bulunabilen 100nf kullansak bu değer bize oldukça yeterli olacaktır.
100nf kullandığımız zaman sinyalimiz.
Şekilde de gördümüz gibi arkları önledik ancak şimdi de bazı salınımlar meyadana gelebilir. Bunlar kondansatörün ve direncin toplam empedansı nedeyiyle oluşuyor. Ve deşarj işlemi hemen olmuyor. Her elemanın ve her bağlantı noktasının bir endüktansı vardır. Bu endüktans ve kondansatör bir araya gelince salınım hareketi başlayacak ve - (negatif) yönde gerilim oluşacaktır. Bu negatif gerilim değeri Atmega 328p'nin pinleri için minimum değer olan -0.5V sınırını aşarsa mikrodenetleyiciye zarar verebilir. Bu nedenle salınımların engellenmesi gerekir. Bunun için en iyi yöntem direnç eklemektir. Yeni devremiz aşağıdaki gibi olacaktır.

Salınımları en aza indirmek için kondansatörün çık hızlı bir şekilde R2 direnci üzerinden deşarj olması gerekir. Bu nedenle R2 direncinin düşük değerde olmalıdır. Örneğin 100 ohm.
alacağımız sonuç aşağıdaki gibidir.

Şekilde de görüldüğü gibi osilasyon ve ark engellenmiş oldu. ancak Lojik 1 seviyesinden Lojik 0 seviyesine geçiş hala belli bir süre almakta .Bunun çözümü için 74HC14 schmitt triger buffer kullanmamız gerekir. Devremiz aşağıdaki gibi olur.

74HC14 lojik seviye geçişlerini daha hızlı bir hale getirir ve istenmeyen sinyalleri engeller. 74HC14 aynı zamanda bir inverter'dır. Pull-up bağlantıda butona basınca giriş pinine lojik 0 bilgisi geliyordu. 74HC14kullandığımız zaman bu lojik 0 terslenecek ve giriş pini butona basılınca Lojik 1 olacak. Bu nedenle programda buton kontrolu Lojik 1 ' e göre tekrar düzenlenmelidir.
Donanımsal olarak yapabileceklerimiz bunlar. ekleyeceğimiz her eleman devremizde fazladan yer , iletim yolu ve maliyet olarak karşımıza çıkacaktır. Devremiz çok hassas olamayacaksa donanım yerine yazılımımızı düzelterek de bu sorunu çözebiliriz.
devremize kondansatör ve 74hc14 ekledikten sonra
Deneyimizde kondansatör ve 100 ohm'luk direnci çıkratıp sadece 10kohm pull-up ve 74hc14 kullandık sonuç yine temiz bir giriş puls'i oldu.
2- Yazılımsal Çözüm
buton programımız
#include <avr/io.h>
#define F_CPU 1000000ul
#include "util/delay.h"
int main(void)
{
DDRB |=(1<<PINB0);
DDRD &=~(1<<PIND0);
while (1)
{
if(!(PIND & 0X01))
{
PORTB|=(1<<PINB0);
}
else
{
PORTB&=~(1<<PINB0);
}
}
}
1.yöntem buton arkını önlemek için birkaç tane yazılımsal çözüm vardır. Bunlardan en basit olanı buton kontrolünden sonra bir süre gecikme sağlamaktır. Bu şekilde sinyalin ark ksımları program tarafından okunmaz. Ancak gecikme algılamanın hızlı oması istenilen durumlarda kullanışlı olmaz.
#include <avr/io.h>
#define F_CPU 1000000ul
#include "util/delay.h"
int main(void)
{
DDRB |=(1<<PINB0);
DDRD &=~(1<<PIND0);
while (1)
{
if(!(PIND & 0X01))
{
_delay_ms(30);
PORTB|=(1<<PINB0);
}
else
{
PORTB&=~(1<<PINB0);
}
}
}
programda şöyle bir değişiklik daha yapabiliriz. Bekleme sonrası tekrar butonun durumunu kontrol edbiliriz.
while (1)
{
if(!(PIND & 0X01))
{
_delay_ms(30);
if(!(PIND & 0X01))
{
PORTB|=(1<<PINB0);
}
}
else
{
PORTB&=~(1<<PINB0);
}
}
2.yöntem butona basıldığı anlaşıldığında, bir de bir önceki periyotta butona basılmamış olması kontrol edilir. Eğer bir önceki periyotta da butona basıldı uyarısı varsa bu ark olarak algılanır ve işlenmez.
int butonbasildi=0;
while (1)
{
if(!(PIND & 0X01))
{
if(butonbasildi==0)
{
PORTB|=(1<<PINB0);
butonbasildi= 1;
}
}
else
{
PORTB&=~(1<<PINB0);
butonbasildi=0;
}
}
3.yöntem butona basildiğinda veya basilmadiğinda her iki durum için de ayrı ayrı bir sayaç tutulur.. Bu sayaç değerleri belli bir sayıya ulaştığında butonun durumuna karar verilir. Örneğin sayacımızın sınırını 500 olarak ayarladığımızda, butona basıldığı veya basılmadığı değeri 500 'e ulaşan sayaç ile belirlenir. Sayaçlardan herhangi biri artarken diğer durum oluşursa sayaç sıfırlanır. Böylece ark durumları sırasındaki hızlı geçişler algılanır ama en son butonun durumuna karar verlir. Kullanılabilecek en güvenli yöntemlerden biridir.
#define F_CPU 1000000ul
#include <util/delay.h>
#define buton PINB1
#define led PINB0
int buton_basili=0;
int buton_basilidegil=0;
char basildi=0;
int main(void)
{
DDRB&=~(1<<buton); // BUTON PINB1
PORTB|=(1<<buton); // PINB1 PULL UP
DDRB|=(1<<led); // LED PINB0
while (1)
{
if(!(PINB & 0x02)) // butona basıldığı anlaşılıyor.
{
buton_basili++; // butona basildiğini gösteren sayaç
buton_basilidegil=0; // butona basilmadiğini gösteren sayaç sıfırlanır
if(buton_basili>500) // buton_basili sayacı 500'e ulaşırsa butona basıldığı
//anlaşılır
{
if (basildi==0) // bir önceki durumda basılı değil ise
{
PORTB^=(1<<led); // Led toggle yapılıyor
_delay_ms(200);
basildi=1; // bir sonraki periyot için basıldı uyarısı
buton_basili=0; // buton_basili sayaci sıfırlanmış
}
}
}
else // butona basılı değil ise
{
buton_basili=0; // buton _basili sayacı sıfırlanır.
buton_basilidegil++; // buton basilidegil sayacı artıyor
if (buton_basilidegil>500) // buton_basilidegil sayacı 500 sınırını aşarsa
{
basildi=0; // bir sonraki periyot için basilmadı uyarısı
buton_basilidegil=0; // buton basilidegil sayacı artıyor
}
}
}
} Bu konu ile ilgili çeşitli yazılımsal yöntemler geliştirilebilir. Yöntem yapılan uygulamaya göre değişkenlik gösterebilir.
Donanımsal çözüm, çok hassas ve algılama hızının yüksek olduğu durumlarda daha kullanışlıdır. Ancak devrede daha fazla elaman , daha fazla iletim yolu ve maliyet artışı demektir. Yazılımsal çözümler hassasiyet az olduğu ve algılama hızının önemsenmediği uygulamalarda daha kullanışlı olur.
Kaynak : http://www.gooligum.com.au/tutorials.html
Ayrıca yardımlarından dolayı Düzce Üniversitesi Teknoloji Fakültesi Elektrik-Elektronik Mühendisliği bölümü 3. sınıf öğrencilerim Mahmut ÖZBAY, Engin MERT, Yasin UYSAL ve Yasin BİLGİ'ye teşekkür ederim
kodları, yorum satırı ile acıklarsanız daha iyi olabilir. gene gayet faydalı bir içerik olmuş teşekkür ederim
YanıtlaSil