15 Haziran 2015 Pazartesi

SDCC ile Butona Basıldığında Ledi Yakma (PIC16F877A) – Ders04



Bir önceki dersimizde basit şekilde led nasıl yakılır ve pic14, pic16 serisine mensup mikrodenetleyicilerin sigorta ayarlarının yapılmasındaki farkı anlamaya çalıştık. Aslında tek kelimelik bir farkmış :) Dikkat ettiyseniz derslerimizde bir tek işlemci üzerinden anlatımı yapmak yerine neredeyse her derste farklı bir işlemci ile örnek yapıyoruz. Esasında bu şekilde yapmak bayağı bir zorluyor insanı. Kitap yazarlarının neden tek mikrodenetleyiciye bağlı kitap yazdıklarını şimdi daha iyi anlıyorum. Benim farklı mikrodenetleyicileri seçmemin sebebi zaten bilinen led yak söndür, butona bas zıplasın örneklerini hemen hemen tüm kitaplarda birbirinin kopyası niteliğinde bulabiliyorsunuz. Bunları birde benim tekrarlamamda bir anlam yok. Bize bilinmeyen farklılıklar lazım. Sdcc ile ilgili Türkçe bilgi azlığından dolayı bende elimden geldiğince öğrenilmesi gereken farklılıklara dikkat çekip, yazı yazarken bir taraftanda kendime de öğretmek.

Bu dersimizde piyasanın en çok üzerine belki yazılıp çizilmiş mikrodenetleyicisi olan PIC16F877A yı kullanıp buton led yakma uygulaması yapacağız. Şunu artı bilgi olarak paylaşmak istiyorum; microchip firması PIC16F877 yerine PIC16887 yi önermekte. Bazı yerlerde iyileştirme yaptıklarından da bahsediğini duydum. Herneyse buda aklınızda bulunsun. Hem daha da ucuz.

Devre şemamızı ve mikrodenetleyici kodumuzu aşağıda vererek işe başlayalım.




























// Copyright (C) 2015 Durali Kiraz
// PIC16F877A için hazırlandı.

#define NO_BIT_DEFINES
#include <pic14regs.h> //Mikrodenetleyici Ayar adreslerini ve seçenekleri içerir
//#include <stdint.h> //uint16_t tanımı için gerekliydi. Şimdi ise tipi kendimiz tanımladık.

typedef unsigned short int uint16_t;

//sigorta tanımlarımızı yapıyoruz.
__code uint16_t __at _CONFIG __configword =
_FOSC_XT &&
_WDT_OFF &&
_BOREN_OFF && //Brown Out Reset (BOR) Disable
_LVP_OFF;

#define LED_PORT PORTBbits.RB0
#define BUTON PORTAbits.RA0
#define TRIS_A0 TRISAbits.TRISA0
#define TRIS_B0 TRISBbits.TRISB0


void main(void)
{
   ADCON1 = 0x07; //PortA yi dijital olarak yönlendirdik.
   TRIS_A0 = 1; //A0 giriş olarak seçildi.
   TRIS_B0 = 0; //B0 çıkış olarak seçildi.

   LED_PORT = 0; // LED sönük
   BUTON = 0; // Buton pasif
  
   while(1)
   {
      LED_PORT = BUTON;
   }

}


Bu koddaki birinci değişiklik tek bir adet uint16_t tipi için <stdint.h> başlık dosyasını koda ekleyip gereksiz bir kod şişkinliği yapıyorduk. Bunun yerine bu tipi bu ana kodun içinde tanımlayıp bizim için çok önemli olan microdenetleyici program hafızasından tasarruf etmiş olduk. Mikrodenetleyici programı yaparken bu hususa dikkat edilmediği takdirde daha yüksek hafızalı ve daha pahalı olan entegrelere para yatırmış olursunuz. Buda istenmeyen bir durumdur.

Yine dikkatinizi çektiği üzere sigorta ayarlarımızı kullanacağımız 16F877A aygıtına göre şekillendirdim. Bu konuda pic16F877a.h isimli dosyanın içine (/usr/local/share/sdcc/non-free/include/pic14 dizininden bulabilirsiniz) bir göz atmam gerekti. Buradaki osilatör ve sigorta tanımlarına ve açıklamalarına bakarak bu tanımlamayı kendi ihtiyacıma göre yaptım. Diğer derslerde belirtmediğim _BOREN_OFF && //Brown Out Reset (BOR) Disable Sigorta ayarı kısaca giriş voltajı eşik değerin altına indiğinde mikrodenetleyici kendini resetlemesin anlamında bir ayardır. Voltaj eşik değeri genelde +5 volttur. Diğer bir sigorta ayarı olan _FOSC_XT ile XT tipinde harici bir kristal osilatör kullanacağımı derleyiciye bildirdim. Eğer yüksek hızlı misal 20 MHZ lik bir osilatör kullandıysam devrede bu ayar _FOSC_HS şeklinde olması gerekirdi. Dikkat ettiyseniz bir önceki derslerde hep dahili osilatörle çalışmıştık. PIC16F877A nın dahili osilatörü olmadığı için bu örnekteki harici osilatör kullanma örneği bizim farkı anlamamız açısından önemlidir. Burada benim vermiş olduğum sigorta ayarları tamamen bir örnektir arkadaşlar. Siz kendi ihtiyacınıza göre kendi sigorta parametrelerinizi && işaretlerinin yanına ekleyerek oluşturacaksınız. Yoksa burada yazılan hersatır kural değildir.

#define LED_PORT PORTBbits.RB0” şeklinde ifade tanımlarımızın nasıl yapıldığını ve ne amaçla yapıldığını daha önceki derslerde zannedersem bahsettim. İsterseniz LED_PORT gibi bir ifade yerine program içinde PORTBbits.RB0 tanımını doğrudan kullanarak program yazabilirsiniz. Genelde biz kod okunaklığını daha iyi yapmak adına yeni bir sembol tanımlayıcı ile yani LED_PORT gibi bir isimler kullanırız. Dediğim gibi isterseniz kullanmayabilirsiniz.

Main ana fonksiyonumuzda sırasıyla
  • ADCON1 = 0x07;ile PORTA nın dijital olacağını (anolog olamayacağını),
  • TRIS_A0 = 1; ile A0 ın giriş için kullanılacağını
  • TRIS_B0 = 0; ile B0 in çıkış için kullanılacağını
  • LED_PORT = 0; ile led_port a lojik sıfır sinyali atadığımızı
  • BUTON = 0; ile butonumuzun basılı olmadığını yine lojik sıfır ile atamasını yapıyoruz.

Daha sonrasında while(1) işlem bloğumuz başlamakta. İsterseniz bu ifadenin yerine for(;;) şeklinde bir blok başlatabilirsiniz. Sonuçta iki ifadede sizin için sonsuz döngüyü başlatacaktır. Bu bloğumuzun için de sadece bir satırlık LED_PORT = BUTON; ifadesi var. Bu ifade LED_PORT içine BUTON ile tanımlı ifadenin sayısal değerini atar. Yani BUTON 1 ise LED_PORT' a lojik 1 yani 5 voltu gönderir. Dolayısıyla led eğer buton 1 ise yani basılı ise yanar. Eğer buton 0 ise yani basılı değilse ledimiz sönük olacaktır. Bu sonsuz döngü içerisindeki kod bloğumuz sonsuza kadar butona basılımı? Değilmi? Sorgulamasını yapıp led imize sonuç gönderecektir. Zaten bu koddan amaçlanan bu.

Bir sonraki derslerde daha iyi örneklerle buluşmak üzere hoşçakalın.



duralikiraz.blogspot.com
16 Haziraz 2015

Muvaffakiyet Allahtandır”

14 Haziran 2015 Pazar

SDCC ile Led Yakma (PIC16F628A) – Ders03


Bir önceki dersimizde belirli zaman aralıkları ile LED yakıp söndürme uygulamasını yapmıştık. Bu derstede çalışma olarak aynı diyebileceğimiz bir uygulamayı yapacağız. İki ders arasındaki tek fark sigorta ayarlarının pic16f628a ya göre yapılmış şeklini göreceğiz. Belki basit bir sigorta ayarı diyebilirsiniz ancak pic16F886 ile pic16F628A arasındaki sigorta ayarlarının aynı olmadığını öğrenmek benim yaklaşık 6 saatime mâloldu :) . Deneme yanılma yolu ile buldum diyebilirim. Tabi bendeniz bu işin uzmanı olmadığım için bir uzmana göre daha çok uğraştım. Siz uğraşmayasınız diye bu yazıyı kaleme alıyorum. Şimdi pic16F628A ya göre hazırlanmış devreyi ve yazılmış kodu bir görelim.

















// Copyright (C) 2015 Durali Kiraz
// PIC16F628A için hazırlandı.

#define NO_BIT_DEFINES
#include <pic14regs.h> //Mikrodenetleyici Ayar adreslerini ve seçenekleri içerir
#include <stdint.h> //uint16_t tanımı için gerekli

//Dahil osilatörü kullanacak ve osilatör portları giriş çıkış amaçlı kullanacağım
//Watch Dog Timer devredışı
//Düşük voltaj programlaması devre dışı.
// Bu ayarlanmış sigorta ayarlarının dışında kalanlar varsayılan ayarlar olacaktır.

__code uint16_t __at _CONFIG __configword = _INTRC_OSC_NOCLKOUT && _WDTE_OFF && _LVP_OFF;

//Not: Yukardaki sigorta ayarları pic16f628a ya özel oluşturuldu.

#define LED_PORT PORTBbits.RB0
#define LED_TRIS TRISBbits.TRISB0

// kalibrasyonsuz delay, sadece bir dizi döngü yinelemeleri için beklemeyi sağlar.
void delay(uint16_t milisaniye)
{
uint16_t i,j;
for (i = 0; i < milisaniye; i++)
{
// Döngüde optimizasyon için bu asm komutu eklenmiştir.
for (j=0; j < 4; j++)
__asm nop __endasm;
}
}

void main(void){

LED_TRIS = 0; // Pin çıkış olarak ayarlandı
LED_PORT = 0; // LED sönük
while(1)
{
LED_PORT = 1; // LED Yanıyor
delay(10000); // 1 sn bekle
LED_PORT = 0; // LED Sönük
delay(10000); // 1 sn bekle
}

}


Bu kodun diğer bir farkıda delay fonksiyonunda oldu. Bu mikrodenetleyicinin dahili osilatörünün hızından kaynaklı delay fonksiyonunda senkronizasyonu sağlamak için düzeltmeler yaptım. Isis programında yaptığım testte tâbi tuttuğumda gerçektende birer saniye aralıklarla yanıp söndüğünü gördüm.

Şimdi pic16886 ile pic16f628a mikrodenetleyicileri için fark arz eden sigorta ayarlarının yapıldığı satırlara göz atmaya :

PIC16F628A için:

__code uint16_t __at _CONFIG __configword = _INTRC_OSC_NOCLKOUT && _WDTE_OFF && _LVP_OFF;

PIC16F6886 için:

__code uint16_t __at (_CONFIG1) __configword = _INTRC_OSC_NOCLKOUT && _WDTE_OFF && _LVP_OFF;


Aslına bakarsanız çok bir fark yok. Sadece (_CONFIG1) ifadesini 16F628A mikrodenetleyicisi için derleyici kabul etmedi ve hata verdi. O yüzden deneme yanılmalar sonucu bu ifadenin yerine _CONFIG değişkenini kullanınca sorunu çözdüm. Bilmiyorum belki 16F628A için olan tanımlama diğeri içinde geçerli olabilir. Ancak böyle bir farkı gördüğümü sizlerle paylaşmak istedim. Muhtemelen başlık dosyasındaki tanımların uyuşmayışıyla alakalı olabilir. Gördüğünüz üzere kodun geri kalan kısmında fazla bir fark yok. Sdccman.pdf el kitabından okuduğuma göre pic14 yazılım mimarisi ile pic16 yazılım mimari arasında sdcc tarafından iyileştirmelerin yapıldığı ve pic16 tarafının daha iyi Ansi C uyumu sağlağı gibi şeylerden bahsetmekte. Zaten ileriki derslerde göreceğimiz üzere pic16 yani 18FXXXX piclerde sigorta tanımlarını #pragma önişlemci ifadesi ile daha iyi yapılabildiğini göreceğiz. Sdcc geliştiricileride 18F grubu piclerde eski tanımlama yerine #pragma önişlemci ifadesi ile yapılmasını tavsiye etmekteler. Şimdilik bununla kafanızı karıştırmayın. Bir sonraki derste görüşmek üzere Hoşçakalın.


duralikiraz.blogspot.com
15 Haziran 2015

Muvaffakiyet Allahtandır”