Bir önceki konumuzda bir buton ile bir led'i yakmayı başardık. Şimdi yapacağımız uygulamada 8 tane led ve bir tane butonumuz olacak. Devremiz aşağıdaki gibidir.
peki bu uygulamanın bir önceki uygulamadan farkı nedir?
1- Pull-up direncimiz olmayacak. portb0'in dahili pull-up özelliğini kullanacağız.
2- Butona her basışımızda bir artış sağlanacak. Bu şekilde bir önceki uygulamada kullandığımız buton kontrol mantığının ne kadar işe yarayacağını ,eksik yanın ne olduğunu öğrenmiş olacağız.
devre şemamız

Butona her bastığımızda bir led yanacak ama sönmeyecek. Ledler yanmaya PBO pininden başlayacak. bütün ledler yanınca ledler bir kere yanıp sönecek ve işlem başa dönecek.
önce butonumuzun bağlı olduğu pinin pull-up 'ını nasıl ayarlayacağımızı öğrenelim.
1- Butonun bağlı olduğu pin giriş olarak tanımlanır. DDRD &=~(1<<PIND0);
2- pin sanki çıkışmış gibi HIGH (1) yapılır. PORTD |=(1<<PORTD0);
Programımız
#include <avr/io.h>
#define F_CPU 1000000ul
#include "util/delay.h"
int main(void)
{
DDRB =0xff; // B portu çıkış olarak ayarlandı
DDRD &=~(1<<PIND0); // PD0 pini giriş yapıldı
PORTD |=(1<<PORTD0); // PD0 pull up aktif
while (1)
{
if(!(PIND & 0X01)) // butona basıldı ise
{
PORTB<<=1; // PORTB bir sola kaydırılıyor
PORTB |=0x01; // PORTB bir artırılıyor.
}
}
}
Programı incelediğiniz zaman mantık olarak çalışması gerekiyor. çünkü bir önceki buton led uygulamasındaki aynı buton kontrol mantığı kullanılmıştır. şimdi programı proteusta veya devrenize yükleyerek deneyin.
Sonuç istediğimiz gibi oldu mu ? Butona bir kere bastığınızda her defasında bir led yandı mı? yanmadı değil mi . :) butona birkere bastınız ama muhtemelen birçok led veya hepsi yandı değil mi :) . Peki neden ? hata veya eksik nerde ?
işte bu uygulamanın amaçlarından birtanesi de bu eksiği bulmak.
Şimdi aslında ne olduğunu açıklayalım. bir önceki konuya geri dönersek
{
if(!(PIND & 0X01))
{
PORTB|=(1<<PINB0);
}
else
{
PORTB&=~(1<<PINB0);
}
}
programımız böyleydi. Bizim denetleyicimiz şu anda 1 Mhz'de çalışıyor. bu şu anlama gelir atmega 328p her 1/1000000 sn'de yani 1 mikrosaniyede bir komut işler. (bazı istisna komutlar hariç). yani yaklaşık 5 mikro sn'de bir (5 mikrosaniye hassas hesaplanmış değildir ortalama bir süre olarak aldım. süreyi net bir şekilde programın assembly haline bakarak hesaplayabiliriz . Ancak şuanki konumuz değil. )
Bizim elimizi butona basıp çekmemiz çok hızlı dahi olsak yarım saniye yani 500000 mikro saniye eder. yani biz elimizi butona bastığımızda program 500000/5 =100000 defa bastığımız zanneder. bu nedenle şimdi yaptığımız uygulamada butona birkez bastık ama program bunu birkez değil çokkez olarak algıladı
proramın
if(!(PIND & 0X01)) // butona basıldı ise
{
PORTB<<=1; // PORTB bir sola kaydırılıyor
PORTB |=0x01; // PORTB bir artırılıyor.
}
bu kısmı birçok kez çalıştırdı. sonuçta butona bir basışta bir led yanacağına bütün ledler yandı.
örneğin bankaya veya postaneye gittiniz numaratördeki butona bastınız ve birtane sıra kağıdı alacağınıza beş on tane aldınız. :)
Klavyeden "A" tuşuna bastınız. Ekranda bir tane "A" yazmasını bekliyorsunuz ama sizin butona basma hızınıza bağlı olarak
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" şeklinde "A" yazar
peki çözüm nedir ?
1.Yöntem - Butona basıldığını anladıktan sonra programa belli bir süre gecikme ekleriz. Bu şekilde program bir süre hiçbir işlem yapmaz ve biz bu süre içinde elimizi butondan çekersek program istediğimiz gibi çalışır.
if(!(PIND & 0X01)) // butona basıldı ise
{
_delay_ms(700);
PORTB<<=1; // PORTB bir sola kaydırılıyor
PORTB |=0x01; // PORTB bir artırılıyor.
}
deneyelim. şimdi oldu değil mi ? her basışta bir led yandı. Tam istediğimiz gibi. fakat dikkat ederseniz ledler gecikmeli yanıyor. Bu bazı durumlarda sıkıntı olabilir.
_delay_ms(700); buradaki 700 değerini düşürerek daha hassas bir tepki elde edebilirz. mesela
_delay_ms(100); 'ü deneyin . herbasışta iki led yandı.
_delay_ms(200); benim içi daha iyi oldu. Ama benim için !. herkesin butona basma hızı aynı olamaya bilir.
örneğin bankaya eya postaneye gittiniz numara alacaksınız. butoan bastınız siz bir tane numara aldınız. daha yavaş biri bastı iki tane numara aldı . :) açıkçası yapacağınız işlem kişiye bağlı olmamalı her basışta bir numara vermeli .
2. Yöntem - Butona basınca yapmak istediğimizi butona basınca değilde butundan elimizi çektiğimizde yapmak.
Butona bastık program anladı , hiçbir işlem yapmadı , elimizi butondan çekmemizi bekleyecek.
bunun için while(!(PIND & 0X01)) ; kullanabiliriz. butona basıldığı sürece burada bekler, elimizi çekince programın bir sonraki aşamasına geçeriz.
if(!(PIND & 0X01)) // butona basıldı ise
{
while(!(PIND & 0X01)) ; // buton basılı olduğu sürece bu satır işler
PORTB<<=1; // PORTB bir sola kaydırılıyor
PORTB |=0x01; // PORTB bir artırılıyor.
}
programımızın son hali
#include <avr/io.h>
#define F_CPU 1000000ul
#include "util/delay.h"
int main(void)
{
DDRB =0xff; // B portu çıkış olarak ayarlandı
DDRD &=~(1<<PIND0); // PD0 pini giriş yapıldı
PORTD |=(1<<PORTD0); // PD0 pull up aktif
while (1)
{
if(!(PIND & 0X01)) // butona basıldı ise
{
while(!(PIND & 0X01)) ; // buton basılı olduğu sürece bu satır işler
PORTB<<=1; // PORTB bir sola kaydırılıyor
PORTB |=0x01; // PORTB bir artırılıyor.
}
if(PINB==0XFF) // bütün ledler yandı ise
{
_delay_ms(200); // biraz bekle yanık kalsın
_delay_ms(200);
_delay_ms(100);
PORTB=0X00; // tüm ledleri söndür.
_delay_ms(200); // biraz bekle
_delay_ms(200);
_delay_ms(100);
PORTB=0Xff; // tüm ledleri yak
_delay_ms(200); //biraz bekle
_delay_ms(200);
_delay_ms(100);
PORTB=0X00;
}
}
}
denediğimiz zaman istediğimizin olduğunu göreceğiz :)
Yorumlar
Yorum Gönder