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.

Arkadaşlar sağolsunlar pic.h içinde bize yardımcı olabilecek çok sayıda şey tanımlamışlar. pic_chip_select.h tam olarak mikrokontrolör header’ı seçimini yapıyor ve onu mutlaka konuşacağız. Ancak sırayla buradaki bazı ibretlere bir değinelim. PIC16F84A; 68 byte RAM’i ve 1024 word’lük inanılmaz(!) FLASH belleği ile, hakikaten kısıtlı kaynaklı bir donanım olduğundan, dayılar haklı olarak LOG ve TRACE fonksiyonelitelerini kapatmışlar 🙂 Zira bu fonksiyoneliteleri kullanmaya kalksaydık, kaynakların çoğunu kullanmış olurduk.

Yukarıdaki etiketler, assembler komutlarını çağırarak sırasıyla watchdog timer’ı resetlemenin ve uyku moduna girmenin verimli implementasyonları olarak göze çarpıyor. Watchdog timer’ı resetlemek bazı arkadaşlara bir anlam ifade etmemiş olabilir. Mikrodenetleyici bir sebepten donarsa filan, reset atabilecek bir donanımın olması gerekiyor. Eğer mikrodenetleyicideki kod, belli aralıklarla watchdog timer’ın sayacını sıfırlamazsa, sayaç artıp taşar ve taştığı gibi mikrodenetleyiciye reset atar. Yerli yerinde kullanıldığında WDT (watchdog timer) candır 🙂 Sleep ise, mikrodenetleyiciyi düşük güç tüketimi moduna sokmanın güzel bir yoludur. Bu kısmı da ileride detaylıca ele alacağız.

ei(); ve di(); fonksiyonları ile sırasyla interrupt enable ve interrupt disable işleri kolaylaştırılmış. İleride detaylıca değineceğimiz kesme fonksiyonelitesinin aktive edilmesi ya da devre dışı bırakılması için bu makroları kullanmak mümkün 🙂 Diğer kısımlar zaten benzer. Öyleyse şimdi pic_chip_select.h kütüphanesinin bir kısmını inceleyelim. Gerisi de zaten aynı 😀

Bu dosyada gördüğünüz gibi, IDE tarafından biz projeyi oluştururken tanımlanan etiketler kullanılarak doğru başlık dosyaları (header files) projeye dahil ediliyor yani çağırılıyor. Bu saydede biz xc.h dediğimizde, mikrokontrolör modeline göre, başlık dosyaları otomatik çağırılmış oluyor. Hmm, güzel 🙂 Öyleyse bir adım daha dalalım.

Burada, tüm register tanımlarının nasıl yapıldığına dikkat ediniz 🙂 Bizim Gömülü C yazı dizisini tamamen okuyan herkes için burada ne yapıldığını anlamak kolay olacaktır. Yine de anlamadığınız yerler olursa sorunuz 🙂 Şimdi merhaba dünya kodumuzdaki register’ları özellikle inceleyelim.

Burada demişler ki PORTB diye bir değişken yaratıyoruz ve bu bellekteki 0x006 numaralı adrese karşılık düşüyor. Yine benzer şekilde TRISB diye bir değişken yaratıyoruz ve bu bellekteki 0x086 numaralı adrese karşılık düşüyor. Bu bilgileri datasheet’teki bellek haritasından aynen doğrulamak mümkün. Zaten oradan bakıp yazmışlar 🙂 Ama ayıbetmişler… Çünkü tüm register’lar için kafadan değişken tanımlanmış. Bu, ödemesi ağır bir bedel. Ayrıca @ operatörü standart bir operatör değil. Dolayısıyla bu tanımlar, platform bağımlılığı yaratmakta ve kodların taşınabilirliğini negatif etkilemekte. Bunlara bir ayar çekmemiz kaçınılmaz duruyor 🙂

Şimdi, bu noktaya geldikten sonra, geleneğimizi uygulayalım ve yine header kullanmaksızın merhaba dünya kodumuzu yeniden yazalım 🙂

Gördüğünüz üzere, kodda ne bir kütüphane kullandık, ne de bir değişken! Zaten kodumuzda, merhaba dünya kodundaki gereksiz şeylerin hiç birisi yok. Register tanımlarını da çok çok daha verimli şekilde yaptığımızı gururla huzurlarınıza sunarım 🙂 0 byte değişken kullanarak, yine ledimizi yaktık!

PIC16F84A_3

Buradan gerekli ibretleri lütfen alalım 🙂 Sanıyorum ki, “Abi PIC programlama yaparken Hi-Tech compiler CSS’den iyiymiş yaa” filan gibi geyiklere artık bolca gülersiniz. Hiçbirine ihtiyacımız yok, sadece tekerleği yeniden icad etmemek için onları araç olarak kullanıyoruz 😉

Sonraki yazımda bu temellerin üzerine, giriş çıkış işlemleriyle ilgili detaylı bir yapı inşa etmeyi planlıyorum. Dilerim sizler için de faydalı ve eğlenceli bir yazı olmuştur.

Şimdi devam…

Önceki Sayfa   Sonraki Sayfa

 

PIC Programlama – 2: Merhaba PIC16

Selamlar 🙂 Bu gün nihayetinde Merhaba PIC16 yazımı ekleme niyetindeyim. Esasen yazdığım sayfalarca yazıyı browser’ın azizliğinden dolayı kaybettim. Ancak yılmak yok 🙂 Tekrardan yazmaya devam. Sizlerle 07.03.2015 tarihinde paylaşmayı planladığım bu yazımı ne yazık ki ancak paylaşabiliyorum. Bu gecikme için affınıza sığınıyorum ve yılmadan yazmaya devam diyorum.

Bu yazı dizisinde, sevgili dostum Birol Çapa ile üniversite yıllarında birlikte oluşturduğumuz kaynaklardan da faydalanacağım. Bu vesileyle sevgili dostum Birol‘a da teşekkürlerimi iletiyorum.

Efendim bu yazı dizisinin temel amacı, devasa bir okyanus olan gömülü sistemlere, okyanusun ortasından dalmak yerine güzel bir sahilden dalmak. Yani ne demek istiyorum? Derya deniz diye özetleyebileceğimiz bu konuda, uygulama yapabileceğimiz güzel bir başlangıç noktasından balıklama konuya dalmak. Yine çok sayıda ibretlik noktaya değineceğimizi düşünüyorum. Yazılar da yine her zamanki uslüpla olacağından, sizleri de sıkmadan eğlenceli bir yazı dizisi geçireceğimize inanıyorum.

Neden PIC16 sorusunun cevabını esasen bir önceki yazımızda bir miktar vermiştik. Şimdi başka soruların peşinde koşalım!

Neden Mikrokontrolörler?

Efendim gömülü sistemler derya deniz demiştik. Gömülü sistemlerin en yaygın kullanım alanlı alt dalı, mikrokontrolör tabanlı sistemlerdir. Bu dal öyle bir daldır ki, çoğu ağaçtan çok daha okkalıdır. Burada edineceğimiz bilgileri, joker gibi diğer tüm gömülü sistem uygulamalarında uygulayabileceğimizden dolayı, mikrokontrolörleri iyi bilmek, iyi kullanmak çok çok önemlidir. Buna istinaden bu yazı dizisi vesilesiyle hızlıca mevzuya dalmanın faydalı olacağını düşünüyorum.

PIC de, gömülü sistemlerin temel mantığını çok çok güzel şekilde anlayabileceğimiz bir başlangıç noktası. Beğenirsiniz beğenmezsiniz, Arduino var olana kadar en önemli hobi elektroniği argümanlarından birisi PIC idi. Halen daha kullanımı çok yaygın. Ve dostlar bence buradan da öğrenebileceğimiz çok önemli noktalar olabilir. O sebeple hakir görmeyelim 🙂

Neden C?

C dili ile ilgili tonlarca şeyi, Gömülü C yazı dizisinde konuşmuştuk. Mikrokontrolör programlama işlerinde, C/C++’ın yanı sıra, Assembler, basic ve hatta yer yer java dilleri bile kullanılır. C dili bunların hepsinin ağzını burnunu kırar diyeceğimi lütfen düşünmeyiniz bile. C dilini bir kenara atıp diğer dillere çamur atmaya da niyetli değilim.

Yazılımda programlama dilleri amaç değil araçtır. Programcı bir nevi ninja ise, programlama dili de ninjanın silahıdır. Bazen kocaman bir kılıç karşısında, minik bir hançer ya da mınçıka galip gelebilir. Zira kılıç ile bir hareket yapıncaya kadar, bu ufaklıkları 8. hamlesini tamamlayabilir 🙂 Keza savaş uzaktan yapılıyorsa, belki ok ve yay kullanmak daha yeğdir. Neyse, Age of Empires ya da Hitman oynamıyoruz. Ağzımdaki baklayı çıkarayım; bu dillerin her birinin muhakkak ki birtakım avantajları ve dezavantajları bulunmaktadır. Bu diller içerisinden C dilini seçmemizin nedeni, bu dilin en yaygın kullanılan programlama dili olması, gömülü sistemlerin her alanında gücünden pek de bir şey kaybetmeden kullanılabilmesi gibi çok güzel sebepler yatar. Ancak göreceksiniz ki yeri gelecek birden fazla dili beraber de kullanacağız. Benim Assembly kardeşimi hakir görmek, şüphesiz ki davaya ihanet olacaktır 😛

Temel Kaynaklar

Bir mikrokontrolör programlama mevzusu varsa en birinci kaynak, şüphesiz ki o mikrokontrolörün datasheet’i (veri kağıdı) olacaktır. Gömülü sistemlerde bir şeyler yapmayı öğrenmenin büyük bir kısmı veri kağıdı okuyup anlayabilmekten geçer. Bizim PIC16’nın da çeşitlerinin güzel güzel veri kağıtları mevcut. Aslında daha gelişmiş mikrokontrolörlerin datasheet’inde genellikle donanımsal özelliklere yer veriliyor. Bu tip donanımları kullanabilmek için “user guide” olarak da bilinen kullanım kılavuzlarını okumak gerekiyor. Neyseki PIC16F serisi, görece basit bir seri olduğundan veri kağıdı ile paçayı sıyırıyor olacağız. Hemen çok kullanacağımız bazı PIC’lerin veri kağıtlarını paylaşalım.

Efendim, gömülü sistemci olacaksak ne yapıp edip bu dokümanları okuyabilir hale gelmemiz gerekiyor. İngilizce bilmeyen arkadaşlarım da lütfen bu sorunun üstesinden gelmek için Google Translate gibi araçları kullansınlar. Zira bir yerden sonra hep aynı terimler geçtiği için dökümanları anlamak çok çok kolay oluyor.

Veri kağıtlarına ek olarak önemli bir kaynak da, geliştirme ortamının ya da derleyicinin dökümanasyonu oluyor. Ben derleyici dedim ama aslında demek istediğim toolchain. Yani içinde derleyici, bağlayıcı (linker dayı), assembler, türlü türlü kütüphaneler filan bulunan yazılım paketi. Bunun dökümantasyonunu da incelemekte faideler mevcut. Bizimkine, sırası gelince değineceğim.

Kullanılacak Programlar (Kurulumlar)

Yolculuğu kafamızda şöyle kısaca bir çizelim ki, ihtiyacı listeleyebilelim. Bizim öncelikle kodumuzu yazabileceğimiz bir ortama ihtiyacımız var. Bunun adı geliştirme ortamı (IDE). Ardından kodlarımızı anlayacak, derleyecek, link edecek bir yazılım setine ihtiyacımız var. Sonra diyelim ki yazılımımızı yazdık ve executable dosyamızı elde ettik. Bunu PIC’e yazacak bir programlayıcıya, ve programlayabileceğimiz bir donanıma ihtiyacımız var. Veya, programlayıcı + programlanacak donanım yerine simülatör kullanabiliriz 🙂 Özellikle hızlı uygulama ve öğrenme açısından simülatör kullanmak çok mantıklı olabiliyor. Ancak gerçekleme yapmak da şart. Biz tüm bu aşamalara değineceğiz ancak önce kurulumlarımızı tamamlayalım.

  • MPLAB X IDE: PIC için  diye gayet hoş bir IDE mevcut. Ardından bir toolchain’e ihtiyacımız var. Bazı IDE’lerin içinde toolchain hazır olarak geliyor ancak MPLAB söz konusu olunca bu kadar şanslı değiliz. Gerçi MPLAB X, tüm seriler için genelgeçer bir IDE olduğundan, toolchain’in sonradan kurulması da mantıklı 🙂 Ben MPLAB X versiyonu olarak 3.0 beta kurdum. Normal şartlar altında, bir gömülü sistemci asla ama asla beta yazılım kullanmaz. Sağlamclığıa çok aykırıdır. Ancak bu, bilgi paylaşımı amaçlı bir yazılım olduğundan, siz bu yazıyı okuyuncaya kadar 3.0 stabil versiyon da çıkar diyerekten 3.0 beta kurdum. Siz de ücretsiz olarak kurulumu yapabilirsiniz.
  • MPLAB XC8. Neyse bir sonraki aşama olarak 8 bit’lik PIC’ler için olan XC8 toolchain’i kuruyoruz. Efendim eğer 16 bit’lik bir PIC için yazılım geliştirecek olsaydık XC16, 32 bit’lik bir PIC için yazılım geliştirecek olsaydık XC32 kuracaktık ancak suyu bulandırmayalım ve MPLAB X’in üzerine XC8 kuralım. Son versiyon olan, MPLAB® XC8 Compiler v1.34 kurulumunu tamamladım. Siz de en son versiyon hangisi ise, onu kurabilirsiniz. Evaluation sürümü ücretsiz! PRO versiyonu da 60 gün için yine ücretsiz 🙂 XC8’in çiçek gibi de bir dökümantasyonu var. Mutlaka feyizlenelim. Kurulumu yaparken, MPLAB X IDE’yi XC8’i kullanacak şekilde güncelleyin seçeneğini işaretlemeyi unutmayalım 🙂 Esasen ben eskiden toolchain olarak Hitech PIC C kullanırdım. Ama Microchip şurada, artık kullanmayın demiş. Zaten hiç bir şeyin fark etmeyeceğini, bunlara ihtiyacımız bile pek olmadığını anlatacağım. Ama şimdilik önerilen ile devam edip XC8’i kuralım.
  • Proteus ISE:  Bu yazılım da güzel bir simülasyon ortamı. Aslında Proteus’a simülasyon ortamı demek biraz vicdansızlık olur. Zira Proteus ile, devre tasarımı, devre simülasyonu, şematik ve PCB tasarımı da yapılabiliyor. Kendisi çok çok başarılı bir yazılım. Ancak ne yazık ki ücretli. Yine de evaluation versiyonunu kullanabilirsiniz. Ya da internetten proteus kurulumu ile ilgili detaylı bilgileri bulabilirsiniz. Ben 8.10 SP1 versiyonunu kullanıyorum, çok da memnunum 😀 Proteus kurulumunu yaptıktan sonra, eğer proteus kullanmayı bilmiyorsanız google üzerinde proteus derslerine bakıp, proteus kullanımını kabaca öğrenmeniz gerekiyor.

Bunlara ek olarak, donanım bağımsız algoritmaları test etmek amacıyla bir C/C++ IDE’si  kurmakta fayda var. Orwell Dev C++ gayet ufacık tefecik ama işe yarar bir araç.

Kurulumları tamamladıktan sonra, mevzuya dalalım 🙂 Öncelikle, proteus üzerinde programlayabileceğimiz bir PIC ortamı oluşturmamız gerekiyor. İlk örneğimizi PIC16F84A ile yapalım. Proteus’ta “P” tuşuna bastığımızda, place part yani devre elemanı ekleme ekranı açılıyor. Buraya PIC16F84A yazdığınızda, ilgili sembol çıkacak ve çift tıkladığınızda soldaki listeye eklenecektir. Ardından PIC mikrokontrolörü ve diğer gerekli devre elemanlarını eklemeniz mümkün olacak. Proteus derslerini incelediğiniz için burayı kısa kesiyorum ve kurmanız gereken basit devreyi aşağıda sizlerle paylaşıyorum.

PIC16F84A_1

Şimdi akıllara haklı bazı sorular gelebilir. En birincisi, bu devrenin beslemeleri nerede? PIC16F84A üzerine çift tıkladığımızda bir pencere açılır. O penecede sol kısımda “hidden pins” yani gizli pinler yazar. Burada VDD ve VCC pinlerinin gizli olduğunu ve otomatik olarak PIC’in beslendiğini görürüz. Şimdilik bu konu üzerinde çok durmayacağım ancak ileride bunu da açıklayacağım. Şimdilik merak edenler buraya bakabilirler. Proteus burada bizim işimizi kolaylaştırmış ancak gerçek hayatta beslemeyi bağlamazsanız hiç bir şey çalışmayacaktır. Buna ithafen VCC ve GND bacaklarının arasında 2.0V – 5.5V arası bir gerilim olması gerekiyor. Bu bilgiyi nereden öğrendim? Tabi ki datasheet’ten 🙂

Neyse şimdi devam edelim, işlemcinin beslemeleri otomatik yapıldı. PIC16F84A’nın dahili osilatörü olmadığından dışarıdan OSC1 ve OSC2 pinlerine bir XTAL (crystal) osilatör bağlamışız. Buradaki kapasitelerin değerine kadar datasheet’te yazıyor. 22pF da bağlasak olurdu 🙂 Esasen bu pinlerin arasında bir ring osilatör var, XTAL ve kapasitörler bu devreyi tamamlıyor ve osilasyon başlıyor. Burada şimdilik çok detaya girmeyeceğim. Osilatör bir anlamda kalp atışı gibi sinyaller üretir ve mikrodenetleyicinin, bu işarete (saat işareti, clock cycle) senkronize şekilde işlem yapmasını sağlar. Bu kısma parantez değil paragraflar açmak gerekiyor. Onu da ileride açacağım. Ancak şimdi neyse diyelim ve devam edelim.

MCLR diye bir pin var üzerinde de bir çizgi var. Bu pin Reset pini ve üzerindeki çizgi bize, bu pinin “active low” yani “düşük seviyede aktif” olacak şekilde çalıştığını anlatıyor. Bu durumun Türkçe’si şu ki, o pini lojik 0 seviyesine çekerseniz mikrokontrolör reset durumunda kalacaktır. Biz de ne yapmışız, butona basılmadığında o pin lojik 1’de kalacak şekilde yapmışız. Buton’a basıldığında ise mikrokontrolör reset’e çekilecek.

Bizim PIC16F84A yerine PIC16F877A kullanmak istesek bağlantılar nasıl olacaktı? Aşağıdaki gibi, yani aynı olacaktı.

PIC16F877A_1

Neyse biz hemen mevzumuza yani PIC16F84A’ya geri dönelim. Proteus’ta mikrokontrolöre hiç bir şey bağlamasak da mikrokontrolör çalışıyor 😀 Bu sebeple, hızlıca bir led bağlayıp, aşağıdaki devreyi kuralım.

PIC16F84A_2

Hemen ilk kodumuzu da yazalım 🙂 Bunun için MPLAB X’de bir PIC16F84A projesi oluşturmak ve aşağıdaki kodu eklemek gerekiyor.

Bu kodu projemizde derlediğimizde, derleyici .hex uzantılı bir dosya oluşturacak. Şimdi proteus isis’te kurduğumuz devreye dönelim, ve PIC üzerine çıft tıklayıp “Program File” yazan kısma çift tıklayarak, üretilen .hex uzantılı dosyamızı seçelim. “OK” tuşuna basarak çıkalım ve “play” butonuna basarak simülasyonu başlatalım. Led, aşağıdaki gibi yanacak.

PIC16F84A_3

Değerli dostlarım, burada PIC dünyasına merhaba demiş olduk. Mutlaka ki buraya kadar olan kısımda konuşabileceğimiz çok şey var. Ancak tüm bunları diğer yazıya bırakıyorum 🙂 Zira bu yazıyı bu gün bitmeden yayınlamak niyetindeyim. Bir sonraki yazıda bu yaptıklarımızın suyunu çıkaracağız ve ibretler üzerinden gideceğiz 🙂

Buraya kadar okuduğunuz için teşekkürler. Yazıyı beğendiyseniz, faydalanabilecek tanıdıklarınız ile paylaşabilirseniz sevinirim.

Şimdi devam!

Önceki Sayfa   Sonraki Sayfa

PIC Programlama – 1: Girizgah

Yol haritamız, karanlıkta kılavuzumuz demiştik. Donanım altyapısının tahsisinden sonra, kaya misali bir gömülü c altyapısı oluşturmuştuk. Bu sert altyapının ardından yol haritamızda sözünü ettiğimiz ilk yazı dizisi nihayetinde başlıyor. Hobi elektroniğinde yeri çok başka olan Microchip PIC mikrodenetleyicilerini nasıl kulumuz kölemiz yaparız, ne yapar ne eder de bu mikrokontrolörün suyunu sıkarız ona değinmeye çalışacağım.

Tüm bu planlar yol haritamızda belirttiğimiz stratejik bir yolun parçası tabi ki. Gömülü sistemlere adım atan çoğu kimse aynı kırıcı mevzudan şikayetçi; nereden başlayıp nereye gideceğini bilememekten… Sırf bu bağlamda bile yol haritamızın değerli olduğunu düşünüyorum. Konuları kompleks hale getirmeden anlatmanın yollarını bulamazsak eğer, kompleks sistemleri anlamamız mümkün olamayacak. 8-bitlik popüler bir mikrodenetleyici bu sebeple başlamak için iyi bir adım olacak 🙂 Bu sayede sonraki adımlarımızı da çok sağlam atma şansına sahip olacağız.

Kulağa çok kötü gelmiyor da bilader niye böyle bir şey yapıyoruz diyenler olmuştur. Amaç, gömülü sistemler dünyasına ayakları yere basan bir giriş yapmak. Bir eve girerken, duvardan geçmeye çalışmak her zaman iyi bir fikir olmayabilir, ancak bunun farkına varmamız için kapı, pencere gibi temel alternatifleri bilmemiz gerekir. Bu amaçla basit bir mikrodenetleyici üzerinde detaylı bir bilgi seti inşa edip sonraki basamaklara tırmanıyor olacağız. Bu süreç içerisinde yine her zamanki gibi türlü türlü ibretler ve komiklikler şakalar ile karşılaşacağız.

Bu kapsamda Microchip firmasının 3 farklı ürünü üzerinden gideceğiz. PIC16F84A, PIC16F628A ve PIC16F877A. Neden bu serileri seçiyoruz? Çünkü hobi elektroniği camiasında en çok kullanılan ürünler bunlar. Ayrıca vermek istediğim mesajları düşününce, bu serilerin işimizi gayet tertemiz göreceğini düşünüyorum. Bu sebepledir ki bu üç civciv ile başlayacağız yolculuğumuza.Haydi hayırlısı artık 🙂

Bu yolculuğumuzda elle tutulur neler ile karşılaşacağız diye soracak olursanız şöyle bir liste yapmak mümkün olacaktır diye düşünüyorum.

  • Temel anlamda mikrokontrolör kullanımını anlamak
  • Mikrokontrolör’ün veri kağıdını (datasheet) güzelce okumayı öğrenmek
  • Mikrokontrolörün çevresellerini (peripheral) modellemeyi ve kullanmayı öğrenmek (çok önemli)
  • Sensör modellemeyi ve kullanmayı öğrenmek
  • 8 bitlik bir mikrokontrolör üzerinde neler yapılabileceğini ve neler yapılamayacağını görmek
  • Kütüphaneleri kullanıp, onlara bağımlı olmamayı öğrenmek
  • Donanım bağımsız kodlama yapmayı öğrenmek
  • Mikrokontrolörlerde hata ayıklama yöntemlerini öğrenmek
  • Mikrokontrolörün nasıl çalıştığını öğrenmek
  • Karışık sinyal devre tasarımı hakkında pratikler görmek
  • Hayata dokunan, onu yumruklayan işler yapmak

Bu bağlamda standard PIC programlama yazılarından epeyce farklı şeyler göreceğinizin garantisini veriyorum. Umuyorum ülkemizde, bu konular ile ilgilenmek isteyen kimselere faydalı olacak bir yazı dizisi olur. Gerek ilgi duyan kimselerin bu alanlara yönlendirilmesi, gerek bu alanda çalışan kişilerin bilgi birikimine bir nebze olsun katkıda bulunulması hedefleriyle bu yazıyı büyük bir motivasyonla sürdürüyor olacağım 🙂

PIC deyip küçümsemeyiniz, es geçmeyiniz efem. Zira buradan da edineceğimiz bir şeyler muhakkak vardır bakış açısı, bu güne kadar kimseye zarar getirmemiştir 🙂 Ayrıca yalnızca öğrenecek şeyleri olduğunu kabul edenler, kestirmesi olmayan uzun yolların sonunu görebilirler diye düşünüyorum. Bu vesileyle ben de zamanları boşa harcamayacak şekilde yazmayı sürdüreceğim 🙂 Bu süreçten büyük keyif alacağımı hissediyorum.

Dilerim ki sizler için de eğlenceli olur.

NOT: Yazı dizisi’nin ikinci yazısı “Merhaba PIC16” 7 Mart Cumartesi yayınlanacak.

Yazıları beğendiyseniz eğer,  faydalanabilecek arkadaşlarınızla da paylaşabilirseniz sevinirim.

Şimdi devam…

Önceki Sayfa   Sonraki Sayfa

XBee Kullanımı

Merhabalar arkadaşlar, eski blog sayfamı artık güncellemeyeceğimden, oradaki önemli bir yazıyı buraya taşımak istedim. XBee kullanımı üzerine yazdığım yazı, beklentilerimin ötesinde bir ilgi görmüştü ve zaman içerisinde özellikle resimlerin uçmasından ötürü çok sayıda kişi, resimleri güncellemem için benimle iletişime geçmişti. Bu vesileyle hem resimleri güncelleyeceğim hem de yazıyı buraya taşımış olacağım.

RF haberleşmesinin ne kadar sık kullanılan bir haberleşme teknolojisi olduğu su götürmez bir gerçek. Günümüzde RF haberleşme bir ham veri kümesini radyo dalgalarıyla aktarmaktan fazlasını ifade ediyor. Zigbee kavramı da burada ağırlığını ortaya koymuş, hatta ve hatta stratejik önemi haiz olmuş bir kavram olarak karşımıza çıkmaktadır (ne dedim !?  :D)

Zigbee aslında bir protololdür. Jennic firmasının Jennet protokolü gibi… xBee ise bu haberleşme protokolünü taşıyan bir donanımdır.

MaxStreamXBeeModules

 

Bu blog yazımda iki adet xBee’nin haberleştirilmesi işleminin nasıl yapıldığı ve gerekli alt yapı bilgilerini aktarmaya çalışacağım.
PAN ( Personal Area Network )
xBee modüllerinde tüm haberleşme işlemleri bir PAN üzerinden yapılmaktadır. Haberleşmenin gerçekleşebilmesi için mutlaka ama mutlaka bir PAN oluşturulmalıdır. PAN oluşturulmadığında hiç bir xBee cihazı faaliyet gösteremeyecektir. Bir PAN’ı ancak bir “Coordinator” oluşturabilir. PAN yönetimi ile ilgili bilgilere raporun ileri ki kısımlarında değineceğiz.
Bir PAN içinde bulunan tüm cihazların PAN ID’si aynı olmalıdır. Bunu daha teknik biçimde açıklayacak olursak aslında “coordinator” tarafından oluşturulan PAN’a katılmak isteyen tüm cihazların PAN ID’leri mutlaka “coordinator” cihazın PAN ID’si ile aynı olmalıdır. Aksi taktirde cihaz ağa kabul edilmez. Ağa kabul işlemleri ile ilgili daha geniş bilgilere ileri ki kısımlarında değineceğim.
Ağ Oluşturma:
xbee_create_pan
Yukarıda örnek bir PAN görmektesiniz. C, R ve E türü cihazların özelliklerini açıklayalım.
C , “Coordinator” :
Haberleşme kanalını ve PAN ID’sini belirler. Bir PAN’ın başlatılmasından C sorumludur. PAN’ı başlattıktan sonra C, E ve R’lerin PAN’a katılmasına izin verebilir. C veri alıp yollayabilir, ya da mesh network yapısında verinin bir sonrki cihaza iletilmesi işlemlerini gerçekleştirebilir. C tüm ağı yönettiğinden pil ile beslenmesi ve/veya düşük güç modlarında çalıştırılması kesinlikle uygun değildir. C sabit bir güç kaynağı ile beslenmeli ve “main power mode” dediğimiz standart güç modunda çalıştırılmalıdır. C’nin işlevini kaybetmesi, tüm ağın çökmesi anlamına gelmektedir.
R, “Router” :
Bir R’nin çalışabilmesi için öncelikle bir PAN’a katılması gerekir. PAN’a katıldıktan sonra R, diğer R’lerin ve E’lerin (End Point) PAN’a katılmasına izin verebilir. R veri alıp yollayabilir ya da mesh network üzerinde veri aktarımını sağlayabilir. R’ler diğer cihazların PAN’a katılmasına izin vereceklerinden düşük güç modlarında çalıştırılmaları uygun değildir.
E, “End Device”:
R’de olduğu gibi E’de çalışabilmek için öncelikle bir PAN’a katılmalıdır. E diğer cihazların PAN’a katılmasına izin veremez, ancak mesh network üzerinde veri iletimi yapabilir.
Cihazların işlevlerini okuduktan sonra, yukarıdaki iletişim diyagramının tekrar incelenmesi faydalı olacaktır.
Xbee Konfigürasyonu
xBee’lerin konfigüre edilmesi için bir çok araç bulunmamaktadır ancak bunlar içerisinde en çok kullanılan ve en güvenilir olan digi firmasının bizzat ürettiği x-ctu yazılımı-dır. Tamamen ücretsiz olan bu arayüz ile xBee ile ilgili hemen her işlemi gerçekleştirebiliyo-ruz. Bu program üreticinin web sitesinden indirilebilir.
C Konfigrasyonu:
C’yi broadcast modda çalıştırıyoruz. Bunun için yapmamız gerekenler:
PAN ID belirlenir, (ID)
Scan Channels belirlenir, (SC)
Scan Duration belirlenir (opsiyonel) (SD)
Destination Low Adress belirlenir: DL = 0xFFFF yapılır.
Destination High Adress belirlenir: DH = 0 yapılır.
NI belirlenir: NI = COORDINATOR
İlgili konfigrasyon ekranı aşağıdaki gibidir:
xbee_c_config
R Konfigrasyonu:
R unicast modda programlanmalıdır.
SC ve ID değerleri seçilir (PAN’a göre yani C’ye göre)
CH ve OP kontrol edilir
MY belirlenir, bu routerın 16 bitlik network adresidir.
DH = 0 yapılır.
NI = ROUTERNAME yapılır
Ekran aşağıdaki gibidir:
xbee_r_config
ÇOKLU AĞ KURMA
xBee’ler ile mesh network kurmak için yapılması gerekenlere değineceğimiz bu kısımdaki işlemler temelde 2 ana başlık altında toplanabilir. Bunlardan bir tanesi AT komutları, diğeri ise konfigürasyon.
AĞ 1:
Kurmak istediğimiz basit ağ yapısı, 1 koordinatör ve 3 router cihazdan oluşacak. Öncelikli olarak koordinatör cihazdan yayın yaparak tüm router cihazlar ile aktif veri alışverişi kuracağız.
xbee_nw1
Yukarıda çizmiş olduğumuz diyagramda görüleceği üzere koordinatör router cihazlara yayın yapmakta, bununla birlikte de router cihazlar koordinatöre veri yollayabilmektedir.
Cihazları yukarıdaki çalışma için konfigüre ederken, öncelikli olarak xctu yazılımında fonksiyon seti olarak ROUTER/END DEVICE AT seçilir. Daha sonra Show Defaults butonuna basılır. sonrasında da PANID belirlenir. Biz bu uygulamada PANID olarak 0x100 değerini girdik. 3 router’ı da konfigüre etttiğimizde operating PANID olarak gördüğümüz değer 0xFFFF olmalıdır. Bunun sebebi ise xBee’lerin aynı PANID’li bir koordinatör bulamaması ve ilgili PAN’ın açılmasını beklemesidir. Bu durumda Router’lara ilişkin konfigürasyon aşağıdaki gibidir:
xbee_cnf_nw1
Koordinatör cihazı konfigüre etmek için ise, function set kısmı COORDINATOR AT olarak seçilir. Daha sonra Show Defaults butonuna basılır. Bundan sonra da PAN ID seçilmelidir. PAN ID’yi yine 0x100 seçeceğiz. Daha sonra read butonuna bastığımızda operating channel’ın 0x0E olduğunu gördük. Bu değer farklılık gösterebilir.
xbee_cnf2_nw1
PAN oluşturulduktan sonra tekrar router cihazları xctu programı yardımıyla gözlemlemeliyiz. Bunun için yine ilgili modüle bağlandıktan sonra modem konfigrasyonu sekmesi açılmalıdır ve read butonuna basılmalıdır. Bunu yaptığınızda tüm modemlerin operating channel değerinin koordinatör cihaz ile aynı olduğunu göreceksiniz. Bu da router/end cihazların personal area network(PAN) içine başarıyla katıldığını göstermektedir.
Bu ayarları yaparken tüm modüllerin aynı seri haberleşme parametrelerini taşıdığından emin olmak gerekir, eğer bir modül handshaking isterken diğeri istemiyorsa ya da arada baudrate, parity, stop bit gibi farklılıklar varsa haberleşme gerçekleşmeyecektir. Bu haberleşmenin başarılı olduğunu aşağıda 1 defaya mahsus olarak gösteriyoruz, bundan sonraki ağ yapılarında bu şekilde olduğu gibi ekran çıktıları ile gösterim yapılmayacaktır. Benzer basamaklar kullanılarak tüm yapılar kolaylıkla test edilebilir.
 Koordinatör Xbee:
xbee_c_pan

Router 1 Xbee:

xbee_r_pan

Router 2 Xbee:
xbee_r2_pan
Router 3 Xbee:
xbee_r3_pan
Görüldüğü üzre planladığımız ağ yapısı beklentilerimize uygun olarak çalışmıştır. Yukarıda gördüğünüz mesajlardan kırmızı olanlar cihazın aldığı mesajlar, mavi olanlar ise cihazın gönderdiği mesajlardır. Buna göre koordinatör herkese mesaj göndermiş ve herkesten mesaj almıştır. Bu sayede ağ yapılarına ilişkin ilk uygulama tamamlanmış oldu.
AĞ 2 (Point to MultiPoint Bidirectional Network)
Bu ağ yapısı çoğunlukla kullanacağımız ağ yapısıdır. Bu ağ yapısı sayesinde bir merkezin kontrolünde istediğimiz haberleşme sistemini rahatlıkla kurabilmekteyiz. Ağ yapısı ise aşağıdaki gibidir:
xbee_cnf_nw2
Yukarıdaki sistemde koordinatör yayın yapmamaktadır. Router/End cihazlar doğrudan merkez ile haberleşmektedirler. Bu yapıda koordinatör bir anlamda server, router ise client gibi düşünülebilir. Her xBee ağında olduğu gibi burada da koordinatörün gücünün kesilmemesine dikkat edilmelidir.
Yukarıdaki yapı gibi bir çok farklı ağ yapısı düşünülebilir.Bu yapıların kurulmasında artık arayüzden ziyade AT komutlarından yararlanacağız. Bunun nedeni ise xBee modüllerini OHM’ler ile kontrol edecek olmamızdır. Dolayısıyla xBee modülüne ilişkin yapacağımız her türlü değişiklik seri haberleşme ile sağlanacaktır. Şimdi de yukarıdaki sistemi oluşturmak için yapmamız gerekenlere değinelim.
  1. Öncelikli olarak bir önceki uygulamada yani AĞ1’deki gibi bir yapı kurulur.
  2. Tüm router’lar için aşağıdaki işlemler yapılır
    1. Koordinatör cihaza terminal vasıtası ile “+++” komutu yollanır. Bu 2 saniyelik bir süre için xBee’yi komut moduna sokar.
    2. Zaman geçirilmeden “ATSH” komutu yollanır. Okunan değer not edilir.
    3. Hemen ardından “ATSL” komutu yollanır ve bu değer de not edilir.
    4. Daha sonra da “ATWR” komutu yollanır.
  3. Routerların tümü için sırayla aşağıdaki adımlar izlenir:
    1. “+++” komutu ile komut moduna geçilir.
    2. “ATDLkoordinatörSL” komutu işletilir. KoordinatörSL yazdığımız kısma 2. adımda not etmiş olduğumuz SL değeri yazılır. Örneğin “ATDL1A3252” gibi bir komut yollanabilir.
    3. “ATDHkoordinatörSH” komutu işletilir. KoordinatörSH yazdığımız kısma 2. adıma not etmiş olduğumuz SH değeri yazılır. “Örneğin ATDH402D5DA9” gibi bir komut yollanabilir.
    4. Bu adımlar tamamlanınca router koordinatöre veri yollamak üzere konfigüre edilmiş demektir. “ATWR” ile işlem sonlandırılır.
  4. Koordinatörden herhangi bir router cihaza veri yollamak için yapılması gerekenler 3. adımda router’a yaptığımız ile neredeyse aynıdır. Hangi router’a veri yollamak istiyorsak DH ve DL adreslerine onun adresini girebilir ve sırayla istediğimiz cihaza veri yollayabilir. Bu veri yollama rutininde xBee ağlarının tüm özellikleri devam eder.

 

Umarım işinize yarar 🙂

Yazıları beğendiyseniz eğer,  faydalanabilecek arkadaşlarınızla da paylaşabilirseniz sevinirim.

Şimdi devam…