Elektronik Devreler Projeler Elektronik ve biraz daha fazlası İletişim - Araçlar - Dikkat - Topluluk
Elektronik / Elektronik Kaynakları/

HI-TECH PIC C İle Program Derleme MPLAB IDE Kod Geliştirme

Sponsorlu Bağlantılar

Bu belgede genel olarak mikroişlemci ve mikrokontrolörlerin yapısından bahsedilerek Microchip firmasının ürettiği PIC16F84, PIC16F628 ve PIC16F877 mikrokontrolörleri üzerinde durulacaktır. Bu mikrokontrolörlerin C programlama dili ile programlanmasına ilişkin açıklamalar yapılacak ve PIC C anlatılacaktır. Yalnızca bu mikrokontrolörlerin anlatılmasına rağmen sonunda okuyucunun herhangi bir mikrokontrolörün veri kağıdına (datasheet) bakarak onu programlayabilmesi hedeflenmektedir.

Ancak; bu belgeyi okuyanların “C Programlama Dili” ve “Sayısal Devreler” konularında bilgi sahibi olduğu varsayılacak.

Bu belgede anlatılan kodlar HI-TECH PIC C derleyicisi ile derlenecek ve yine Microchip firmasının kullanıcılarına sunduğu MPLAB IDE editörü kullanılarak geliştirilecektir. Bu belgede aynı zamanda bu programların nasıl kullanılacağından kısaca bahsedilecektir. Bu programları şu adreslerden ücretsiz olarak indirebilirsiniz:

MPLAB IDE v. 7.60
http://ww1.microchip.com/downloads/en/DeviceDoc/mp760a.zip

HI-TECH PIC C Compiler
http://www.htsoft.com/downloads/ (üyelik gerekiyor)

Ayrıca yazdığımız programları Proteus ISIS adlı benzetim programında denememiz çok faydalı olacaktır.

Genel Tanımlamalar

Mikroişlemci ve mikrokontrolör kavramları sıkça karıştırılmakta ve birbirleri yerine kullanılmaktadırlar. Tabi ki bu iki kavram aynı yapıyı ifade etmez. Bu kavramları kısaca tanımlayacak olursak;

Mikroişlemci; kendisine gönderilen komutları işleyen çok küçük boyutlardaki bir sayısal devredir. Bu yapıyı bilgisayarımızdaki MİB ( Merkezi İşlemci Birimi ) olarak düşünebiliriz. MİB tek başına bir bilgisayarı oluşturamayacağına, dahası hiçbir işe yaramayacağına göre mikroişlemciler de tek başlarına kullanılamazlar. En azından bir bellek ve giriş/çıkış arabirimlerine ihtiyaç duyarlar. İşte bunlar ve hatta çok daha fazlası bir araya getirilerek tek başlarına uygulamalarda kullanılabilen sayısal devrelere mikrokontrolör denir. Mikrokontrolörler günümüzde kullandığımız hemen hemen bütün elektronik cihazların içinde bulunmaktadır.

Mikrokontrolörler, mikroişlemcilerin yanı sıra RAM, ROM, EPROM, EEPROM, Flash Bellek gibi bellek yapıları, G/Ç ( Giriş/Çıkış ) arabirimleri, analog-sayısal çeviriciler, zamanlama ve sayma birimleri, PWM çıkış modülleri, seri haberleşme portları, çeşitli kesme yapıları, vb. barındırırlar. Bu birimlerin düzenli ve bir arada çalışmasını sağlamak amacıyla ise “kütük” (register) denilen özel hafıza bölgelerinden yararlanılır. Yine bu birimlerde kullanılan ve kütükler üzerinde yer alan, çeşitli işlemler için izinleri ayarlayan ya da işlemlerin hangi aşamada olduklarını gösterebilen, yerine göre yazılım ya da donanım tarafından değiştirilebilen “bayrak” (flag) yapıları mevcuttur. Bu konular ile ilgili daha ayrıntılı bilgi ve örnek uygulamaları ilerleyen bölümlerde bulabileceksiniz.

Bu belgede mikroişlemcilerin devre şemalarından bahsedilmeyecek; ancak yine de mikrokontrolörlerin blok şeması halinde genel yapılarından bahsedilecek. Ayrıca çalışma mantığını anlayabilmek açısından elimizde olduğunu varsayacağımız mikroişlemcimiz ile kendi mikrokontrolörümüzün bellek yapısını tasarlayacağız.

Mikrokontrolörlerin Genel Yapısı

Mikrokontrolör yapıları çok çeşitlilik gösterebilmesine rağmen Şekil-1’deki gibi genel bir yapıdan bahsedilebilir.

mikrokontrolorlerin-genel-yapisi
Şekil 1. Bir mikrokontrolörün genel yapısı

Bu yapıda adres yolu, kontrol yolundaki işarete göre G/Ç arabiriminin hangi adresinin etkin olacağını ya da bellek bloğunun hangi gözlerine veri yazılacağını / okunacağını bildirir. Veri yolu da aynı şekilde kontrol yolundaki işarete bağlı olarak bellek bloğuna yazılacak / okunacak veriyi ya da G/Ç arabiriminden okunan ya da yazılan veriyi taşır. Mikroişlemcinin kelime uzunluğu ( bit sayısı ) bir seferde adres ve veri yollarında kaç bitlik veri taşınacağının ölçüsüdür. Örneğin yaygın olarak kullanılan ve birçoğumuzun bilgisayarında bulunan işlemciler 32 bitliktir ve bir seferde 32 bitlik veriyi ya da adres bilgisini taşıyabilir. Ancak bizim kullanacağımız uygulamalarda ve gerçek hayattaki pek çok uygulamada 8 bitlik mikrokontrolörler yeterli olacaktır.

Bu genel yapıdan bahsettikten sonra kendi mikrokontrolörümüzü tasarlayabiliriz. Burada sadece mikrokontrolörümüzün bellek yapısını tasarlayacağız.

Mikrokontrolörün Bellek Yapısı

Madem ki bir işe kalkıştık ve mikrokontrolörümüze bellek yapısı tasarlayacağız, öncelikle malzeme listemize bakmamız gerekir. Öncelikle belleğimizin boyutunu belirleyerek 8 bitlik bellek gözlerinden “a” adet satın aldık diyelim. Şimdi bu bellek gözlerini öyle yerleştirmeliyiz ki en az bit sayısıyla tüm bellek gözlerimize ulaşabilelim. Tahmin edileceği gibi bunu yapmanın tek yolu “a” sayısını birbirine en yakın çarpım şeklinde ayırmak. Bunlar da “m” ve “n” olsun. Yani “a=mxn”. Bundan sonra bu belleklerimiz öyle yerleştirmeliyiz ki her bir bellek sadece üzerinde bulunduğu satır ve sütundan ikisinden birden işaret geldiğinde etkinleşsin, aksi halde hiçbir tepki vermesin. Örneğin satırın 1. bacağına ve sütunun 2. bacağına işaret verdiğimizde 1.2 bellek gözü etkinleşsin.

Şekil 2’de yer alan yeşil alandaki gibi bir yapı elde ettiğimize göre şimdi bu satır ve sütunlara veri gönderme işine geldi sıra. Belleklerimin tamamına ulaşabilmemiz için n+m bitlik adres yolumuzun olması gerekir. Oysa bizim mikroişlemcimizin adres yolu sadece 8 bitlik ve 4 satır, 4 sütun için ayırırsak 4x4x8 = 128 bitlik belleğimiz olur. Ancak bu bellek bize yetecek gibi gözükmüyor. Tabi ki akla ilk gelen çözüm nasılsa aynı anda iki satıra ya da sutuna işaret gönderemeyeceğimize göre bir çözümleyici kullanabiliriz. Bu durumda 24x24x8=2048 bitlik belleğimiz olur. Büyük ihtimalle bu bellek de bize yeterli olmayacaktır. Bu durumda 8 bit ile önce satırlara, sonra sütunlara veri gönderebilecek bir yapı geliştirmemiz gerekecek. Bunu da 8 bitlik iki tutucu (latch) ile kolayca sağlayabiliriz. Bu durumda 28x28x8=524288bit=65536 baytlık bir belleğimiz olabilir. Ancak gerçekte, mikrokontrolörlerde bu kadar belleğe ihtiyaç olmayışından, farklı bellek yapıları kullanıldığından ve giriş/çıkış işlemleri için de adresleme yapmak gerektiğinden bu kadar bir belleğe rastlayamayız.

Artık her bir bellek gözüne ulaşabildiğimize göre ulaştığımız bellek gözünde okuma işlemi mi yoksa yazma işlemi mi yapacağımı bilmemiz gerekiyor. Bunu da veriyi bir önbellekte tutarak gelen kontrol işaretine göre hareket ederek yapabiliriz.

Artık yapının tasarımını tamamladığımıza göre yazma ya da okuma işlemi için hangi yolları izleyeceğimizi düşünebiliriz. Örneğin üzerinde çalıştığımız bellek gözü 1.2 olsun. Bu bellek gözü üzerinde yazma ve okuma işlemlerinin nasıl gerçekleşeceğini düşünelim:

1. Satır tutucusunu etkinleştirip sütun tutucusunu pasifleştirdik ( bunu LE (latch enable) bacağı ile yapabiliriz )
2. Satır çözümleyicisinin ilk bacağına işaret gönderecek olan 8 bitlik veriyi gönderiyoruz.
3. Sütun tutucusunu etkinleştirip satır tutucusunu pasifleştirdik
4. Sütun çözümleyicisinin ikinci bacağına işaret gönderecek olan 8 bitlik veriyi gönderiyoruz.

5. Yazma işlemi yapacaksak WE ( write enable ) bacağını etkinleştirip OE ( output enable ) bacağını pasifleştiriyoruz ve 8 bitlik verimizi veri yolundan yolluyoruz.

6. Okuma işlemi yapacaksak WE bacağını pasifleştirip OE bacağını etkinleştiriyoruz ve 8 bitlik verimizi veri yoluna yolluyoruz.

Ancak burada dikkat edilmesi gereken nokta bu işlemlerin tam olarak bu sırada yapılmalarının zorunlu olduğu. Bu uyumu sağlamak için ise hemen hemen tüm sayısal devrelerde kullanılan bir saat işareti mikroişlemciye uygulanır.

Neyse ki mikrokontrolörlerdeki kütük denilen özel bellek bölgeleri yukarıda saydığımız adımları bizim için yapıyorlar. Bizim tek yapmamız gereken kütüğün değerini değiştirmek olacak.

bir-mikrokontrolorun-calisma-sekline-bir-ornek
Şekil 2. Bir mikrokontrolörün çalışma şekline bir örnek

Bu işlemler sırasında önbelleğin CE ( chip enable ) bacağının neden kullanılmadığı merak edilebilir. Cevabı çok basit: gerçekte kimse bize 8 bitlik bellek gözleri satmaz. Yukarıdaki yapının bir bütün halinde paketlendiği RAM, ROM, EPROM ya da EEPROM gibi bellek yapılarını çeşitli amaçlar için bir araya getirerek bir bellek organizasyonu yaparız. İşte orada CE bacağı hangi bellek bloğunda işlem yapacağımıza bağlı olarak belleği etkinleştirir ya da pasifleştirir.

Giriş – Çıkış arabirimleri de aynı şekilde tasarlanabilir.

Kullanacağımız mikrokontrolörün veri kağıdına bakılırsa mikrokontrolörün mimarisi, bellek organizasyonu gibi ayrıntılar bulunabilir.

PIC Bağlama Şekli

Bir PIC Şekil 3’teki gibi bağlanılabilir. Burada PIC16F84A kullanılmıştır, ancak genel olarak tüm mikrokontrolörler bu şekilde bağlanabilir.

pic-baglama
Şekil 3. PIC Bağlama Şekli

Burada PIC’in OSC1 ve OSC2 bacaklarına saat darbesi üretecek olan kristali ve darbelerin sağlıklı olabilmesi için ise 33pF’lık iki kapasiteyi şekildeki gibi bağlıyoruz. Kapasite değerlerinin seçimine veri kağıdından bakabilirsiniz. PIC MCLR bacağında mantıksal “0” değerini gördüğünde resetlenir. Bunu engellemek için bu bacağı 10k’lık bir dirençle 5V’a bağlarız. Gerektiğinde resetleyebilmek için ise bir anahtarı şekildeki gibi bağlamamız yeterli olacaktır. Proteus ISIS adlı benzetim programı yukarıdaki bağlama şeklini gerçekleştirmesek bile PIC’i çalıştıracaktır. Bu nedenle bundan sonra PIC’e sadece işimizle ilgili elemanları bağlayacağız. Ayrıca bu programda gösterilmeyen besleme bacaklarını mutlaka bağlamamız gerekiyor. Burada VSS bacağı toprağa, VDD bacağı ise 5V’a bağlanır.

pic16f84-pic16f628-ve-pic16f877-icin-pin-diyagramlari
Şekil 4. PIC16F84, PIC16F628 ve PIC16F877 için Pin Diyagramları

İlk C Programı

İlk C programımızı yazmadan önce kullanacağımız yazılımları tanıtmakta fayda var. Giriş kısmında bahsettiğimiz MPLAB IDE ve HI-TECH PIC C derleyicisini kurduktan sonra Başlat>Tüm Programlar>HI-TECH Software>PICC>Configure for MPLAB 6 programını çalıştırarak MPLAB’ın C kodunu bu derleyici ile derlemesini sağlıyoruz. Bundan sonra MPLAB IDE programımızı çalıştırıyoruz. Burada Project>Project Wizard… programını çalıştırıyoruz. Çıkan ekranda “Next” tuşuna bastıktan sonra kullanacağımız PIC modelini seçiyoruz. Bundan sonra kullanacağımız derleyiciyi “PICC Compiler” olarak seçiyoruz. Bir daha ileriye gittiğimizde bize proje dosyamızı nerede yaratacağımız soruluyor. Burada dikkat edilmesi gereken nokta bu yerin “Masaüstü” ya da “Belgelerim” gibi uzun dizin isimli yerlerde olmaması. Programımız bu gibi konumlarda sorun çıkardığından “C:/projeler/ilk/” tarzı bir yerde tutmanız faydalı olacaktır. Bundan sonra karşınıza daha önceki projelerinizden şimdikilere hangi dosyaları aktaracağınızı soran bir pencere çıkacak. Bunu da ileri diyerek geçtiğinizde artık proje dosyanız yaratılmış olacak.
Projemizi yarattığımıza göre artık sabırsızlıkla beklediğimiz kod yazma işine başlayabiliriz. File>New ile yeni bir dosya yaratarak kodumuzu buraya yazıyoruz.

ilk.c

#include <pic.h> // PIC ile ilgili tüm adres tanımları bu dosyada

 

void main(void) {

TRISB = 0; // B portunu çıkış olarak tanımlıyoruz.

PORTB = 1; // B portunu 1 değerine getiriyoruz.

while(1); // Programımızın sonlanmaması için..

}

 

Yukarıdaki program B portunun 0. bacağına bağlanmış bir ledi yakan bir program. Satır satır açıklayacak olursak 1. satırda kütük ve bayrak adres bilgilerini tarayıcıya yüklüyoruz. 4. satırda PIC’in B portunu çıkış olarak ayarlıyoruz. 5. satırda ise B portuna “1” değerini gönderiyoruz. Bu değeri 8 bit biçiminde yazarsak “00000001” değeri B portunun 0. bacağına mantıksal “1”, diğer bacaklarına ise mantıksal “0” gönderildiğini ifade eder. Bilgisayar programlarından farklı olarak biz mikrokontrolör programının sonlanmasını istemeyiz. Bunu engellemek için mutlaka her programın sonuna sonsuz bir döngü eklemeliyiz.

Şimdi kodumuzu yazdığımıza göre artık dosyamızı kaydedebiliriz. Ancak dosyamızı kaydettikten sonra soldaki projemizin dosyalarının ağaç şeklinde güzüktüğü pencereye sağ tıklayarak “Add Files…” seçeneğini seçerek dosyamızı buraya yüklemeliyiz. Bundan sonra “Build All” tuşuna tıkladığımızda programımız derlenecek ve bir .HEX dosyası oluşacak. Bu dosyayı mikrokontrolörümüze attığımızda artık ilk programımızı çalıştırabiliriz.

ilk-programimizin-devre-semasi
Şekil 5. İlk programımızın devre şeması

PIC C Veri Çeşitleri

Veri Çeşidi Açıklama
bit Bir bitlik veri taşır. 0 ya da 1 olabilir
char 8 bitlik veri taşır. -127 ve +127 arasında değerler alabilir
unsigned char 8 bitlik veri taşır. 0 ve +255 arasında değerler alabilir
int 16 bitlik veri taşır. -32767 ve +32767 arasında değerler alabilir
unsigned int 16 bitlik veri taşır. 0 ve 65535 arasında değerler alabilir
long 32 bitlik veri taşır. -2147483647 ve +2147483647 arasında değerler alabilir
unsigned long 32 bitlik veri taşır. 0 ve +4294967295 arasında değerler alabilir.
float 24 veya 32 bitlik veri taşır
double 24 veya 32 bitlik veri taşır

Değişkenler mikrokontrolörde RAM’de tutulur. Ancak buradaki kaynakları etkin kullanmak gerektiğinden eğer değişkenimiz program boyunca değişmeyecekse tanımlamanın başına “const” ekleyerek bu değişkeni EEPROM ya da Flash bellekte tutmak yerinde olacaktır.

Fonksiyon her çağırıldığında değerinin değişmesini istemediğimiz değişkenler için yine tanımın başına “static” ekliyoruz.

Eğer resetleme esnasında bir değişkenimizin değerinin değişmesini istemiyorsak tanımın başına “persistent” yazmamız yeterli olacaktır.

Bir değişken sadece belli bir kod tarafından değil de bir kesme alt programı ya da donanım tarafından değiştirilebiliyorsa değişkenimizin başına “volatile” anahtar kelimesini ekleriz. Özellikle kütük adresleri tanımlanırken bu anahtar kelimenin kullanılması önemlidir.

PIC C’de değişkenleri 2’lik, 10’luk ve 16’lık sayı tabanlarında tanımlayabilirsiniz. Örnek vermek gerekirse bir x değişkeni için aşağıdaki örnekteki tüm eşitlemeler aynı değeri gösterecektir. Sayı tabanı kullanımı derleyici için hiçbir şey değiştirmeyecek ama kullanıcının sayıları rahat okuyup durumu anlayabilmesini kolaylaştıracaktır.

unsigned char x;

 

x = 158; // ondalık

x = 0x9E; // onaltılık

x = 0b10011110; // ikilik

 

PIC C’de Operatörler

Operatör Açıklama
() [] Parantez
! Mantıksal değil
~ Bit tersi
* İşaretçi operatörü
+ – * / Aritmetik operatörler
% Modül
++ 1 artır
1 eksilt
& Adres (önde kullanılırsa)
& Ve operatörü (iki değerin “ve”lenmiş halini döndürür)
| Veya operatörü (iki değerin “veya”lanmış halini döndürür)
^ Xor operatörü (iki değerin “xor”lanmış halini döndürür)
<< >> Kaydırma operatörleri
>= <= > < Karşılaştırma operatörleri
sizeof Boyut bulma operatörü
== Mantıksal eşittir
!= Mantıksal eşit değil
|| Mantıksal veya
&& Mantıksal ve
= Eşitleme operatörü
+= -= *= /= Eşitlik operatörleri
&= |= ^= Eşitlik operatörleri
%= >>= <<= Eşitlik operatörleri

Bazen C ile halledemeyeceğimiz durumlar ortaya çıkabilir. Bu tür durumlarda kodun istediğimiz yerinde assembly diline geçebiliriz. Örneğin “Bekçi Köpeği Zamanayıcısı”nın (Watchdog Timer) içeriğini sıfırlamaya yarayan “CLRWDT” komutunun işlevini C ile gerçekleştiremeyiz. Bu durumda aşağıdaki iki yöntemden biriyle assembly yazabiliriz:

PIC C’de “@” operatörü ile mikrokontrolörün mutlak adresini bir değişkene atayabiliriz. Örneğin PIC16F84 mikrokontrolörünün veri kağıdına bakarak PORTA kütüğünün “05h” (‘h’ hexadecimal anlamındadır) adresinde olduğunu öğrenebiliriz. Bu durumda aşağıdaki gibi bunu bir değişkene atayabiliriz:

Hazırlayan: Ufuk Sevim – Emeği geçen hazırlayan kişilere teşekkürler yukarıda özetler verildi anlatımın tamamı: hi-tech-pic-c-ile-program-derleme-mplab-ide-kod-gelistirme.RAR alternatif link2 alternatif link3

  • Mustafa

    The selected compiler: “PCM” is not installed on this PC

    bu hatayı alıyorum nasıl çözebilirim acaba?