CCS-C ile PIC Programlama, Bit ve Byte İşlemleri Dahili Fonksiyonları

bit_clear()

Bir değişkenin istenilen Bit’ini Sıfır’lamak için kullanılır. Parametre olarak 8,16 veya 32 bitlik değişken alır. Geriyi değer döndürmeyen bu fonksiyonun kullanımı şu şekildedir.

bit_clear(degisken,BitNo)

1
2
3
4
5
6
7
8
9
int x;
long y;
int32 z;
x = 0x1f;
y = 0xa501;
z = 0x9c54a8;
bit_clear(x,0); // x'in 0. bitini sıfırla x= 0x1e olur
bit_clear(y,8); // y'nin 8. bitini sıfırla y = 0xa401 olur
bit_clear(z,31); // x'in 31. Bit'ini sıfırla x = 0x1c54a8 olur.

Bu fonksiyonun görevini yerine getirecek Ansi C uyumlu kod ise şu şekilde yazılabilir. degisken & = ~(1 << Bitno); x= 0x1f iken bit_clear(x,0) komutu x değerini 0x1e yapıyordu. Ansi C kodu ile yapalım x &= ~(1<<0); 1 sayısını 0 kez sola kaydırırsak yine bir olur, yani kaydırmıyoruz 🙂 0000 0001 (1 sayısı) ~ operatörü Bit düzeyinde değil işlevi görür. ~1 = 1111 1110 ( Bir ler 0, Sıfırlar 1 oluyor) x & = 1111 1110 = x & 1111 1110 x degerini ve 1111 1110 değerini alt alta yazıp & (And) ler isek 0001 1111  (0x1f) 1111 1110 0001 1110 (0x1e) değerine ulaşmış oluruz

Şöyle bir soru akla gelebilir, (1<;<;8) veya (1<;<;22) gibi bir işlemde 1 sayısı int olarak mı long olarak mı veya int32 olarak mı değerlendiriliyor. Cevap: CCS-C kullandığınız değişkene göre kendisi bunu otomatik ayarlıyor.  Şöyle bir örnek verelim;

1
2
3
long f;
f = 0xa501;
f &=~(1<<8); ifadesi için derleyici sadece BCF 3F.0 kodunu  oluşturur

f değişkeni 2 Byte olduğu için RAM’de 0x3e,03f adreslerinde saklanmaktadır. (Derleyicinin hangi değişkeni Hangi Adrese yerleştirdiğini öğrenmek için Compile Araç Çubuğundaki Symbol Map seçeneğine tıklayın)

1
2
3
f = 0xa501; ataması yapıldığında RAM Bölgesinde
Adres 3e = 0x01
Adres 3f = 0xa5 olur

F’nin 8. Bit’inin Sıfır’landığında 0xa5 değeri 0xa4 olacağı için asm oalrak BCF 3F.0 kodu doğrudur.

bit_set()

Bu fonksiyon bit_clear() fonksiyonun tersi işlem görür. Yani bir değişkenin istenilen Bit’inin değerini 1 yapmak için kullanılır.

bit_set(degisken,BitNo)

1
2
3
4
5
6
7
8
9
int x;
long y;
int32 z;
x = 0x1f;
y = 0xa501;
z = 0x9c54a8;
bit_clear(x,7); // x'in 7. bitini 1 yap x= 0x9f olur
bit_clear(y,2); // y'nin 2. bitini sıfırla y = 0xa401 olur
bit_clear(z,31); // x'in 31. Bit'ini sıfırla x = 0x0c54a8 olur.

Eşdeğer Kod

degisken |=(1<;<; BitNo); // Sağlamasını yapıp sonucu görün

bit_test()

Bir değişkenin istenilen Bit’inin durumunu sorgulamak için kullanılır. Sorgulanan Bit 1 ise geriye döndürülen değer 1, Sıfır ise geriye döndürülen değer 0 olur.

bit_test(degisken,BitNo)

degisken: 8 , 16 veya 32 Bit Integer Bitno: 0-31 arası değer (Kullandığınız değişken tipine göre)

1
2
3
4
5
6
7
int x;
int32 y;
BOOLEAN led;
if(bit_test(x,5)) // x'in 5. Biti 1 ise
if(!bit_test(x,5)) // x'in 5. Biti 0 ise
led = bit_test(y,26); //y'nin 26. Bit'i 1 ise led = 1 olur 0 ise led = 0 olur

Eşdeğer Kod

(1<<bitno)& degisken;<=”” strong=””>

Kullanım örneği

1
if((1<<5)&x) // x'in 5. bit'i 1 ise

 

rotate_left()

Bu fonksiyon bir değişkeni veya dizi değişkeni  sola döndürmek için kullanılır. Parametre olarak değişkenin adresi ve kaç Byte işlem yapılacağını alır. Geriye değer döndürmez

rotate_left(adres,byte)

adres: Hafıza bölgesi Byte: Döndürme işlemi Kaç byte üzerinden yapılacak

Döndürme İşlemi Nedir?

Hemen örnekle açıklayalım;

x = 0x81 olsun binary = 1000 0001 değerine karşılık gelir. x’i sola döndürmek şu demektir. En soldaki biti çıkar diğer bütün bit’leri 1 sola kaydır. Soldan çıkan Bit’i en sağa yerleştir. Yani kısaca en soldaki Bit’i al en sağa koy.

en soldaki biti alıp en sağa koyar isek yeni değer 0000 00011 olur. Hex olarak 0x03 değeri bulunur

1
2
int x = 0x81;
rotate_left(&x,1); //komutundan sonra x= 0x03 olur

&x = x değişkeninin adresi manasına gelir

1
2
long x=0xffaa;
rotate_left(x,2); // x = 0xff55 olur

 

rotate_right()

Bu fonksiyon ise sağa döndürme işlevi yapar. İşleyişi rotate_left() ile aynıdır sadece yön farklıdır. En sağdaki bit çıkarılıp en sola konur.

1
2
int x = 0x81;
rotate_right(&,1); //komutundan sonra x= 0xc0 olur

&x = x değişkeninin adresi

1
2
long x=0xffaa;
rotate_right(x,2); // x = 0x7fd5 olur

 

shift_left()

Sola kaydırma işlemlerinde kullanılan bu fonksiyonun kullanım şekli aşağıdaki gibidir.

shift_left(adres,bytes,deger)

adres: Ram hafıza bölgesi, yani değişkenin adresi bytes: İşlemin kaç Byte üzerinden yapılacak? data: 1 veya 0, kaydırma işlemiyle birlikte değişkene eklenecek bit

sola_kaydırma işleminde, en soldaki bit çıkarılıp diğer bitler sola kaydırılır. data parametresinde verilen değer en sağa eklenir.

Örnek verelim

 

1
2
int x= 0x81; // binary 1000 0001
shift_left(&;amp;amp;amp;x,1,1);

en soldaki biti atalım 0000001 olur en sağa da 1 koyalım 0000 0011 olur.

1
2
shift_left(&;amp;amp;amp;x,1,1) = 0x03 olur
shift_left(&;amp;amp;amp;x,1,0) = 0x02 olur  (soldaki bit atılıp en sağa 0 konulur)
1
2
int dizi[5];
shift_left(dizi,5,1); // 5 byte üzerindne işlem yapılır, dizinin ilk elmanının ilk biti 1 olur

Not: dizinin adı asresi yerine geçer bu yüzden başına &; simgesi konmaz.

Bu fonksiyonun geriye döndürdüğü değer en soldan atılan Bit’dir.

1
2
3
int1 test_bit;
int x=0x81 // binary = 1000 0001
test_bit = shift_left(&;amp;amp;amp;x,1,0)) // test_bit = 1 olur, en solda 1 vardı çünkü

 

shift_right()

Bu fonksiyonun çalışması aynı shift_left() gibidir, bunda yön sola doğru değil sağa doğrudur. En sağdaki bit çıkartılır en soldan verilen değer girilir.

1
2
3
int x = 0x81; // binary = 1000 0001
shift_right(&;amp;amp;amp;x,1,1) = 0xc0 (binary 1100 0000)
shift_right(&;amp;amp;amp;x,1,0) = 0x40 (binary 0100 0000)

 

make8()

make8() fonksiyonu 16 veya 32 bit değişkenlerden 8 bitlik değerler almak için kullanılır. Kullanımı şu şekildedir.

make8(degisken,offset)

degisken: 16 veya 32 Bit integer offset: 0-3 arası değer. (16 için 0-1, 32 için 0-3)

1
2
3
4
5
6
7
long x=0x1234;
long y = 0x12345678;
int sekizBit;
sekizBit = make8(x,1); //sekizBit = 0x12 olur
sekizBit = make8(x,0); //sekizBit = 0x34 olur
sekizBit = make8(y,3); //sekizBit = 0x12 olur
sekizBit = make8(y,1); //sekizBit = 0x56 olur

 

make16()

2 adet 8 Bitlik (1 Byte) değerden 16 bitlik (2 Byte) değer oluşturmak için kullanılır. Kullanılışı şu şekildedir;

make16(MSB,LSB);

MSB ve LSB 8 bit Integer

1
2
3
4
5
int x,y;
long z;
x = 0x55;
y = 0x aa;
z = make16(x,y); // z = 0x55aa olur.

 

make32()

Parametre olarak verilen 8 bit veya 16 Bit değerlerden 32 bit değer oluşturmak için kullanılır. Kullanılışı şu şekildedir;

make32(deger1,deger2,deger3,deger4)

Parametrelerin ikisi opsiyoneldir, degerlerin 1 kısmı 16 bir kısmı 8 bit olabilir

int x,y,z,t; long a,b; int32 c;

x = 0xd1; y= 0x12; z = 0x55; t=0xa9; a= 0xf301; b =b7c4;

c = make32 (x,y,z,t); // c = 0xd11255a9 olur c = make32(b,a) // c = 0xb7c4f301 olur c = make32(x,a); // c = 00d1f301 olur (değer 00 ile 32 bite tamamlanır)

 

_mul()

Çarpma işlemi oldukça fazla kod üreten bir işlemdir. Bu fonksiyon daha optimize çarpma işlemleri yapmak için kullanılır. Çarpılacak sayıları parametre olarak alır, çarpım sonucunu geri döndürür.

_mul(deger1,deger2)

deger1, deger2 çarpılacak sayılardır. Bu degerler 8 Bit veya 16 Bit olabilir. Her ikisi 8 Bit olduğunda geriye dönen değer 6 Bit diğer durumlarda 32 Bit’tir.

1
2
3
4
5
6
int x=10,y=100;
long z=500,sonuc1
int32 sonuc2;
sonuc1 = _mul(x,y); // sonuc1 = 1000 olur
sonuc2 = _mul(x,z); // sonuc2 =5000 olur

 

swap()

8 Bitlik 1 sayıda, 4 er bitlik her iki kısma “nibble” denmektedir. Yani 8 bitlik bir sayıda 2 adet nibble vardır. swap() fonksiyonu parametre olarak verilen sayının nibble’larının yerini değiştirir. Şöyleki;

1
2
int x=0xa5;
swap(x); // x = 0x5a olur.

Eşdeğer Kodu

x = (x<;<;4) | (x>;>;4) ;

#fuse

Bir önceki yazımızda kod örneklerinde kullandığımız halde açıklamamıştık. Haklı olarak bazı arkadaşlar sordular. Bizde  bu yazıda bahsedelim dedik.

PIC Mikro Denetleyicilerine Program yüklenirken, fuse denilen ayarlarında yüklenmesi gerekir. Bu ayarlar hex kodunu çipe yüklerken kullandığınız programda yapılabilir.  Siz kodunuzda bu yarları belirtirseniz çipe yazılımı yüklediğiniz programda bu ayarları yapmazsınız.

Fuse ayarları PIC modeline göre değişiklik göstermektedir.  CCS-C de View Menüsüne tıklayıp açılan kısımdan Valid Fuses butonuna basın. Açılacak olan pencerede istediğiniz PIC modelini seçin, o PIC için kullanabileceğiniz FUSE ayarları ekrana gelcektir.

PIC16F877 için FUSE ayarlarına Bakalım

XT: 4 Mhz veya 4 Mhz’den Küçük Kristal Osilatör HS: 4 Mhz’den Büyük Krsital Osilatör RC: Direnç / Kapasite Osilatörü Clock Out Var 4 mhz kristal kullanacaksanız #fuse XT daha büyük kullanacaksanız #fuse HS şeklinde ayarlamanız gerekiyor. NOWDT: WatcDog Timer Kapalı WDT: WathDog Timer Açık PUT: Power UP Timer açık NOPUT: Power UP Timer Kapalı PROTECT: Kod Okumaya Karşı Korumalı NOPROTECT: Kod Okumaya Karşı Korumasız PROTECT_50%: Kod Bölgesinin %50’si korumalı. BROWNOUT: Brown Out Koruması Aktif NOBROWNOUT: Brown Out Koruması Aktif Değil LVP: Düşük voltaj Programlama Açık NOLVP: Düşük voltaj Programlama Kapalı CPD: Data EEPROM Kod Korumalı NOCPD: Data EEPROM Kod Korumalı Değil WRT: Program Hafızası Yazma Korumalı NOWRT: Program Hafızası Yazma Korumalı Değil DEBUG: ICD debugger kullanılacak NODEBUG: ICD Debugger Kullanılmayacak

Fuse ayarlarının her birinin ne manaya geldiğini ayrıntılı olarak başka bir yazıda işleyeceğiz.

 

#use delay

CCS-C derleyicisinin 3 adet gecikme fonksiyonu vardır, bunlar delay_ms(), delay_us ve delay_cycles() fonksiyonlarıdır. Bu fonksiyonların düzgün çalışması için. İşlemcinin Saat Frekansı #use delay direktifi ile Derleyiciye bildirilir.

#use delay(clock = 20000000)  // İşlemci Çalışma Hızı 20 Mhz)

Eğer Watch-Dog Zamanlayıcısını kullanıyorsanız, gecikme fonksiyonlarında zamanlayıcının sıfırlanması gerekir. Bu gibi durumlarda #use_delay aşağıdaki gibi kullanılır

#use delay(clock = 20000000,restart_wdt) // 20 Mhz, watch-Dog sıfırla

PROTEUS PROJESİ İÇİN ÖRNEK KODLAR

Kodları simule etmek için bir önceki yazımızda verdiğimiz proteus projesini kullanabilirsiniz.

Örnek-1

B portundaki dip-switch’ler D portundaki Led’leri kontrol ediyor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <16f877.h>
#use delay(clock=4000000)
#fuses XT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
void main(void)
{
int PORTB,PORTD,i; // PORTB,PORTD ve i 8 bit integer
while(1)
{
PORTB = input_b(); // B portunu oku değeri PORTB'ye ata
PORTD = 0; // PORTD değişkeni sıfırlanıyor (PORT DEĞİL)
for(i=0;i<8;++i)  // 8 adımlık döngü, her adımda i bir artıyor
{
if(!bit_test(PORTB,i)) // PORTB in önce 0. biti test ediliyor
bit_set(PORTD,i); // bit 0 ise (switch = ON) PORTD ilk biti 0
// döngü sayesinde 8 bit kontrol edilir ve ayarlanır
}
output_d(PORTD); // PORTD değişkenini Porta yaz (Ledler)
}
}

Örnek-2

Aynı işi yapan başka bir kod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <16f877.h>
#use delay(clock=4000000)
#fuses XT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
void main(void)
{
int PORTB,PORTD,i;
while(1)
{
PORTB = input_b(); // B portu PORTB değişkenine okunuyor
PORTD = 0; //değişken sıfır'lanıyor
for(i=0;i<8;++i) // 8 adımlık döngü her adımda 1 artıyor i
{
//PORTB değişkeninin 8 biti PORTD değişkenine shift ediliyor
shift_left(&;amp;amp;amp;PORTD,1,bit_test(PORTB,i));
}
output_d(PORTD);  // değer LED'lere aktarılıyor
}
}

Örnek-3

Geçen yazımızda yaptığımız yürüyen ışık.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <16f877.h>
#use delay(clock=4000000)
#fuses XT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
void main(void)
{
int PORTB,PORTD,i;
PORTD = 0x01; // önce ilk ledi yakacağız
while(1)
{
output_d(PORTD);  // değeri ledlere aktar
delay_ms(250);
rotate_left(&;amp;amp;amp;PORTD,1); // bir biti devamlı döndürüyoruz
}
}

Örnek-3

Swap için örnek

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <16f877.h>
#use delay(clock=4000000)
#fuses XT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
void main(void)
{
int PORTB,PORTD,i;
PORTD = 0xf0; // Led'lerin sadece 4 tanesi yanacak
while(1)
{
// sırasıyla ledlerin ilk 4 ü yanar sonra ikinci dördü yanar
// daha sonra yine ilk dördü yanar.
// değer 0xf0 ve 0x0f arasında dönüşüm yapar sürekli
output_d(PORTD);
delay_ms(250);
swap(PORTD);
}
}

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir