PIC Programlama – 10 – EEPROM

Merhabalar, doktora yeterlik sınavı dolayısıyla ara verdiğim blog yazılarıma, yeterlik aşamasını geçtiğimden dolayı devam ediyorum 😀 PIC16F84A ile ilgili, geriye kalan son bir iki konuyu da irdeleyeceğimiz bu yazıda, ana gündemimiz EEPROM olacak.

“EEPROM nedir?” sorusuna yanıt arayanlar için WIKIPEDIA sayfasında yeterli bilgi olduğunu belirtmek isterim. Kısaca özetlemek gerekirse EEPROM, elektriksel olarak yazılıp silinebilen, kalıcı bir bellek tipi; yani elektrik gitse de içerisinde kayıtlı olan veri kendiliğinden silinmiyor. Flash belleğe göre yazım ömrünün çok fazla olması, bu devre elemanını bu gün dahi popüler tutmaya yetiyor.

PIC16F84A içinde de 64 byte’lık bir EEPROM bulunuyor. 64 byte kadar küçük bir EEPROM olsa da, özellikle kalıcı konfigürasyonları saklama konusunda, bu modül hayat kurtarıyor. Bu durumda bize düşen de, PIC16FLIB adıyla geliştirdiğimiz alternatif PIC kütüphanesine bu modülü de eklemek olacak. Öyleyse hemen başlayalım!

İlk adım olarak, her zamanki gibi datasheet’i okuyup anlayarak, yazılımsal olarak modelleyeceğiz. Datasheet’te EEPROM modülü, sistemin blok diyagramında şöyle yer alıyor:

PIC16F84A veri kağıdından alınmıştır.

Buradan da görüldüğü gibi EEPROM modülümüz 64*8 bitlik veriyi saklayabiliyor. Şimdi de, EEPROM ile ilgili kütüklerin (register), hangi adreslerde olduğuna bakalım.

İlgili kütükleri fosforlu sarı ile işaretlediğimden adreslerini görebilirsiniz. Artık adreslerini ve yapılarını da bildiğimizden, bu kütükleri yazdığımız PIC kütüphanesine ekleyebiliriz. EEPROM modülünü de derlemeye dahil edip etmemeyi seçimli yapmak için işe pic16flib_conf.h dosyasına aşağıdaki işaretli satırı ekleyerek başlıyoruz.

Şimdi pic16f84a_lib.h içerisindeki kütük tanımlamalarına geçelim. Aşağıdaki işaretli satırları pic16f84a_lib.h dosyasına ekliyoruz.

Register tanımlarını nasıl yaptığımızı daha önceki yazılarda çokça açıkladığımdan bu defa tekrara düşmemek adına açıklamayacağım. Her zamanki gibi, veri kağıdındaki bilgileri modelleyerek kütük tanımlarını yaptık.

Şimdi gelelim eeprom’dan veri okuma ve eeprom’a veri yazma fonksiyonlarına. Onları da aşağıda görebilirsiniz:

Her iki fonksiyon girişinde de, girilen adresin 63 değerinden büyük olup olmadığını kontrol ettik. Toplamda 64 byte’lık bir eeprom’umuz olduğundan, en yüksek adres 63 oluyor. Ardından okuma yapmak için, okuma yapacağımız adresi seçtik. Sonrasında RD bitini 1 yaparak okumayı başlattık ve okunan değeri REG_EEDATA kütüğünden okuduk.

Yazma kısmında ise işler biraz daha karışık şekilde çözülüyor. Yine adres seçimini yaptıktan sonra ilk iş olarak yazmak istediğimiz veriyi REG_EEDATA kütüğüne yazıyoruz. Ardından WREN bitini 1 yaparak yazma izni vermiş oluyoruz. Sonrasında, veri kağıdından okuduğumuza göre EECON2 kütüğüne sırasıyla 0x55 ve 0xAA yazmak gerekiyor. Bu, koruma amaçlı konmuş ve veri kağıdına üretici tarafından yazılmış bir ek sekans 🙂 Kodu yazan ne yaptığını biliyorsa, ancak o zaman yazabilsin demişler. Saygımız sonsuz 😉 Ardından WR bitini 1 yaparak yazım sürecini başlatıyoruz. Yazım hemen bitmiyor; bu durumda yazımın bittiğini anlayabilmek için tek çaremiz EEI (eeproma veri yazıldı) kesmesini kurarak, kesme bayrağı 1 olana kadar beklemek. Burada bekleme işini asm(“nop”); satırı ile yaptık. asm(KOMUT) fonksiyonu, XC8 derleycilerinde C kodunun içerisnde assembly komutları çağırmaya yarar. Biz de “nop” yani “bir şey yapmadan 1 saat darbesi bekle” komutunu çalıştırarak bekleme sağladık. Ardından kesme bayrağı 1 olup while döngüsünden çıktığımızda kesmeyi kapatıp, kesme bayrağını temizleyip, WREN kütüğünü sıfara çekerek çıkıp gidiyoruz 🙂 Verimiz yazıldı.

Dikkat! Burada while döngüsü sonsuza kadar sürebilir. Bunu engellemek için while içinde bir değişkeni her turda 1 artırıp, döngü sayısı bir üst sınır değerini geçerse ve yazım işlemi hala bitmemişse hata döndürerek çıkmasını sağlamakta fayda vardır.

Yukarıdaki fonksiyonların eklendiği durumda pic16f84a_lib.c dosyamız şöyle oluyor:

Artık kütüphanemiz hazır olduğuna göre, basit bir test fonksiyonu yazacağız. 0x01 adresli EEPROM bellek alanına 1 byte’lık ‘X’ karakterini yazan ve doğru yazıp yazmadığını kontrol eden bir kod, aşağıda yer almakta.

Bu kodumuz, yazım ve okuma işlemleri başarılı ise B portuna 0xAA yazıyor. Eğer hata olursa B portu ilk değeri olan 0x00 değerinde kalıyor. B portuna 0xAA=10101010 değerinin yazılması, sırasıyla pinlerin yüksekte ve alçakta olmasına sebep oluyor.

Kodda bir diğer önemli kısım ise #pragma ile başlayan konfigürasyon satırları. Buna göre osilatör olarak kristal osilatör seçmiş olduk. Ayrıca, mikrokontrolörün donup kaldığı durumlarda ona reset atacak olan watchdog timer modülünü aktive ettik. Yine güç dalgalanmalarında reset atmaya yarayan power on reset’i aktive ettik ve kod korumayı kapattık. Kod koruma açık olarak mikrokontrolöre yazılım atarsanız, o kod bir daha okunamayacak ve kolaylıkla değiştirilemeyecektir. Prototip aşamasında CP (code protection, kod koruma) seçeneğini OFF yapınız (varsayılan değer de budur).

Bu kodun çalıştığı duruma ilişkin Proteus ISIS simülasyon çıktısı ise aşağıda yer alıyor.

Gördüğünüz gibi, EEPROM sürücümüz de başarıyla çalışıyor 🙂

Projenin kaynak kodlarını BURADAN indirebilirsiniz.

Bu günlük de bu kadar. İleride yeni yazılarla devam edeceğiz.

Yazıları beğendiyseniz, faydalanabilecek tanıdıklarınızla paylaşmayı unutmayınız.

Önceki Sayfa   Sonraki Sayfa

PIC Programlama – 9 – Zamanlayıcılar (Timers) 2

Merhabalar, görece uzunca bir aradan sonra yazılarımıza kaldığımız yerden devam ediyoruz. Önceki yazıda tam da bir takım soru işaretleri bırakarak ayrılmıştık. Gün, bunların olabildiğince yanıtlanacağı gündür.

Öncelikle şu 1.06ms meselesinin çözümünü ve cevabını verelim. Evet efendim, kodumuzda yaptığımız tek satırlık bir modifikasyon ile özlenen tabloyu öncelikle kamu huzuruna sunalım.

1.00 ms zamanlayıcı çıktısı

Gördüğünüz üzere tam 1.00 ms’lik çıktıyı yakaladık. Tabi burada tam’dan kasıt, mikrosaniye mertebesindeki ölçüme ithafen bir tamlık. Neyse, şimdi hemen ilk aşamada bu uygulamanın kodlarını paylaşalım.

Kütüphanemiz yine aynı, orada bir değişikliğe ihtiyaç yok. Şimdi burada neyin değiştiğini ve neden değiştiğini açıklayalım. Bir önceki yazıdaki koddan farklı olan tek satır şu:

Bu değerin normal şartlar altında 125 olması gerektiğini açıklamıştık. Ancak gelgelelim kesme fonksiyonu içinde yazdığımız kodlar, ister istemez bir miktar gecikmeye neden oluyor. Bu sebeple bu gecikmeyi tolere edemiyorsak, timer0’a yüklenecek değeri kalibre etmemiz elzem oluyor. Denemeler ile görüyoruz ki kesme fonksiyondaki kodlarımız 7 timer0 cycle kadar bir gecikmeyi doğuruyor. Bunu kompanze etmek için 125 cycle yerine 118 cycle saydığımızda tam 1.o0 ms’lik bir zamanlama elde ediyoruz. Tabi ki bu süreç yalnızca PIC gibi çok kısıtlı kaynaklı ve görece yavaş ortamlarda yaşanıyor. Örneğin ARM Cortex M3-M4 gibi platformlarda bu süreler ihmal edilecek kadar kısalır ve böyle bir istisnai kodlama yapmanız gerekmez. Yine uygulamanız zaman kritik değilse, böyle bir istisnai kodlamaya ihtiyaç duymazsınız. Ama yine de bu önemli konuyu akılda tutmakta fayda var 🙂

Şimdi, önceki yazıdaki defteri kapattığımıza göre bu yazının esas konusuna gelebiliriz. Bu yazımızda zamanlayıcıların bir başka önemli kullanım alanına değineceğiz: PWM (Pulse Width Modulation). Nedir efendim PWM? Çevirisini yapacak olursak dalga genişliği modülasyonudur. PWM’in ne olduğu detaylıca ŞURADA anlatıldığından daha fazla açıklama yapmaya gerek duymuyorum.

Çoğu mikrokontrolörde, zamanlayıcılar üzerinde çalışan PWM modülleri donanımsal olarak bulunur. PIC’in bazı modellerinde de bu imkan sağlanmış. Onların kullanımına da elbet değineceğiz ama daha önemlisi donanımsal PWM modülü olmasa da bu modülasyonu nasıl gerçekleyebileceğimiz. Bu yazıda zamanlayıcı kullanarak PWM gerçekleyeceğiz.

Zamanlayıcılar ve GPIO ile PWM

PWM dediğimiz nane sayısız işe yarıyor. Örneğin bir motorun dönüş hızını, bir LED’in ışık şiddetini ve daha bir çok benzer şeyi PWM ile yapabiliyoruz. PWM, işaretin etkin değerini değiştirmeye yönelik bir modülasyon olduğundan, fiziksel çıktı farketmeksizin “şiddet ayarlama” işini yapar. Ne demek istiyorum?

  • Bir motoru sabit 5V ile beslediğinizde o motor 5 birim hızla dönüyorsa, o motoru sabit 2.5V ile beslediğinizde motor 2.5 birim hızla döner.
  • Bir LED’i sabit 5V ile beslediğinizde o LED 5 birim ışık şiddeti ile yanıyorsa, o LED’i sabit 2.5V ile beslediğinizde LED 2.5 birim ışık şiddeti ile yanar.
  • Bir buzzer’ı sabit 5V ile beslediğinizde o buzzer 5 birim şiddetle ses çıkarıyorsa, o buzzer’ı sabit 2.5V ile beslediğinizde buzzer 2.5 birim şiddetle ses çıkarır.

Yani çıktının fiziksel şekli farketmeksizin, genelde bu iş böyle yürür. Gelgelelim biz dijital dünyada öyle kolay kolay 2.5V veremiyoruz. Bunun yerine işareti zamanda modüle ederek işimizi görmek istiyoruz. Nasıl yani?

Yani elinizde olan yalnızca 5V ise, bundan 2.5V etkin gerilim değeri elde etmenin başka bir yolu var. 1ms süreyle 5V, 1ms süreyle 0V verip bunu sürekli tekrarlarsanız bu işaretin etkin gerilim değeri (5V*1ms +0V*1ms)/2ms = 2.5V olur. 5V lojik 1, 0V lojik 0 olduğundan ve işaret zamanın %50sinde lojik 1 değerini aldığından bu işarete %50 PWM denir.

Benzer şekilde  8ms süreyle 5V, 2ms süreyle 0V verip bunu sürekli tekrarlarsanız bu işaretin etkin gerilim değeri  (5V*8ms + 0V*2ms) /10ms= 4V olur. Hesap açık efendim. Zamanın %80’inde işaret lojik 1 değerini aldığından bu işarete %80 PWM denir. PWM’de işaretin 1 olduğu zamana duty cycle denir. Tekrar eden toplam zaman, periyottur ve burada işaretin periyodu 10ms’dir. Frekans = (1 / Periyot[sn]) olduğundan burada frekans 1/10[ms] = 1/0.01[sn] = 100 Hz olur.   Periyot ve duty cycle kontrol edilerek dalga genişliği modülasyonu (PWM) yapılabilir.

PWM’i anlatmaya gerek yok dedim ama anlatmadan da duramadım. Şimdi lafı bırakıp icraate geçelim. Peki ne yapacağız, PWM’in %1’lik çözünürlükle kontrol edilebildiği bir uygulama yazalım.

Kütüphanemizde bir değişiklik yapmaksızın main.c dosyamızı aşağıdaki gibi yazarsak olay tamam oluyor.

Ve bu şirin mi şirin ama bir o kadar da acımasız kodun çıktısı aşağıdaki gibi oluyor.

%50 PWM

Gördüğünüz üzere periyodu ~100ms olan %50’lik bir PWM işareti elde etmiş olduk. Gelin şimdi %25’lik PWM elde etmek için ne yapmamız gerektiğini görelim.

Yalnızca şu satırı değiştirmek yeterli:

Bu durumda simülasyon çıktısı da aşağıdaki gibi oluyor.

%25 PWM

Her iki çıktıda da periyodun 100ms olduğuna yani frekansın 10Hz olduğuna dikkat ediniz. PWM frekansını örneğin 20HZ yapmak için aşağıdaki değişikliği yapmanız yeterli.

Bu değişiklik ile zamanlayıcının birim zamanını 1ms’den 0.5ms’ye düşürdük. Bu da frekansı iki katına çıkardı.

Bu uygulama ile artık bir motorun hızını kontrol etmek mümkün. Robotçu arkadaşlar varsa bu kısım faydalı olacaktır diye düşünüyorum.

Projenin kaynak kodlarını BURADAN indirebilirsiniz.

Bu günlük de bu kadar. İleride yeni ibretlerle ve yeni yazılarla devam edeceğiz.

Yazıları beğendiyseniz, faydalanabilecek tanıdıklarınızla paylaşmayı unutmayınız.

Önceki Sayfa   Sonraki Sayfa

PIC Programlama – 8 – Zamanlayıcılar (Timers)

Merhabalar, geçen yazımızda kesmeler üzerine oldukça marjinal bazı çalışmalar yapmıştık. Şu ana kadar PIC mikrokontrolörün giriş çıkış ünitelerini, kesmeleri de içerecek şekilde evire çevire kullanabilecek bilgi birikimini edindik. Tabi bu bahsettiğimiz konu, işin bahanesiydi. Asıl amacımız, tüm mikrokontrolörlerde kullanabileceğimiz bir modelleme ve geliştirme altyapısını tahsis etmekti. Buna istinaden yaptığımız en orijinal iş, Microchip firmasının sunduğu kütüphanelerden performans, estetik, yazılım kalitesi, taşınabilirlik ve geliştirilebilirlik bakımından çok daha iyi bir kütüphane oluşturmak oldu. Mikrokontrolör’ün veri kağıdını nasıl modelleyeceğimizi gördüğümüzden aynı işlemleri herhangi bir başka platform için yapmak sorun olmayacaktır.

Dış dünyaya mikrokontrolörün I/O pinleri üzerinden müdahale edebildiğimizden bir sonraki adıma geçmenin sırası geldi. Bir sonraki adım şüphesiz ki periyodik işlerle nasıl başa çıkabileceğimizi bulmak olacak. Güncel durumda yazdığımız kodlar ömürleri boyunca aynı işi aralıksız olarak yaptılar. Oysa gerçek hayattaki pek çok uygulamada gerçekleşmesi gereken zamanda ve periyodik gerçekleştirilmesi gereken olaylar görürüz. Periyodik yapılan işlerden ilk akla gelen örneklemedir. Nyquist amcamızın da yıllar önce ortaya koyduğu gibi, bir işareti doğru zamanlama ile örneklemezsek o işaretin taşıdığı bilgiyi kaybetmiş olabiliyoruz.  Biraz daha net şekilde açıklamak gerekirse:

Sosyal Mesaj
Nyquist örnekleme frekansı, bir işaretin örneklenmesi sürecinde tanımlanan bir alt limittir ve bu limit işaretin içerdiği maksimum frekans bileşeninin iki katıdır. Eğer işaret maksimum frekans bileşeninin iki katından  – ki bu frekans Nyquist frekansı oluyor – daha az bir frekansla örneklenirse o işaret, ölçümlerden düzgünce tekrar üretilemez çünkü örnekleme esnasında bilgi kaybı yaşanmış olur.

Sonuç olarak, mikrokontrolörde zamanı ölçmenin bir yolunun olması gerekiyor. İşte bu noktada devreye Timer (Zamanlayıcı) modülleri giriyor. Ancak zamanlayıcılara geçmeden önce, zamanlama sorununa sunduğumuz en basit çözümü hatırlayalım. BURADAKİ yazımızda, DummyDelayMs fonksiyonun kurnazca tanımlayarak milisaniye mertebesinde bir zamanlama sağlamıştık. Hemen implementasyonu hatırlayalım.

Gördüğünüz gibi bu kodda, mikrokontrolöre boş beleş sayı saydırıp, geçen zamandan faydalandık. Tersten giderek, 1ms beklemek için gerekli olan sayma sayısını hesaplayıp, mikrokontrolörün o kadar boş beleş (dummy) işlem yapmasını sağladık. Bu da adeta bir araçta vitesi boşa atıp gaza sonuna kadar basmaya benziyor. Bir yere gitmiyoruz ama cayır cayır benzin yakıyoruz 🙂 İşte bunu yapmamak için Timer modülü var.

Bizim bu zamana kadar çalıştığımız PIC16F84A’da ne yazık ki tek bir zamanlayıcı modülü var. Ancak diğer modellerde daha fazla sayıda zamanlayıcı modülü mevcut. Unutmamak gerekir ki zamanlayıcılar gömülü sistemlerde “elzem” olduğundan, hemen her mikrokontrolörde zamanlayıcı bulunur. Şimdi hemen bir tablo ile hangi PIC’te hangi zamanlayıcı var görelim.

Zamanlayıcı PIC16F8X PIC16F62X PIC16F877
Timer0 + + +
Timer1 + +
Timer2 + +

Bu arada hemen araya sıkıştırayım; zamanlayıcıları da bitirince artık daha gelişmiş PIC modelleri üzerinden devam etmemizde bir sakınca kalmayacak. O nedenle yavaştan diğerlerine de geçebiliriz. Şimdi Timer0’ın hakkından gelelim 😉

TIMER 0

Timer0 kardeşimiz, 8-bit’lik bir zamanlayıcı/sayıcı olarak tasarlanmış olup, doğal olarak 0’dan 255’e kadar sayabilmektedir. Yine bu efendi kardeşimizin sayacını okumak da sayacına yazmak da mümkündür; bu da bize zamanlayı istediğimiz değerden başlatma ve güncel değeri okuma imkanları sunar.

Zamanlayıcı, esasında; herhangi bir saat işaretini (clock pulse) alıp o işareti çeşitli ön işlemlerle örnekleyerek sayan bir devreciktir. Buna istinaden söz konusu saat işareti dışarıdaki bir osilatörden (Ring osilatör) ya da iç osilatörden (RC osilatör) alınabilmektedir.

Bu zamanlayıcılar 255’e kadar sayabildiğinden 255’ten sonraki sayımda taşma olur yani değer tekrar 0’a döner. Bu anda kesme kurmak mümkündür. Bu da zamanlayıcı kesmesi olarak adlandırılmaktadır.

Timer0 ile alakası olan kütükler, mikrodoentleyicinin veri kağıdında açıkça belirtilmiştir. Buna göre OPTION_REG, INTCON_REG, TMR0_REG, TMR0_REG ve inanmazsınız TRISA/PORTA kütükleri Timer0 ile ilintili imiş. Bunların her birini didik didik ederek zamanlayıcıların suyunu çıkaracağız. Tabi ki yapacağımız ilk iş, henüz modellemediğimiz kütükleri modelleyerek kütüphanemize eklemek olacak.

Tüm bunlara ek olarak, kütüphanemizi yine adım adım optimize etmeye devam edeceğiz. Burada yine tasarım trade-off”larını tartışacağız ve yeni eksikleri hep birlikte tespit edeceğiz 🙂 Öyleyse işe koyulalım ve TIMER0 ile ilk periyodik fonksiyonumuza hayat verelim!

Malumunuz her yazıda yeni kesme değerlendirme rutinleri, yeni veri yapıları ekliyoruz. Bunları her uygulamada kullanmayacağımızdan, bu uygulamalarda biraz bellek israfı yapmış oluyorduk. Şimdi onları bir config dosyası üzerinden seçimli hale getirmenin tam sırası. Yeni config dosyamız “pic16lib_conf.h” aşağıdaki gibi.

Görmüş olduğunuz PIC16FLIB_USE* etiketlerinden ikisi commentlenmiş. Eğer uygulamanızda RB0/PORTB kesmesini kullanacaksanız bunları da açabilirsiniz. Biz bu uygulamamızda yalnızca TIMER0 kesmelerini kullanacağımızdan seçimi o şekilde yaptık.

Hemen güncellediğimiz kütüphane dosyalarımızı görelim.

Timer0 adres ve kütük tanımlamalarının yapılmış olduğuna dikkatinizi çekerim 🙂 Aynı zamanda, config dosyasında kullandığımız etiketler de, kullanılmayan kesmelerin fonksiyon prototiplerini derleme zamanında kapatmak için yerli yerinde. Öyleyse hemen .c dosyamızı görelim.

Görüldüğü üzere, alışılageldik şekilde timer0 kesme rutinlerini de ekledik. Ek olarak yine config etiketlerimiz de fonksiyonları çevrelemiş durumda 🙂 Artık kütüphanemizi kullanan kimselere çok daha geniş optimizasyon imkanı sunuyoruz! Her durumda yine Microchip liblerinden çok daha yüksek performanslı bir konumda kütüphanemiz 🙂 0 byte kullanarak tüm register erişimlerini yapmak mümkün. Konfor arayan yazılımcılar için de, kütük erişimlerini çok kolaylaştıran veri yapılarını implement ettik. İsteyen istediği yönde optimizasyon yapabiliyor. Bu da kütüphanemizin esnekliğini ciddi oranda artırmış durumda. Şimdi uygulama koduna geçelim.

Bu yazılımda, B portlarını 1 milisaniyede bir eviren bir yazılım oluşturduk. Peki ama bunu nasıl yaptık? Hemen hesap kitaba değinelim. PIC mikrokontrolörümüze dışarıdan bir kristal osilatör bağlı ve frekansı 4MHz.

Aman Diyelim
Proteus simülasyonu yapmadan önce, PIC mikrokontrolöre çift tıklayıp FOSC değerini 4Mhz yaparsak, buradaki hesaplarla uyumlu çıktılar alabiliriz. Aksi durumda varsayılan değer olan 1Mhz geçerli olacaktır ve bu durumda istenen çıktılar elde edilemeyecektir.

PIC16F84A’da timer modülüne gelen saat işareti 4’e bölünerek gelir (datasheet’te yazmakta). Dolayısıyla modülün girişi 1MHz yani saniyede 1 milyon saat darbesi geliyor. Timer modülünün giriş kısmında bir frekans ölçeklendirici (prescaler) bulunmakta. Biz ölçeklendirme oranını 8’e bölecek şekilde seçtik. Bunu, aşağıdaki satır ile yaptık.

Buna göre, 1MHz’lik işaret frekansını 8’e böldük ve prescaler çıkışındaki frekans 125Khz oldu. Bu da 8 micro saniyede bir saat darbesi demek. Eğer bu saat darbelerinden 125 tane sayılınca kesme olacak şekilde bir konfigurasyon yaparsak, 8*125 us = 1ms’lik bir kesme rutini elde etmiş olacağız.  Bu sebeple aşağıdaki tanımla 125 değeri tanımlandı.

Bu değer ise timer0 kütüğüne aşağıdaki şekilde atandı.

Burada ibretlik bir macromuz var. Bu macro TIMER0_ASSIGN_CNT. Peki neden buna ihtiyaç duyduk? Malumunuz bizim timer0 modülü yukarı doğru sayıyor ve 255(0xFF)’de taşıyor. Taşmadan önce 125 tur sayabilmesi için aslında 255-125 =130 değerinden başlamalı Timer0. Bu durumda timer 130’dan başlatılacak ve tam 125 tur sonra (1ms yapıyor) kesme gelmiş olacak. İşte bu çıkarma hesabını yapan macromuz TIMER0_ASSIGN_CNT. Kütüphanemizdeki tanımı da aşağıdaki gibi idi.

Bu sayede 1ms’lik zamanlama sağlamış oluyor. Ancak sürekli olarak 1ms’lik zamanlamayı sağlamak için TIMER0 taştığında, yani kesme oluştuğunda Timer0’ı tekrar 130 değerinden başlatmak gerekiyor. Bunun için, milisaniye callback fonskiyonumuzda aşağıdaki gibi bir tekar yükleme yaptık.

Bu sayede her şey çalışır durumda ve enerji efektif şekilde periyodik işlerimizi yapabilir hale geldik 🙂 Hemen proteus isis üzerindeki simülasyon çıktımızı da ekleyelim.

pic_timer0_0

 

Osiloskoptaki zaman ölçümünün 1.06 mS oluşuna dikkat ediniz. 1ms güzel de, bu 0.06 mS nereden geldi? Buradan da çok güzel ibretlere değineceğiz dostlar, ancak bu sorunun yanıtı ve dahasını bir sonraki yazıya bırakıyoruz 🙂

Zamanlayıcılar konusunda ne kadar çok tekrar yaparsanız, farklı uygulamalar yazarsanız o kadar iyi olur. Örneğin karaşimşek uygulamasını zamanlayıcı kullanarak yazmakta faydalar var.

Şimdi devam!

Yazıları beğendiyseniz, faydalanabilecek tanıdıklarınızla paylaşmayı unutmayınız.

Önceki Sayfa   Sonraki Sayfa

PIC Programlama – 7 – Kesmeler (Interrupts) 2

Merhabalar, geçen yazıda RB0/INT kesmesini bahane ederek kesmeler hakkında bir takım feyizli işler yapmıştık. Bu yazımızda da kesmelere olan sevgimizi ve ilgimizi pekiştirerek, ilginç bir başka örnek yapacağız ve yeni ibretlerle karşılaşacağız. PIC mikrodenetleyicilerde de bir taş üstüne bir taş daha koyalım diyerekten bu günkü örneğimizi PORTB değişme kesmesi üzerinden gerçekleyeceğiz.

Bundan seneler önce, gömülü sistemlerdeki ilk dönemlerimde; keypad (tuş takımı) sürmekten nefret ederdim çünkü mikrodenetleyicilerde kullanımı hem zordu hem de inanılmaz derecede verimsiz idi. Tuş takımının pinlerini matris gibi düşünürsek, sütünları ikili düzende her seferinde bir pin 1’de diğerleri 0’da olacak şekilde, 1 olan pini bir kaydırarak sürerdik ve o esnada da satır pinlerini input olarak ayarlayıp değerini okuyup hangi pine basıldığını anlamaya çalışırdık. Bu olay son derece can sıkıcı bir olaydı ama neyse ki bu can sıkıcı durumu uzunca bir süredir unutmuştum. Ta ki bu yazıyı kafamda planlayana kadar. Bu yazı, bu çirkin yönteme bir tepki olabilirdi, olacak da.

Bir donanımı sürmek için yazılan kodun kesmeler yerine polling (sürekli değer okuma/yazma yani bir nevi deneme yanılma) ile sürülmesi gerek performans açısından gerek güç tüketimi açısından kötü bir durum. Öte yandan tuş takımı sürülmesini anlatan resmi dökümanlar bile en iyi çözüm olarak kesme/polling hibrit kodlar veriyorlar. Bu da oldukça verimsiz bir duruma tekabül ediyor. Daha önce tuş takımı süren arkadaşlar eminim anlayacaklardır. Tuştakımı sürme işinin sadece kesme ile yapılabilmesi güzel olurdu. Öyleyse sadece kesmeyle yapalım 🙂 Arada PORTB değişme kesmesini de anlatmış olacağız.

keypad

Gördüğünüz üzere b portunun 4-7 arası pinleri pull down yaparak satır girişlerine bağladık. Yine 0-3 arası pinlerle keypadin sütun pinlerini süreceğiz. Pull down amaçlı koyduğumuz dirençler bize çok yardımcı olacak 😉 Şimdi gelelim kodlara. Öncelikle güncellediğimiz kütüphanelerimiz aşağıdaki gibi:

Ve yukarıdaki header dosyasına ilişkin kaynak kodu aşağıda:

Gördüğünüz gibi TRISA ve PORTA kütüklerini de modelledik ve ayrıca kütüphaneyi PORTB kesmesini de destekleyecek hale getirdik. Şimdi gelelim main fonksiyonunun bulunduğu main.c’ye 🙂

Gördüğünüz gibi gerekli pin ayarlamalarını yaptıktan sonra, kesmeyi aşağıdaki gibi aktive ettik:

Ardından, yazdığımız kütüphaneye eklediğimiz callback registration (fonksiyon bildirimi kaydı) mekanizmasını kullanarak kesme geldiğinde, haberdar olmak için initialize_keypad_event fonksiyonunu implement ettik. Buna göre PORTB’nin 4-7 arası pinlerinde gerilimsel bir değişme olduğunda haberdar olacağız. Yükselen kenarı ilk konfigurasyon olarak almamızın sebebi ise, keypad satır pinlerimizi donanımsal olarak pull-down’a yani lojik sıfıra çekmiş olmamız. Pull-down ne demek bilmiyorsanız buradan öğrenebilirsiniz.

Bu durumda kodumuz tamamen kesme ile çalışacak şekilde tamamlanmış oldu ve başarıyla da çalışıyor. Ancak yine içimize sinmeyen bazı noktalar var. Bunlardan birincisi şu aşağıdaki satır.

Bu satırın amacı, B portunun ilk 3 pinini 0 değerine çekmek ama bunu yaparken diğerlerini değiştirmemek. Aslında bu satır daha anlaşılır şekilde aşağıdaki gibi de implement edilebilirdi.

Peki neden yukarıdaki gibi yazmadık? Çok daha anlaşılır olurdu oysa ki. İşte burada cevap “performans”. Tek satır olan kod eğer diğerinden daha kısa sürede işletiliyorsa, o zaman zaman kaybetmemek için anlaşılırlıktan feda edilebilir, ki burada yapılan da o 🙂 Ancak bu durumda bile anlaşılırlığı kaybetmemek mümkün. Nasıl mı? Comment yani yorum satırları ekleyerek. Bu vesileyle bir kez daha yorum satırlarının ne denli önemli olduğuna değinmekte fayda var. Kodu iyileştirmek için aklımda bazı hinlikler var ama önce kodun bellek kullanımına bakalım.

Yukarıdaki kodun bellek kullanımı aşağıdaki gibi:

Şimdi iyileştirme yaptığımız main.c dosyamıza bakalım.

Yapılan değişiklikleri kısaca sıralarsak:

  • Register erişimi için değişken kullanımını ortadan kaldırdık. Ve bu iş için hiç değişken kullanmadık!
  • Bellek bayram etti (mi acaba, göreceğiz 🙂 ama etti)
  • Kodun anlaşılabilirliğini çeşitli define ve yorum satırları ile boost ettik.
  • Doxygen stili dökümantasyon yaparak (hepsini yapmasak da 😉 ) o işi de kodun üzerinde aradan çıkardık.

Ve güncellenmiş main kodumuzun olduğu uygulamanın bellek kullanımı:

 

Gördüğünüz üzere program alanı kullanımını 612’den 440 worde (1 word=2 byte) düşürdük. Ayrıca veri alanı kullanımını da 37 byte’dan 29 byte’a düşürdük 🙂 İşte bu elle tutulur bir optimizasyon.

Keypad’i de tertemiz, kesme kullanarak sürmüş olduk. Arada PORTB değişme kesmesi nasıl kullanılır onu da hallettik. Sayısız ibretlere de değindiğimizden bu günlük bu kadar diyoruz 🙂

 

Yazıları beğendiyseniz, faydalanabilecek tanıdıklarınızla paylaşmayı unutmayınız.

Önceki Sayfa   Sonraki Sayfa

PIC Programlama – 6 – Kesmeler (Interrupts)

Önceki yazımızda PIC16F84A’nın pinlerini kontrol etmeyi işlemiştik. Elbette ki buraya kadarki bilgilerle çok sayıda uygulama yapmak mümkün ancak bu yazı dizisi altyapı oluşturma amacı taşıdığından şimdilik farklı uygulamaları geleceğe bırakarak altyapı çalışmalarına devam diyoruz. Mikrokontrolör’ün giriş çıkış arayüzlerini detaylıca inceledikten sonra sıra geldi kesmelere. Önce genel manada kesmelerin ne olduğuna değinip, ardından da port ve pin kesmeleri ile devam edeceğiz. Mikrokontrolör’ün çevresellerinden bazıları farklı tipte kesmeler destekler. Örneğin zamanlayıcı kesmelerine, zamanlayıcı modülünde değineceğiz. Hazır port/pin kontrolünü görmüşken bu yazıda port/pin kesmelerine değineceğiz.

Kesme nedir demeden önce, mikrokontrolör ve CPU arasındaki farkları hatırlayalım. CPU (işlemci, merkezi işlem birimi) mikrokontrolör içerisindeki bir modüldür. Mikrokontrolör içinde, CPU’ya ek olarak bellek ve çevreseller (perihperal) bulunur. CPU içerisinde genelde aritmetik/lojik işlemleri yapan bir modül (ALU) bulunur. Hemen PIC16F84A’nın yapısını inceleyelim. Bu blog diyagram PIC16F84A’nın veri kağıdından alındı.

pic16f84a_block_diag

Diyagramda ALU’ya dikkat ediniz. Onu CPU olarak düşünebilirsiniz. ALU’dan W reg’e giden yolda sağa doğru bir kanal olduğunu göreceksiniz. O kanal I/O portlarına, TMR (timer, zamanlayıcı) modüllerine ve daha nice yerlere gidiyor. Bu kaçak kanal, olası bir kesme sinyalinin ALU’ya müdahale edebildiğinin bir kanıtı. Bu yazının sonunda da resmin sağ alt kısmında yer alan RB0/INT’in ne olduğu anlatılacak.

Kesme Nedir?

Kesmeleri tanımlamak uygulamada göstermekten zor bir iştir ama şöyle bir tanım yapmak mümkün: Kesme (interrupt), CPU’nun dışındaki bir dış etken tarafından oluşturulan ve oluştuğunda CPU’nun yaptığı işi durdurup,  ayrı bir özel kod parçacığının işletilmesini (yürütülmesini) sağlayan elektriksel bir işarettir. Kesme  oluştuğunda işletilen bu koda genelde kesme servis rutini (interrupt service routine, ISR) denir. Kesme oluştuğu anda, ISR’ye gitmeden önce, CPU program işletiminde kaldığı yeri kaydeder. ISR’nin işletimi bittiği anda da CPU bu kayıtlı noktadan yani kaldığı yerden programı işletmeye devam eder.

Kesme asenkron gerçekleşen bir olaydır, yani ne zaman gerçekleşeceğini CPU önceden bilmez. Gündelik hayattan  buna benzer bir süreç örneği verecek olursak; kapı zilinin ya da telefonun çalması durumlarını örnek verebiliriz. Diyelim yemek yapıyorsunuz, zil çaldı; yemek yapmayı bırakıp kapıyı açıp yemek yapmaya devam ederiz. Zil çalınca, yahu dur sırası mıydı demeyiz. Ya da sürekli kapıyı kontrol etmeden zilin ne zaman çalacağını bilemeyiz. Bununla birlikte, kapının çalışını duymazdan gelmeniz bir seçenektir tabi ki. Aynı şeyler kesmeler için de geçerli 🙂

Kesmeler, gömülü sistemlerde çok çok önemli bir yere sahiptir. Kesmeler’in düzgün kullanımı ile tasarlanmış bir sistem daha verimli, daha duyarlı (responsive) ve daha anlaşılır şekilde tasarlanabilir. Kesmeler düzgün kullanılmazsa da “yaa böyle olmaması lazımdı ama, çok saçma, böyle çalışmaması lazımdı ama” sözleri havada uçuşur, işin içinden çıkılmaz. Halbuki dostlar, her şey deterministik 🙂 Çok güçlü ama biraz da tehlikeli olduklarından bazı yazılımcılar kesmelerden korkar ama gömülü sistem programcısı kesmeden korkmamalı, kesmelerle samimi olmalı, onları son derece işeyarar ve güçlü bir arkadaş olarak görmelidir. Zira, etrafınızda gördüğünüz gömülü sistemlerden en az bir kesme kullanmayanı bulmak sıradışı bir olaydır. Sözün özü, kesme candır.

Farklı mikrokontrolör mimarilerinde kesmeler farklı şekillerde ele alınır. Şimdi PIC’ten başlayalım. Yine ibretlerle dolu bir uygulama yapacağız.

Switch ve Led Uygulaması

Bir önceki yazımıza yaptığımız uygulamada, while döngüsünün içerisinde switch’in durumunu sürekli kontrol etmiştik. Buna polling deniyor ve ekstrem derecede verimsiz bir yöntemdir bu. Bunun yerine kesme kullansaydık, sadece anahtarın durumu değiştiğinde ledlerin durumuna müdahale edebileceğimiz bir senaryo oluşacaktı. Bu da ileride özellikle güç tüketimi anlamında da bize avantajlar sağlayacaktı. Haydi sağlasın madem. Uygulamayı bu defa kesme kullanarak yapacağız. Yine switch bir konumda iken kırmızı yanar sarı söner durumda olacak, switch diğer konumdayken sarı yanar kırmızı söner durumda olacak. Yine bu uygulamada da kod yazımımızı bir kaç adım öteye taşıyacağız ancak önce kaldığımız yerden devam edelim 🙂

Kodun çalıştırılacağı devre bir önceki yazıdakilerle aynı. Yani çıktı aşağıdaki gibi olacak.

switch2

switch1

Şimdi gelelim fasülyenin faydalarına. Kesmeyi nasıl kullanacağımızı nereden bildik? PIC16F84A’nın veri kağıdının 6.8 Interrupts başlıklı kısmında hangi registerları nasıl konfigüre etmemiz gerektiği açıkça yazıyor. Bildiğiniz gibi bu yazı dizisinde kendi yazdıklarımızdan başka bir kütüphane kullanmıyoruz. Bunun amacı her şeyi temelinden anlamaktı. Doğal olarak kullanacağımız yeni registerlar için de tanımlamaları yapıyoruz. Aşağıda OPTION ve INTCON kütüklerinin (registerlarının) adres tanımlarını ve yardımcı etiketleri görebilirsiniz. Buna ek olarak bir de BIT_TOGGLE makrosu tanımladık. Bu makronun amacı bir biti birse sıfır, sıfırsa bir yapmak. Bunu ileride kullanacağız.

Registerların modellenmesini ise aşağıdaki gibi yaptık.

Bu tanımlamaları datasheetten bakıp yaptıktan sonra INTCON ve OPTION kütüklerini gösterecek işaretçileri aşağıdaki gibi tanımladık.

Ardından gelelim ana fonksiyon(main) içinde yaptığımız ek konfigürasyonlara.

Öncelikle kesme bayrağının temiz olduğundan emin olmak için onu temizledik. Ardından INTE ile RB0/INT kesmesine izin verdik. Ardından da global kesme aktivasyonu için GIE bitini etkinleştirdik. GIE ve INTE bitlerinin ikisi de 1 değerini almadan kesme gerçekleşemez. Bunu da verikağıdındaki aşağıdaki şemadan anlayabiliyoruz.

int_logic

Konfigürasyonda kesmeyi de yükselen kenarda olacak şekilde ayarladık. Buna göre anahtar sıfırdan bire çekildiğinde yükselen kenar kesmesi gelecek. Ama burada bir sorun var, bize hem yükselen kenar hem düşen kenarda kesme gerekiyor. Çünkü anahtarın konumu sıfırdan bire değiştiğinde de birden sıfıra değiştiğinde de kesme almak ve LED’lerin durumunu değiştirmek istiyoruz. PIC’te böyle doğrudan böyle bir seçenek yok; ya yükselen kenar kesmesi seçilebiliyor ya da düşen kenar. Burada beyin bedava diyoruz ve kafayı çalıştırarak soruna çözüm sunuyoruz. Önce yükselen kenar kesmesini aktive ettiğimizi düşünelim, bu durumda ilk gelen yükselen kenar kesmesinin hemen ardından düşen kenar kesmesini aktive edersek, switchin durumu tekrar değiştiğinde kesme alabiliriz. Yani yükselen/düşen kenar konfigürasyonunu, kesme oluştuğunda toggle etmemiz gerekiyor. Kesme tamamlandığında kesme bayrağını yani INTF bitini de sıfıra çekip temizlemek gerekiyor. Kodda da bunları yaptık. PIC’te kesme fonksiyonu fonksiyon adının başına gelen “interrupt” kelimesi ile derleyiciye anlatılır. Buna göre kesme fonksiyonumuz aşağıdaki gibi oluyor.

PIC’te tüm kesmeler tek bir fonksiyon içine düşer, bu da interrupt ön ekli fonksiyondur. Bu sebeple bu fonksiyonun adını global_isr_handler koyduk. Daha sonra gelen kesmenin RB0/INT olup olmadığını kontrol ettik ve eğer o ise switch değerlendirmesi işlemini yapıp yükselen/düşen kenar seçimini güncelleştirip bayrağı temizledik. INTEDG’nin toggle edilmesi ile hem düşen hem yükselen kenardaki değişimleri güzel bir oyun ile algılayabilir duruma geldik. Çiçek oldu.

Şimdi gelelim bu kodun sorunlarına. Birincisi register tanımları giderek kabarıyor ve onların ayrı bir *.h dosyası içinde yer alması gerekiyor artık. İkincisi, ilk durumda switch’in durumuna bakmaksızın kesme konfigurasyonu yaptığımız için ilk açılışta ledlerin ikisi de yanmıyor. Üçüncüsü de şu, madem her kesme aynı fonksiyona düşecek, ileride kod daha da büyüdüğünde kesme fonksiyonu sürekli değiştirilecek ve eğer birisi orada yanlış bayrakları temizlerse ya da kurarsa, önceden yazılmış kısımlar da bundan etkilenecek ve kodun her yeri bozulacak. Bu çok büyük bir risk. Burada SDK tasarımı devreye giriyor. Akıllıca bir seçenek, kesme fonksiyonunu kullanıcı programından ayırmak olacaktır. Burada kesme bayraklarının yönetiminin de otomatik yapılması da isabetli olacaktır. Bu olay gerçekten bir ileri tasarım öğesidir ancak adım adım oraya gideceğiz. Kodun bir diğer önemli sorunu da kütüphane kullanmayacağız inadımızla kullanmadığımız stdint kütüphanesidir. “unsigned char” gibi boyutu “hayırlısı” olan bir veri tipi kullanmak yerine “uint8_t” ile modelleme yapmamız daha temiz olurdu. Nitekim amacımız PIC kütüphanelerini kullanmadan, daha iyi şekilde temelden olayı yazarak olayın dinamiklerini anlamaktı. Bu da stdint’e geçişimizi engellemiyor. Bir diğer eksik nokta da register tanımlarıyla ilgili. Önceki yazıda, sebeplerini sıraladığımız üzere hem bit hem de byte erişimi sağlayabilmek için kütük modellemelerinde union kullanmıştık. Yeni modellediğimiz kütüklerde de bunu uygulamakta fayda var. Bunlara göre projemizi yine düzenleyelim 🙂

Switch ve LED Uygulaması v2

Bu projede 3 adet dosyamız olacak. Birincisi pic16f84a kütüphanemizin header dosyası. Bu dosya (pic16f84a_lib.h) aşağıdaki gibidir.

Yine pic16f84a kütüphanemizin kaynak dosyası (pic16f84a_lib.c) aşağıdaki gibidir.

Ve nihayetinde ana programımız (main.c) aşağıdaki gibidir:

Kodda, vadettiğimiz tüm değişiklikleri yapmış olduk. En en en en en önemli yer, kullanıcının yani main dosyasının kesme fonksiyonunu hiç bir şekilde görmeden kesme işlemlerini haber alması. Bunun için SDK geliştiricisi olarak çıkardığımız fonksiyonu kullancı aşağıdaki şekilde çağırmış oldu:

Bu fonksiyonun implementasyonu da tam anlamıyla ibretlik. Maksimum 5 kaynak RB0/INT kesmesine abone olabiliyor. Bu genişletilebilirlik açısından çok çok önemli. Biz switch kodunu yarın öbürgün “switch geldiğinde bir de düdük çalsın” isteriyle genişletmek istediğimizde düdüğü çalacak fonksiyonu da register edecersek o düdük çalınacaktır ve bizim önceki işlerimiz asla bundan etkilenmeyecektir. Bu olaya lütfen çok dikkat ediniz. Listeye kaydolmuş fonksiyonların yani callback’lerin çağırıldığı satır ise aşağıdaki satır.

Şimdilik bu kadar 🙂 Bu gün epey fantastik mevzulara değindik. PIC deyip geçmemek gerek, bu basit alet için bile ileri düzey tasarım yapmak mümkün. Nitekim daha da ilerleyeceğiz. Yazılar devam edecek.

Yazıları beğendiyseniz, faydalanabilecek tanıdıklarınızla paylaşmayı unutmayınız.

Önceki Sayfa   Sonraki Sayfa

 

PIC Programlama – 4 – Giriş Çıkış (I/O, Input/Output) İşlemleri

Merhabalar, bir önceki yazımızda  PIC için yazdığımız bir merhaba dünya kodunun içini dışını hallaç pamuğuna çevirmiş ve sayısız ibretlerle keyiflenmiştik. Bu yazımızda da PIC16’nın bir pinini nasıl giriş yaparız, nasıl çıkış yaparız, bir giriş pininden nasıl değer okuruz, bir çıkış pinine nasıl değer yazarız gibi işlemlere değineceğiz 🙂 Sözün özü, hayatı bir dizi gerilimsel işaretle mıncıklayacağız 🙂

Sosyal Mesaj
Malumunuz bu yazım öncekilere nazaran epey gecikti. Ciddi bir ara vermiş oldum ancak gerçekten yoğun bir dönemi geride bırakmış olduğumu belirtip, affınıza sığınarak yazı dizilerine devam ediyorum.

Şimdi, yine bir kütüphane kullanmadan (ya da sadece kendi yazdığımız kütüphaneleri kullanarak) bir karaşimşek kodu yazalım =) Karaşimşek kodu meşhurdur dostlar =) es geçmeyelim!

Tıpkı PIC mikrodentleyicilerinin bizler için “araç” olması gibi, karaşimşek kodu da anlatmak istediklerimizi anlatmak üzere kullanacağımız bir araç olacak. Amacımız ibretleri birer birer kapmak. Sözü sakız edip uzatmadan hemen kodumuzu yazalım.

Evet efendim kodumuz yukarıda yer aldığı gibi. Çıktısını göstermeden önce, dilerseniz kodu bir açıklayayım. İlk aşamada bekletme (delay) işlemlerini yapabilmek için çalışma frekansını giriyoruz. Buna göre çalışma frekansı 1.000.000 Hz yani 1MHZ olarak aşağıdaki gibi belirleniyor.

Ardından, bir önceki yazımızda anlattığımız üzere kendi çabalarımızla register tanımını yapıyoruz. Malum bu yazı dizisinde bir hedef de PIC’i bahane edip, bir mikrokontrolöre kütüphane nasıl yazılır onu da öğrenmek. Önceki yazıda myTRISB diye yaptığımız register tanımı Ağaoğlu MyTRISB projesi ile isim benzerliği göstermesin diye isimlendirmeyi birazcık değiştirdik 😛

Bunlar malumunuz; efektif şekilde tanımlanmış kütükler. Ben afedersiniz kütük diyorum ama onun İngilizcesi “register”. Neyse bir sonraki aşamada main’e geçecek olursak önce pin’lere ilk değer veriliyor ki o kısım zaten önceki, merhaba dünya örneğinin aynısı. Ardından el yordamı ile yazdığımız  DummyDelayMs fonksiyonuna değineyim.

Bu fonksiyonun işi, cnt değişkeninin değerini insafsızca ve ahlaksızca artırarak CPU’nun diğer işleri yapmasını engellemek. Bu da hödükçe bir beklemeye sebep oluyor.  Çalışıyor mu? Çalışıyor! Oradaki 120000 sayısını empirik olarak buluyoruz. Proteusta bir OSC kullanıp zamanı ölçerek bulmak mümkün. Hesapla kitapla da yaklaşık olarak bulmak mümkündür. Neyse biz işimize devam edelim. Aşağıdaki kod ise karaşimşek işini yapmaktadır.

100ms’de bir led bir kaydırılıyor. Bu kodun çıktısı ise aşağıdaki gibi oluyor 🙂

ks

Bu yazı bu kadarcık olsun 🙂 Başka bir yazıda devam edeceğiz.

Önceki Sayfa   Sonraki Sayfa

 

PIC Programlama – 3 – Merhaba Dünya Analizi

Uzunca bir dönemdir, çok büyük bir yoğunluk içindeyim. Bu sebepledir ki, bir türlü fırsat bulup yeni bir yazıya başlayamadım. Herhalde gün, bu gündür 🙂

Geleneksel olarak yine merhaba dünya yazımızın suyunu sıkma niyetindeyiz. Her ne kadar girizgah seviyesinde de olsa yazdığımız merhaba dünya yazısında, netleştirilmesi gereken bazı şeylerin olduğu aşikar. Bu yazı dizisinden önce Gömülü C yazı dizisinin okunmuş olmasını şiddetle tavsiye ediyorum.

Şimdi lafı uzatmadan, PIC’de yazdığımız ilk kodu hatırlayalım.

Bir kere şu xc.h’ı bir inceleyelim ne varmış içinde?

Gördüğünüz üzere, XC aslında MplabX Compiler anlamında yer alıyor ve kullandığımız platform 8 bitlik olduğundan, __XC8 etiketi sistemde tanımlı olduğundan (MplabX tarafından, biz projeyi oluşturduğumuzda otomatik tanımlanır) ilgili compiler header’ı çağırılmış. Bunun da “htc.h” olduğunu görüyoruz. Burada jeton düşüyor, hmm demek ki bu xc serisi, eski hi-tech C compiler’ın üzerine kurulmuş. Burnumuz bunun kokusunu aldı. Şimdi daha derine inelim; htc.h’ı açalım.

Bu header dosyası sayesinde, projenin özelliklerine bakılarak jenerik olarak doğru header’ların seçilmesi sağlanıyor. Muhakkak ki bunların hepsi alt alta dallanıyor ancak şöyle kısaca bir özet geçelim. CCI denilen bir muhabbet var. The Common C Interface (CCI) kavramı, taşınabilir kod yazılabilmesi için ortaya atılmış güzel bir kavram. Ancak Microchip bence bu yarışta biraz geride kalmış. Yine de CCI’ya ileride değineceğim.

xc8debug.h ise, MplabX ide üzerinden yapılan debug işlerine yardımcı olan, çok çok basit bir header. Dolayısıyla üzerinde çok konuşmaya değmeyecek.

pic.h ise önemli. Çünkü derleyicinin bizim işlemcinin register tanımlarını aldığı kütüphane bu kütüphane. Bu iş nasıl oluyor? Biz projeyi yaratır iken, IDE bizim seçtiğimiz işlemciye göre gidip -D ile, compiler define yapıyor. Daha sonra pic.h gibi kütüphaneler bu bilgileri kullanarak, hangi mikrodenetleyicinin header’ının seçileceğine karar veriyor. Örneğin bizim seçimimizde IDE, bizim seçtiğimiz işlemciye göre -D_16F84A tanımını yaptı. Bu bilgiyi cebe atıp devam edelim. pic.h’ın içine bir bakalım.