![]() |
Pic C Detaylı Anlatimi |
![]() |
![]() |
#1 |
Prof. Dr. Sinsi
|
![]() Pic C Detaylı Anlatimi************************************************** ****** PIC C Derleyici Hi-TEch Pic C lite 8 ![]() ************************************************** ****** 1 ![]() C programlama dili günümüzde en yaygın olarak kullanılan programlama dillerinden biridir ![]() ![]() ![]() ![]() ![]() PIC mikrokontrolörler için yazılmış olan çok sayıda C derleyicileri bulunmaktadır ![]() ![]() Bu projede Hi-Tech firmasının ürünü olan ve oldukça popüler olan PICC Lite C derleyicisi kullanılmıştır ![]() 1 ![]() ![]() Hi-Tech firması tarafından geliştirilmiş olan ve ANSI C standardını izleyen bu C derleyicisi pek çok özelliklere sahip olup birçok endüstriyel uygulamalarda, öğretim ve öğrenim amaçlı, ve ayni zamanda elektronik hobi olarak kullanılmaktadır ![]() PICC Lite derleyicisi, yine ayni firmanın ürettiği ve pazarladığı PICC derleyicisine çok benzemekte olup, ücretsiz olduğu için bazı kısıtlamaları bulunur ![]() ![]() ![]() ![]() ![]() Bu bölümde, PICC Lite derleyicisinin özelliklerini ve bu derleyici ile C programı geliştirmeyi inceleyeceğiz ![]() 1 ![]() ![]() ![]() PICC Lite C derleyicisi aşağıda belirtilen veri çeşitlerini desteklemektedir ![]() ![]() ![]() bit unsigned char signed char unsigned int signed int long unsigned long float double Şimdi bu veri çeşitlerini örneklerle daha yakından inceleyelim ![]() 1 ![]() ![]() ![]() Bu veri çeşidinde sayılar Boolean (0 veya 1) olabilir ![]() ![]() bit flag; 1 ![]() ![]() ![]() Bu veri çeşidi ile 8 bitlik sayılar tanımlanır ve bu sayılar 0 ve 255 arasında değer alabilirler ![]() ![]() ![]() unsigned char q,a; q = 180; a=’R’; Burada dikkat edileceği gibi, C dilinde her satır noktalı-virgül (“;”) işareti ile bitmektedir ![]() ![]() 1 ![]() ![]() ![]() İşaret içeren bu veri tanımı, -128 ve +127 arasındaki sayıları tanımlamak için kullanılır ![]() signed char p,z; p = -50; z = 28; 1 ![]() ![]() ![]() Bu tanım ile 16 bit olan ve 0 ile 65535 arasında değişen sayılar tanımlanabilir ![]() unsigned int q; q = 915; x = 3000; 1 ![]() ![]() ![]() İşaret içeren ve 16 bitlik sayılar için kullanılan bu tanımda, sayının -32768 ve +32767 arasında olması gerekir ![]() signed int t; t = -500; 1 ![]() ![]() ![]() 32 bit ve işaret içeren sayılar için kullanılan bu tanımda sayının -2147483648 ve +2147483647 arasında olması gerekir ![]() long m; m = 200000; 1 ![]() ![]() ![]() 32 bit işaretsiz sayılar için kullanılan bu tanımda sayıların 0 ve 4294967295 arasında olması gerekir ![]() unsigned long k; k =2000000; 1 ![]() ![]() ![]() Bu tanım 24 veya 32 bitlik kayan nokta değişkenler için kullanılır ![]() ![]() ![]() ![]() float temp; temp = 1 ![]() 1 ![]() ![]() ![]() Bu tanımda sayılar 24 veya 32 bit olabilmektedir ![]() ![]() double sum; sum = 12 ![]() 1 ![]() ![]() C programlama dilinde değişkenlere tanım esnasında değer vermek mümkündür ![]() unsigned int temp = 10; unsigned char x = ‘A’; 1 ![]() ![]() İki tane öne eğik çizgiden (“//”) sonra yazılanlar derleyici tarafından öneme alınmamakta ve programın çalışmasını kolay anlamak için bu tip açıklayıcı yazılar tavsiye edilmektedir: i = 0; //i değişkenini sıfır yap j = j + 2; //j değişkenine 2 ilave et //şimdi iki sayıyı çarp // ve neticeyi sakla Açıklamaları bir diğer şekilde yazma formatı ise, açıklamayı “/*” karakterleri ile başlatmak ve “*/” karakterleri ile bitirmektir ![]() /* Bu program iki tane sayıyı toplar ![]() Sayılardan biri x, diğeri ise y dir ![]() Netice z de saklanir ![]() */ z = x + y; Herhangi bir programda her iki tanım şeklini de kullanmak mümkündür ![]() 1 ![]() ![]() PICC Lite C derleyicisinde değişkenler normal olarak RAM bellekte (genel maksatlı yazmaçlarda) saklanmaktadır ![]() ![]() ![]() Sabit bir değişkeni program belleğinde saklamak için önüne const komutu ilave edilmeli ve değişkenin değeri tanım esnasında belirtilmelidir ![]() ![]() ![]() int temp1 ; const int temp = 12; 1 ![]() ![]() Diziler (arrays) benzeri bir takım değişkenleri bir grup altında toplamak için kullanılırlar ![]() int sonuc[6]; Komutu Şekil 1 ![]() ![]() Şekil 1_1 Örneğin, sonuc[2] = 18 komutu sonuc dizisinin 4üncü elemanını 18 sayısına eşitler ![]() ![]() Bir dizinin elemanları RAM bellekte veya program belleğinde saklanabilirler ![]() ![]() ![]() ![]() const int temp[] = {1, 5, 9, 12, 45}; Aşağıdaki örnekte ise temp dizisi RAM bellekte 10 bayt tutar: int temp[] = {1, 5, 9, 12, 45}; C programlama dilinde string değişkenleri ASCII 0 ile sonlandırılan ve bir takım karakterler ihtiva eden dizilerdir ![]() char name[ ] = “Suzan”; Komutunda derleyici otomatik olarak name stringi için sonuncu karakteri ASCII 0 olan 6 karakter ayırır ![]() ![]() ![]() Diziler birden çok boyutlu olabilirler ![]() ![]() int temp[2][5]; Şekil 1_2 Burada temp, 3 sırası ve 5 sütunu olan bir dizi olarak düşünülebilir ![]() ![]() Örneğin, temp[0][1] = 10 komutu dizinin ikinci elemanını 10 sayısına eşitler ![]() Dizi elemanlarını tanım esnasında belirtmek mümkündür ![]() int temp[2] = {2,5,8}; 1 ![]() ![]() Program değişkenleri bir karakter veya alt çizgi (“_”) ile başlamalı ve bunu takiben istenilen miktarda karakter veya 0¬-9 arasında sayı kullanılmalıdır ![]() size toplam_miktar max5 _ortalama j ge2ci23ci a_b_c_d 1 ![]() ![]() Static değişkenler genel olarak bir fonksiyonda bulunan ve fonksiyonu her kullanışta değerleri değişmeyen değişkenlerdir ![]() ![]() ![]() ![]() 1 ![]() ![]() Volatile değişkenler, bir değişkenin her kullanıldığında eski değerini muhafaza edemeyeceği durumlarda kullanılır ![]() ![]() 1 ![]() ![]() Genel olarak PIC mikrokontrolör reset yapıldığında programda kullanılan bütün değişkenler ilk olarak sıfır değerini alırlar ![]() ![]() ![]() 1 ![]() ![]() Bir değişkenin ismi sonuna “@” karakteri konarak o değişkene bir mutlak adres değeri verilebilir ![]() unsigned char Portbit @ 0x06; Yukarıdaki satırda belleğin 6 ncı adresinde Portbit diye bir değişken tanımlanmıştır ![]() ![]() Portbit EQU 06h Bit veri çeşidi ve mutlak adres birleştirilip istenilen bir adresteki herhangi bir bit okunup değiştirilebilir ![]() ![]() static unsigned char STATUS @ 0x03; static bit PD @ (unsigned)&STATUS*8+3; Burada PD değişkeni bellekteki 27 nci biti (STATUS yazmacının 3 üncü biti) tanımlamıştır ![]() 1 ![]() ![]() Herhangi bir programlama dilinde operatörler son derece önem taşımaktadırlar ![]() ![]() Şekil 1_2_2 1 ![]() ![]() Program akışını değiştiren komutlar assembler dili de olmak üzere her programlama dilinde son derece önemlidirler ![]() ![]() if-else for while do goto break switch - case Şimdi bu komutların kullanımlarını daha yakından inceleyelim ![]() 1 ![]() ![]() ![]() Koşula bağlı olarak program akışını değiştiren bu komut genel olarak şu şekillerde kullanılabilir: if(koşul)komut; veya, if(koşul) { komut; komut; ……… ![]() ……… ![]() komut; } veya, if(koşul) { komut; komut; ……… ![]() } else { komut; komut; ……… ![]() } sadece bir komut içeren durumlarda şu şekilde de kullanılabilir: if(koşul) komut; else komut; Burada, komutlar sonunda noktalı-virgül işaretlerine dikkat ediniz ![]() Aşağıdaki örnekte, p değişkeni 0 ise b değişkeni 1 olarak artırılır, aksi halde b değişkenine 2 ilave edilir: if(p = = 0) b=b+1; else b=b+2; Yukarıdaki örnekte eşittir operatörü olan “= =” karakterlerinin kullanıldığına dikkat ediniz ![]() 1 ![]() ![]() ![]() for komutu program içerisinde döngü yapmak için kullanılır ![]() ![]() for(başla; koşul; artış)komut; veya, for(başla; koşul; artış) { komut; komut; ……… ![]() } burada, başla döngü değişkeninin ilk değerini, artış ise son değerini belirtmektedirler ![]() Aşağıdaki örnekte döngü değişkeni i, 1 den 10 a kadar gitmekte ve sayac değişkeni 10 defa artırılmaktadır ![]() for(i = 1 ; k = 10; i + + )sayac+ +; for komutunu kullanarak iç içe döngü yapmak mümkündür ![]() for(i=0; i<10; i+ +) { for(j=0; j<5; j+ +) { komut; ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() } } 1 ![]() ![]() ![]() Döngü yapmak için kullanılan bir başka komut da while komutu olup bu komutun genel kullanım şekli şu şekildedir: while(koşul)komut; veya, while(koşul) { komut; komut; ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() } Belirtilen koşul doğru olduğu müddetçe döngü devam etmektedir ![]() ![]() i=0; while(i < 10) { komut; komut; i++; } while komutunu kullanırken döngü içerisinde koşulun sağlanmasına dikkat etmemiz gerekir, aksi halde sonsuz bir döngü elde etmiş oluruz ![]() 1 ![]() ![]() ![]() Döngü yapmak için kullanılan bir diğer komut ise do komutudur ![]() ![]() do { komut; komut; …… ![]() ![]() }while(koşul); Aşağıdaki örnekte döngü değişkeni j, 0 dan 5 e kadar gitmekte ve döngü 5 defa tekrarlanmaktadır: j = 0; do { komut; komut; j++; }while < 5); while komutunu kullanırken döngü içerisinde koşulun sağlanmasına dikkat etmemiz gerekir, aksi halde sonsuz bir döngü elde etmiş oluruz ![]() ![]() 1 ![]() ![]() ![]() break komutu, bir döngü içerisinde ve döngü bitmeden, döngü dışına çıkmak için kullanılmaktadır ![]() ![]() while(i < 100) { komut; komut; if(j = = 10)break; } 1 ![]() ![]() ![]() Bu komut, çoklu if-else komutu gibi görev yapmaktadır ![]() ![]() Aşağıdaki örnekte, sec değişkeninde bulunan ve ‘A’ ve ‘F’ arasında olan 1-digit bir hexadecimal sayının decimal sayıya dönüştürülmesi gösterilmiştir ![]() Switch(sec) { Case’A’: hex = 65; break; Case’B’: hex = 66; break; Case’C’: hex = 67; break; Case’D’: hex = 68; break; Case’E’: hex = 69; break; Case’F’: hex = 70; break; default: hex = 0; break; } Burada, sec değişkeninin değeri ‘A’ ise hex değişkeni 65 olur, ‘B’' ise hex değişkeni 66 olur, ‘C’ ise hex değişkeni 67 olur v ![]() ![]() ![]() ![]() 1 ![]() Fonksiyonlar genel olarak bir program içerisinde kullanılan ve ana programdan bağımsız programdırlar ![]() ![]() ![]() ![]() void ledon() { led = 1; } Aşağıdaki ledon fonksiyonu ise ana programa integer bir bilgi aktarır: int ledon() { komut; komut; return(değişken); } Fonksiyonlar ana programdan bilgi alıp bu bilgiyi işler ve tekrar ana programa bilgi aktarabilirler ![]() int kare(int y) { int w; w = y*y; return (w) ; } Bu fonksiyon ana program tarafından şu şekilde kullanılabilir: s = kare(p); Kare fonksiyonu ana programdan p değişkeninin değerini alır ve bu sayının karesini alıp geri ana programa aktarır ![]() ![]() ![]() Burada önemli olan bir nokta, fonksiyonda kullanılan w ve y değişkenleri sadece fonksiyona ait olup ana programda olan bir w veya y değişkeni ile hiçbir ilgileri yoktur ![]() ![]() Örnek 3 ![]() Tabanı ve yüksekliği bilinen bir üçgenin alanını hesaplayan bir fonksiyon yazınız ve bulduğunuz alanı ana programa aktarınız ![]() Çözüm 3 ![]() Tabanı ve yüksekliği bilinen bir üçgenin alanı, olarak bulunabilir ![]() ![]() float alan(float taban, float yukseklık) { float i; i = (taban * yukseklik)/2; return(i) ; } Tabanın 23 ![]() ![]() hesap = alan(23 ![]() ![]() Burada, alan fonksiyon tarafından hesaplanır ve hesap diye adlandırılan bir değişkende saklanır ![]() ![]() 1 ![]() PICC Lite derleyici, diğer standart C derleyicilerde bulunan çeşitli ön-işlemci direktiflerini destekler ![]() ![]() 1 ![]() ![]() Bu direktif program başında kullanılır ve bir makro gibi çalışıp semboller yerine tanımlanan eşitlerini koyar ![]() Örneğin; #define size 10 #define max 100 #define min 0 program içerisinde bu semboller kullanıldığı zaman yerlerine otomatik olarak değerleri konur: a = 1; // a değişkenini 1 yap a = a + size; // a değişkeni 11 değerini alır define direktifi çok kompleks de olabilmektedir ![]() #define mult(a,b) 2*(a + b) Şimdi bu makronun bir program içerisinde kullanımına bakalım ![]() a = 2; // a değişkenini 2 yap b = 5; // b değişkenini 5 yap c = mult(a,b); // c değişkeni 2*(2+5)=14 olur Örnek 3 ![]() Bir integer 2 bayt’tan meydana gelmektedir ![]() ![]() Çözüm 3 ![]() Üst baytı almak için sayıyı 8 defa sağa kaydırabiliriz ![]() #define usfbayt(x) (unsigned char)(x>>Karizmatik olur ![]() ![]() #define altbayt(x) (unsigned char)(x & 0xFF) olur ![]() Örnek 3 ![]() Bir değişkenin herhangi bir bitini 1 veya 0 yapmak için “define” direktifini kullanarak bir makro yazınız ![]() Çözüm 3 ![]() Herhangi bir biti 1 yapmak için kullanacağımız makroya bit_set dersek, şu şekilde yazabiliriz: #define bit_set(var, bitno) ((var) │= (1<< (bitno))) Herhangi bir biti 0 yapmak için, kullanacağımız makroya bit_reset dersek, şu şekilde yazabiliriz: #define bit_reset(var, bitno) ((yar) &= ~(1<< (bitno))) Örneğin, x değişkeninin bit 3 ünü 1 yapmak için şu komutu kullanabiliriz: bit_set(x,3) ; Aynı şekilde, p değişkeninin 6 cı bitini 0 yapmak için şu komutu kullanabiliriz: bit_reset(p,6); 1 ![]() ![]() Bu direktifler sayesinde bir assembler programı, veya bir veya birkaç assembler komutları C programımıza ilave edilebilir: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() a=2; #asm movlw 10h #endasm ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Yukarıdaki programda görüleceği gibi assembler komutları #asm ve #endasm direktifleri arasına yerleştirilmelidir ![]() 1 ![]() ![]() Bu direktifi kullanarak başka bir text dosyasını programımız içerisine alabiliriz ![]() ![]() #include “myproject ![]() veya, #include <myproject ![]() PIC yazılımı geliştirirken <pic ![]() ![]() ![]() 1 ![]() PICC Lite derleyicisinin normal sayı tabanı 10 (desimal) olup birçok mikroişlemci ve mikrokontrolör uygulamalarında kullanılan sayı tabanının zaman zaman değiştirilmesi gerekmektedir ![]() ![]() Bir sayıyı hexadecimal olarak yazmak için önüne %x (veya %0X), octal olarak yazmak için önüne %o ve ikili tabanda yazmak için ise önüne 0b koymak gerekir ![]() toplam = %0x1f; // toplam = 0001 1111 sum = %o37; // sum = 011 111 a = 0b00001111 // a = 00001111 1 ![]() Yapılar, birbirleriyle ilgili olan çeşitli değişkenleri yeni bir değişken altında toplamak için kullanılır ![]() unsigned char adi[80]; unsigned char soyadi[80]; unsigned int yasi; unsigned char adresi[80]; Bir yapı (structure) kullanarak yukarıdaki tanımları şu şekilde yazabiliriz: struct sahsi { unsigned char adi[80]; unsigned char soyadi[80]; unsigned int yasi; urisigned char adresi[80]; } Bu durumda, sahsi yapısı bir şahıs hakkında olan bütün tanımları bir çatı altında toplamış olur ![]() ![]() ![]() Şimdi, aşağıdaki yeni tanımı yapabiliriz: struct sahsi benim_bilgiler; Yukarıdaki tanım ile benim_bilgiler yeni bir değişken olup bu değişkenin çeşidi sahsi’dir ve bu değişken bellekte yer tutar ![]() Benim_bilgiler ![]() Yapıları kullanarak bir değişkene istenilen sayıda bit ayırabiliriz ![]() ![]() struct flags { unsigned char x:1; unsigned char y:1; unsigned char z:6; } struct flags temp; 1 ![]() C programlama dilinde işaretçi kavramı çok geniş olarak kullanılmaktadır ![]() ![]() ![]() ![]() ![]() ![]() char *p; Burada p bir karakter işaretçisi olarak tanımlandığı halde şu an herhangi bir yerde kullanılmış değildir ![]() ![]() ![]() p = &z; p işaretçisi şimdi z değişkeninin adresini tutmaktadır ![]() ![]() *p = 3; Herhangi bir değişkenin adresine erişebilme birçok uygulamalarda çok kullanışlı olmaktadır ![]() ![]() İşaretçiler dizilerde çok kullanışlı olmaktadırlar ![]() ![]() ![]() char buffer[10]; // 10 elemanı olan bir buffer tanımlama char *p; // p bir karakter işaretçisidir p = buffer; // p işaretçiye buffer adresi yüklendi *p = 0; // buffer dizisinin ilk elemanını 0 yap p++; // p’yi artır (sonraki elemanı adresle) *p = 1; // buffer’in ikinci elemanını 1 yap Yukarıda da görüleceği gibi işaretçiler ile çeşitli aritmetik işlemler yapmak ve değişik adreslere gitmek mümkündür ![]() 1 ![]() Bazı PIC mikrokontrolörlerde (örneğin PIC16F84) EEPROM bellek bulunmaktadır ![]() ![]() EEPROM_WRITE(adres, veri) fonksiyonu belleğin adresine veriyi yazar ![]() ![]() EEPROM_READ(adres) fonksiyonu belleğin adresinden veri okur ![]() ![]() 1 ![]() PIC mikrokontrolörün konfigürasyon bitleri “_CONFIG(x)” komutunu kullanarak istenildiği gibi seçilebilir ![]() ![]() _CONFIG(WDTDIS & XT & UNPROTECT); PIC konfigürasyon bitlerini yonganın programlanması esnasında programlayıcı yazılımızla da istediğimiz gibi seçebiliriz ![]() muhendisforum ![]() |
![]() |
![]() |
|