CCS-C ile PIC Programlama, Portlar Led Buton ve Röle Kullanımı

Her ne kadar daha önceki yazılarımızda kısmen anlatmış olsakda PORT’lar ve kullanımı konusunu daha ayrıntılı olarak bu yazımıda ele alacağız.

PORTLAR

Portlar PIC denetleyicilerinde giriş/çıkış işlemleri için kullanılan yapılardır. Örneğin bir anahtarın açık/kapalı durumunu belirlemek, LED yakmak, Röle açıp kapamak, veya bir LCD ekranı sürmek için PORT’ları kullanırız. Her PIC modelinde farklı sayıda port bulunur ve bu portlar farklı büyüklüklerde olabilir. Büyüklükten kastımız PORT’un kaç bit olduğudur.

Kullandığınız denetleyicinin teknik dökümanına bakarak kaç porta sahip olduğunu öğrenebilirisiniz. Portlar A,B,C….F gibi harflerle isimlendirilir, PORTA, PORTB, PORTC gibi. Aşağıdaki resim 16f628A Denetleyicisinin pin bağlantılarını göstermektedir.

Resimde de görüldüğü gibi PIC 16F628A Denetleyicisi PORTA, ve PORTB olmak üzere iki adet porta sahiptir. PORTB RB0…..RB7 olmak üzere 8 Bit, PORTA ise RA0….RA5 olmak üzere 6 Bit’tir.

RB0….RB7, RA0….RA5 PORT’ları oluşturan PIN’lerdir. Bir PIN önündeki <—-> simgesi, o PIN’in hem giriş hem de çıkış olarak kullanılabileceğini —-> simgesi ise sadece giriş olarak kullanılabileceğini gösterir.

CCS-C derleyicisinin kullanımını öğrenmek kadar PIC Donanımlarını da çok iyi öğrenmek gerekir. Donanım tecrübesi olmadan bilgisayarda simulasyonla PIC programlama öğrenmek iyi birşey değildir. Bu yüzden en temel seviyede donanımların ne iş yaptıklarını ve nasıl bağlanacaklarını elimden geldiğince anlatmaya çalışacağım.

Yukarıdaki resimde gördüğünüz gibi PORT PIN’lerinin yanında başka şeylerde yazmakta. RB3/CCP1 ve RB0/INT gibi. Bu ifadeler bu pinlerin alternatif kullanımlarını göstermektedir RB3/CCP1 ifadesi 9 nolu bacaktan PWM sinyali üretebileceğimizi, RB0/INT ifadesi ise 6 nolu bacağın Harici Kesme girişi olduğu belirtir.

Demekki PIC denetleyicilerinde bazı PIN’leri farklı farklı amaçlar için kullanabiliriz. Bu tamamen bizim ihtiyacımıza ve tercihimize kalmış.

GİRİŞ ÇIKIŞ AYARLAMALARI

Bir portun istediğiniz PIN’ini giriş istediğinizi de çıkış yapabilirsiniz. Bu işlemi gerçekleştirmek için ilgili portun TRIS Register’ini ayarlamanız gerekir.

16f628A TRIS Register adresleri TRISA = 0×85 TRISB = 0×86

Bir pini giriş yapmak için ilgili TRIS biti 1 yapılır
Bir pini çıkış yapmak için ilgili TRIS biti 0 yapılır

Şimdi B portunun tüm PIN’lerini giriş yapmak istersek TRISB = 0xff yapmamız gerekir. Bunu gerçekleştirmek için set_tris_x() fonksiyonunu kullanabiliriz

#include <16f628a.h>
main()
{
set_tris_b(0xff); // B portu komple giriş
}

Bu ayarlamayı hazır fonksiyon kullanmadan da yapabiliriz. Bunun için öncelikle TRISB Register’ını programımızda tanımlayıp daha sonra değer atamamız gerekir

#include <16f628a.h>
#byte TRISB = 0x86  // TRISB 0x86 adresindedir

main()
{
TRISB = 0xff;  // B portu komple giriş
}

Başka örnekler

set_tris_a(0b00001010);  // A1,A3 giriş diğerleri çıkış
set_tris_b(0xf0); //B0...B3 Çıkış, B4...B7 giriş
set_tris_c(0x55); //C0,C2,C4,C6 giriş C1,C3,C5,C7 Çıkış

Portlarla ilgili bazı önemli bilgiler.

  • Her bir Giriş/Çıkış PIN’inden çekilebilecek veya bu PIN’e akabilecek maksimum akım 25mA’dir
  • RA4 TOCKI PIN’i Open Collector Output olduğundan, bu pini çıkış olarak kullanmak istediğinizde bir direnç ile beslemeye pull-up yapmanız gerekir.
  • PORTB Dahili pull-up dirençlerine sahiptir ve bu dirençler yazılım ile devreye sokulabilir.
  • Kullanılmayan pin’lerin çıkış olarak ayarlanması gerekir

DONANIM BAĞLANTILARI

Ledler

Bir ledi PIC’e iki şekilde bağlayabilirsiniz. Led’lere besleme verirken bu işlemin bir ön direç ile yapılması gerektiğini unutmayınız. Dirençsiz bağlarsanız led aşırı akımdan dolayı kullanılamaz hale gelecektir. Ledlerin büyük çoğunluğu maksimum 20mA akım ile çalışacak şekilde üretilirler. Led öndirencinin nasıl hesaplanacağını bilmiyorsanız buraya bir göz atın

RB0′a bağlanan LED-1′i yakmak için RB0 = “0″ yapılır, söndürmek için “1″ yapılır

RB3′e bağlanan LED-2′yi yakmak için RB3 = “1″ yapılır, söndürmek için “0″ yapılır

Röleler

Aşağıdaki şemada yaygın olarak kullanılan PIC ile röle sürme devresi görülmektedir.

RB7 = “1″ yapıldığında röle çeker, “0″ yapıldığında bırakır.

VCC voltajı rölelin çalışma votajıdır ve röle modeline göre değişir.

Butonlar

Aşağıdaki şemada da görülebileceği gibi butonlar da iki farklı şekilde PIC’re bağlanabilir.

Buton bağlanan bacaklar giriş olarak ayarlanmalıdır. Yukarıdaki şemaya göre, Buton-1 basıldığında RA2 = 0 olur. Buton-2 basıldığında RB2 = 1 olur. Bu değerler yazılım ile okunarak butonun basılıp basılmadığı tespit edilebilir.

TOPLU ÖRNEK – ISIS ÇİZİMİ VE KODLAR

ISIS Proje dosyasını indirmek için tıklayın test_project

LED-1 RB7′de
LED-2 RB6′da
BUTON-1 RA0′a
BUTON-2 RA1′de
RÖLE RB5′te Bağlı

Örnek

Şimdi 1 nolu butona basılı tutulduğu sürece 1 nolu ledi yakan, buton bırakıldığında söndüren. 2 Nolu butona basıldığında ise bırakıldığında 2 Nolu ledin durumunu değiştiren programı yazalım. Devre ilk açıldığında da rölemiz 2 saniye çekip bıraksın.


#include <16f628a.h>
#use delay(clock=4000000)

#fuses INTRC,NOMCLR,PROTECT,NOWDT
#fuses PUT,NOLVP,NOCPD,NOBROWNOUT

void main(void)
{
set_tris_a(0x03);  //A0,A1 giriş diğerleri çıkış
set_tris_b(0x00);  //B portu komple çıkış
output_low(PIN_B7);
output_high(PIN_B6);

output_high(PIN_B5)   //Röle çeksin

delay_ms(2000);  // 2 sn bekle

output_low(PIN_B5)   //Röle bıraksın
while(TRUE) // Sonsuz döngü
{
if(input(PIN_A0)==0 )  //Buton-1 basılımı?
{
output_high(PIN_B7); // Ledi yak
while(input(PIN_A0)==0); // Butonun bırakılmasını bekle
output_low(PIN_B7); // Ledi söndür
delay_ms(25);  //debounce süresi
}

if(input(PIN_A1)==1 )  //Buton-2 basılımı?
{
while(input(PIN_A1)==1); //Butonun bırakılmasını bekle
output_toggle(PIN_B6);  //Led'in durumuu değiştir
}
}
}

Şimdi aynı işi yapan kodu daha profosyonelce yazalım


#include <16f628a.h>
#use delay(clock=4000000)

#fuses INTRC,NOMCLR,PROTECT,NOWDT
#fuses PUT,NOLVP,NOCPD,NOBROWNOUT

#byte PORTA = 0x05
#byte PORTB = 0x06
#byte TRISA = 0x85
#byte TRISB = 0x86

#bit LED1 = PORTB.7
#bit LED2 = PORTB.6
#bit BUTON1 = PORTA.0
#bit BUTON2 = PORTA.1

void main(void)
{
PORTA = 0;
PORTB = 0;
TRISA = 0x03;  // A0, A1 girişi
TRISB = 0x00;  // Komple Çıkış

LED1 = 0;  // LED1 söndür
LED2 = 1;  // LED2 Söndür

while(TRUE) // Sonsuz döngü
{
if(!BUTON1)  //Buton-1 basılımı?
{
LED1 = 1; // Ledi yak
while(!BUTON1); // Butonun bırakılmasını bekle
LED1 = 0;       // Ledi söndür
delay_ms(25);  //debounce süresi
}

if(BUTON2)  //Buton-2 basılımı?
{
while(BUTON2); //Butonun bırakılmasını bekle
LED2 = !LED2;  //Led'in durumunu değiştir
delay_ms(25);  //debounce süresi
}

}

}

Buton kullanımıyla ilgili ipuçları

  • Gerçek devrelerinizde asla butonları bir kez okuyarak durumları değişmiş kabul etmeyin. En az 100 defa basılmışmı veya bırakılmış mı diye kontrol ettirin. Bu şekilde yapmazsanız dışarıdan gelebilecek parazitler olumsuz etki yapar.
  • Elinizi butondan çekerken bounce (zıplama) denilen hadise nedeniyle ikinci bir basış gerçekleşebilir. Buda bozuk çalışmaya neden olabilir. Bu durumun önüne geçmek için buton bırakılması tespit edildiğinde belirli bir gecikme süresi konur. Yukarıdaki kodlarda 25ms gecikmeler bu amaçla konmuştur.

Yazımızı burada noktalıyoruz. Anlamadığınız yerler olursa sormaktan çekinmeyin

CCS-C ile PIC Programlama, Portlar Led Buton ve Röle Kullanımı yazısı için 73 yorum yapıldı

  1. sinan says:

    öncelikle bizlere böyle bir katkı sağladığınız için canı gönülden teşekkür ederim.emeğinize sağlık yazılarınızın devamını bekliyorum.

  2. kadir says:

    Merhaba, hocam benim bir sorum olacaktı bu konuda biraz yeniyim şu ccs de proje oluşturduğumda #use ve #fuse leri tanımlamıyor.Acaba onları kendimiz mi tanımlamamız lazım?

  3. Emrah AYDIN says:

    @kadir
    PIC Wizard kullanarak projeyi oluşturmuş isen projenin h dosyasında fuse satırlarını bulabilirsin. C dosyasının en üstünde #include ile başlayan satırda h dosyası include ediliyor. o satıra sağ tıklayıp “open fila at cursor” seçeneğini seçersen h dosyasıda açılır.

  4. fatih says:

    Hocam Her zamanki gibi harikasın.
    Allah razı olsun. Allah ne muradın varsa versin.
    İnşallah bize ücretsiz öğrettiğin derslerin ücretini iki dünyada bolbol alasın…

  5. ibiza15 says:

    arkadaşlar anlatım için çok teşekkürler. Ben LM35 ve 16f877 ile sıcaklık sensörü yapıyorum. LM35 çıkışını A0′a bağladım. B portuna da led bağladım. Ölçtüğüm sıcaklığı ikili sisteme göre ledlere aktaracağım ama bir yerlerde yanlışlık yapıyorum sanırım. Giriş değişse de çıkışta bir değişiklik göremiyorum. Kodu aşağıda. Acaba nerede yanlışlık yapıyorum?

    #include “C:\Documents and Settings\asus\Desktop\lm35prj\main.h”
    // Denetleyici konfigürasyon ayarları
    #fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
    #use delay (clock=4000000) // Gecikme fonksiyonu için kullanılacak osilatör frekansı belirtiliyor.
    #use fast_io(a) //Port yönlendirme komutları A portu için geçerli
    #use fast_io(b) //Port yönlendirme komutları B portu için geçerli
    #byte PORTB = 0×00
    void main()
    {
    unsigned long int bilgi; // İşaretsiz 16 bitlik tam sayı tipinde değişken tanımlanıyor
    float voltaj,sicaklik; // ondalıklı tipte değişkenler tanıtılıyor
    setup_adc_ports(NO_ANALOGS);
    setup_adc(ADC_OFF);
    setup_psp(PSP_DISABLED);
    setup_spi(SPI_SS_DISABLED);
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
    setup_timer_1(T1_DISABLED);
    setup_timer_2(T2_DISABLED,0,1);
    setup_comparator(NC_NC_NC_NC);
    setup_vref(FALSE);
    // TODO: USER CODE!!
    set_tris_a(0xFF); // RA Giriş olarak yönlendiriliyor
    set_tris_b(0×00); // B portu tamamen çıkış olarak yönlendirildi, çıkışa led bağlanacak
    setup_adc(adc_clock_div_32); // ADC clock frekansı fosc/32
    setup_adc_ports(AN0); //RA0/AN0 girişi analog
    set_adc_channel(0); // RA0/AN0 ucundaki sinyal A/D işlemine tabi tutulacak
    delay_us(20); // Kanal seçiminde sonra bu bekleme süresi verilmelidir
    while(1) // sonsuz döngü
    {
    bilgi=read_adc(); // ADC sonucu okunuyor ve bilgi değişkenine aktarılıyor
    voltaj=(0.0048828125*bilgi)*1000; // Dijitale çevirme işlemine uğrayan sinyalin mV olarak gerilimi hesaplanıyor
    sicaklik=(voltaj/10)+2; // Her 10mV’ta 1 derece artma
    PORTB=(int)sicaklik;
    delay_ms(100); // 100 msn gecikme
    }
    }

  6. newbie says:

    Merhaba hocam,
    Diger yazınızda bu yazının linkini vermiştiniz cevap olarak ben de sonuna kadar okudum.Yazının sonunda en az 100 defa kontrol edin demişsiniz butonun durumunu.Bu kodda öyle bişey var mı göremedim?
    Bir de ben if-else-while kullanarak bazı denemeler yaptım ama çok garip sonuclar aldım.Sizin de yazdıgınız gibi 1 kere basınca 2 kere output alıyorum (2.si debouncedan dolayıymış bu yazıda yazdıgınız gibi).Ama bunun dışında garip olarak mainin sonuna geldigi halde pic programa baştan başlıyor.Uzun kod verip meşgul etmeyeyim kabaca ne demek istedigimi anlatayım:
    #tanımlamalar
    void main()
    {
    flag=1;
    while(flag)
    {
    if(buton basıldıysa) //pinb0
    printf(“butona basıldı”); //seri porta
    flag=0;
    }
    }

    1 kere basıyorum 2 kere basıldı yazısını görüyorum.Ayrıca 1-2 saniye sonra bastıgımda tekrar yazı görüyorum,mainin sonuna geldigi halde.(Auto reset gibi bişey var mı?)

  7. Emrah AYDIN says:

    verdiğin kodda hata var, orijinal kodunun bu kod olmadığını varsayarak, watchdog timer kapalı olarak çipe yükleme yaptığından emin misin? Yani konfigürasyon bitlerini düzgün ayarlayamamış olabilirsin.

  8. newbie says:

    Nasıl bir hata var hocam?
    Evet orjinal kod bu degil kabaca mantıgı yanlış mı dogru mu diye yazdım.Zaten kesmelerle ilgili yazınızı okuyunca bu işi external kesme ile yapmanın daha saglıklı olacagını gördüm.
    Son olarak şunu sorayım : Yazınızın sonundaki uyarılarda butona basılmışmı veya bırakılmışmı diye en az 100 defa kontrol edin demişsiniz.Bunu kod içinde nasıl yaparız?Kesmeleri kullandıgımda böyle bir kontrole gerek kalır mı?Benim durumumda sadece harici kesme aktif olacak ve butona basılma sadece işlemin ortasında 1 defa gerçekleşecek,dolayısıyla çakışma ya da bir kesme çalışırken digerini kaçırma gibi sorun olacagını sanmıyorum.

    Cevaplar için teşekkürler

  9. newbie says:

    Bu arada yazmayı unutmusum kodun başında şunu kullanıyorum :

    #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT

  10. Emrah AYDIN says:

    Reset atıyorsa pic muhtemelen kesme kodunda hata vardır. Kesme kodu içerisinde delay kullanıyor musun? Parazit alma ihtimali olan devrelerde eğer buton 1 kez kontrol ediliyorsa, anlık voltaj spike’ları hatalı okumalara neden olabilir. Bu tür durumların önüne geçmek için çok fazla sayıda butonun basıldığını ve aynı şekilde bırakıldığını kontrol etmek gerekiyor. 100 kez kontrol için kendin demeler yap.

  11. cundep says:

    merhaba hocam
    butona basılıp bırakılınca aktif
    aynı butona basılıp bırakılınca pasif olmasını istiyorum
    while(1)
    if (input(pin_a0))
    output_high(pin_b7):
    if (input(pin_a0))
    output_low(pin_b7):

  12. cundep says:

    ama farklı calısıyor hocam butona
    basılınca devam ediyor sonra 4 kere basıca sönüyor yada 5 kere basınca yanıyor
    benim istedigim 0.1.0.1…..
    seklinde sonsuz döngü
    yardımlarınızı bekliyorum tessekkürler hocam

  13. deniz ak says:

    Merhaba
    ilk ornekteki A0 butonuna basili iken ledin surekli yanmasini aciklayabilirmisiniz?

    Ayrica A1 butonuna basilip birakildiktan sonra ledin konum degistirmesini de tam anlayamadim.

    Programin bu kisimlari nasil isliyor
    Anlatabilirseniz sevinirim.

  14. cudep says:

    pic ccs c de yeni oldugum için örneği yalnış
    yazmış olabilirim
    işlem olarak yapmak istediğim
    butona basıldıgında pin b0 pini ” 1 ” olsun
    butondan el cekildiginde b0 pini “1″ olarak kalsın.
    butona tekrar basıldıgında pin b0 ” 0 ” olsun
    butondan el cekildiğinde pin b0 “0″ olsun
    ve bu işlem sonsuz döngü olarak devam etsin
    yardımınızı bekliyorum teşekkürler hocam

  15. Mahir says:

    Emrah Bey,

    Web sayfanız bayağı bir zamandır takip ediyor paylaştığınız kodları büyük bir zevkle deniyorum. Fakat, timer0 ve timer1 kullanarak bir deneme yapmak istedim sonuca ulaşamadım. Yapmak istediğim ise; 16f877A MCU’suna 2 buton 2 led bağlamak birinci butona basınca 1. led 1 saniye aralıklarla yansın mesela 2. butona basınca 1. led dursun 2. led yarım saniye aralıklarla yanp sönmeye başlasın… Hepsi bu

    Defalarca timer’ları kurmaya çalışsamda başarılı olamadım normal olarak yapıyorum ama tuşlara bastığımda geçiş olması için delay süresini beklemem gerekiyor ve bu süre zarfında tuşa basılı tutmak zorunda kalıyorum. timer kullanarak çözebileceğimi biliyorum ama timerları hem led için hem butonlar için kullanamadım bu konuda minik bir örnek verebilirseniz çok sevnirim

    Saygılar

    Mahir

  16. ali says:

    bilgisayrın paralel porduna baglı 8 adet ledi 3erli olarak yakıp sağa sola kaydıran bir c program kodu lazım…cok acil
    şimdiden cok tesekkür ederım.

  17. yetkin says:

    Hocam sağolun sayenizde öğrendiğim çok şey oldu. Bu sayfada yaptığınız örnekte rölenin çalışma şeklini anlayamadım bu devrede nasıl çalıştığının mantığını anlatırsanız sevinirim.

  18. harun kaya says:

    meraba, l298 ile dc motor kontrolü yapmak istiyorum . size biraz bahsedeyim konuyu. 6 tane buton girişim var, ayrıca 3 adet reed röle girişim var. benim istediğim 1. butona basıldığında motor çalısacak, eğer 001 konumundaki röle çekikse ,buton gibi düşün(3 adet durdurma girişi oluyor) motor duracak. durum böyleyken butonlardan herhengi birisine basılırsa motor çalışacak hangi butona basıldıysa(ikinci,üçüncü) motor o kumdaki rölede tekrar duracak. olay buu . 6 adet giriş , 6 adet durma konumu .
    birinci röle 001=birinci konum
    ikinci röle 010=ikinci
    birinci ve ikinci röle 011=üçüncü
    üçüncü röle 100=….
    üçüncü ve birinci 101=…..
    üçüncü ve ikinci 110=….

    yazılım konusunda ccs de yazmaya calısıyorum devreyi proteusla hazırladım istersen fotoyu grup sayfanıza ekleyebılırm.
    bana yazılımda yardımcı olur musunuz

  19. Teknobakis says:

    Sitedeki konuyla alakalı dersleri incelerseniz kolaylıkla yaparsınız…

  20. ali says:

    merhabalar.
    benim sormak istediğim konu giriş çıkış portlarını
    set_tris_a(0b00001010);şeklinde ilk bakışta anlaşılır biçimde tanımlamak varken
    set_tris_b(0xf0);şeklinde yada set_tris_c(0×55);
    ilgili tablodan değerine bakmadan anlaşılmayacak şekilde yazılmasının avantajı nedir.
    neden csc de portlar ağırlıklı olarak set_tris_a(0b00001010);şeklinde değilde
    set_tris_c(0×55); şeklinde tanımlanıyor.avantajı nedir.

    birde void main(void)konusu kafamı karıştırıyor.bu komutu daha geniş açıklayabilirmisiniz.

  21. ali says:

    birde
    (0×55),(0xf0) bu kodların (0b00001010) bu şekil karşılık tablosunu nerden bulabilirim.

  22. esra says:

    slm ben ccs c yi yeni ögrenmeye basladım ve hocamız bi ödev verdi hiç birimiz yapamadık basit oldugu halde :) soru:puldown A0 butonuna 5 defa basıldıgında B0 pinindeki ledi yak.
    10 defa basıldıgında B1 deki ledi yakıp B0 dakini söndürsün.
    15 defa basıldıgında B portunu flash yapan bi program istedi yardım edermisinizzz..

  23. Emrah AYDIN says:

    sitede yeteri kadar kaynak var, kendin yaparsan senin için çok daha iyi olur. Yada en azından kendi yazdiğini paylaş bizimle.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>