ATMEL PROGRAMLAMA 11 - Buton led uygulaması -2


   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 

  while (1)
    {
         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.
        }   
 
bu buton işlemlerinde kullanılabilecek güvenli bir yöntemdir. 

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