STM32F030 PROGRAMLAMA YAPISI-GPIO UYGULAMASI- LED YAKMA

                                                           GPIO UYGULAMASI-LED YAK

Uygulamalarda elimden geldiğince az kütüphaneden yararlanmaya çalıştım çünkü ne kadar periphal library nesnelerini kullanırsanız bir nevi yolu uzatmış oluyoruz ve bellek kullanımı 2 3 katına çıkıyo bunu aşağıdaki  uygulama ile ispatlayalım.

111

Yukardaki iki program tamamen aynı işi yapmaktadır fakat görüldüğü gibi periphal kütüphanesinin fonksiyonları kullanılarak gerçekleştirildiğinde kod boyutu 2 katından fazla artmaktadır.Kullanışlılık açısından daha iyi olduğu söylenebilir fakat programlarken ne yaptığınızı görmek açısından fonksiyonların az kullanımının daha mantıklı olduğuna inanıyorum.

Şimdi işin en önemli kısmına geçeceğim bu kısım programlama mantığının ve ifadeler ne anlama geldiğinin anlaşılması için çok önemli.İlk olarak kütüphane fonksiyonlarını kullanarak nasıl yazdığımıza bakalım.

Ben uygulamalarımda stm32f030 discovery kitini kullanıyorum ve üzerinde stm32f030R8T6 mikrodenetleyicisi var.Bu kit üzerinde 2 adet led bulunmakta mavi olan C8 pinine ,yeşil olan ise C9 pinine bağlı.

#define MAVI GPIO_Pin_8    //pin8 e mavi etiketi verdim

#define YESIL GPIO_Pin_9   //pin 9 a yeşil etiketi verdim

Bu komutlar ile her pin_8 ve pin_9 u kullanmak istediğimde sadece MAVI ve YESIL yazmam yeterli olacak.

ilk komutumuz olan;

GPIO_InitTypeDef pinler:Bu ifade ile bir GPIO_InitTypeDef tipinde bir pinler nesnesi tanımlanıyor.Şimdi bunu daha iyi anlatmak için programın bu kodu işlediğinde aslında ne yaptığına bakalım.

GPIO_InitTypdef struct

GPIO_InitTypeDef’e sağ tıklayarak goto “definition of GPIO_InitTypeDef” e tıklarsanız yukarıdaki kod parçacığına ulaşırsınız.Görüldüğü gibi bu kod parçacığı bir struct tanımlamaktadır.Yani bu struct yapı türünden tanımlanan herhangi bir nesne içerisindeki elemanlara ulaşabilmektedir.Bu elemana ulaşma işlemi . operatörü kullanılarak yapılır.

Yukarıdaki typedef tanımlaması ile int,double vs. gibi yeni bir tip olarak GPIO_InitTypeDef tipi tanımlamış oluyoruz ve bu tipten elemanlar tanımlayabiliyoruz.Bu yapının elemanları herhangi bir tipten elemanlar olabilir mesela GPIO_Pin uint32_t tipinde bir yapı elemanı,GPIO_Mode ise aynı GPIO_InitTypeDef gibi kütüphaneyi hazırlayanlar tarafından oluşturulmuş bir tip olan GPIO_Mode_TypeDef tipinden bir elemandır.Şimdi GPIOMode_TypeDef’in içine girelim.

GPIOMode_TypeDef ENUM

GPIOMode_TypeDef ifadesinin bir enum tanımladığı görülmektedir.Enum’un structdan farkı ise enum içerisinde sadece değişkenlere sabitler atanır.Yani 0x00 yazmak yerine GPIO_Mode_IN yazmamızı sağlar buda bize kodlamada kolaylık getirir.

ikinci Komutumuz İse RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);

Bu komut ile C portunun clock almasını sağlıyoruz.Bu bizim kullanılmayan portlara gereksiz yere clock vermemizi engeller ve güç tasarrufu sağlar.Bu komutla clock verilmeyen portlar çalışmazlar.Peki bu fonksiyonun yaptığı iş ne ona bakalım;

portc_clock_ayarı

RCC->AHBENR komutu bizim ikinci programda kullandığımız clock verme komutudur.Görüldüğü gibi fonksiyon 2 parametre alıyor.İlk parametre clock ayarı yapılacak portu,ikinci parametre ise açılıp kapatılma durumunu belirtmektedir.

pinler.GPIO_Pin=MAVI:Bu komut ile portun hangi pinleri üzerinde işlem yapacağımızı belirtiyoruz.Bunu yaparken GPIO_InitTypeDef tipinde tanımladığımız pinler nesnesini kullanıyoruz. pinler.GPIO_Pin komutu ile GPIO_InitTypeDef tipinin GPIO_Pin  değişkenine ulaşıyoruz ve değerini belirliyoruz. pinler.GPIO_Pin değişkeni içerisine bir değer atamış oluyoruz.Bu değer MAVI etiketiyle belirttiğimiz GPIO_Pin_8 dir.

pinler.GPIO_Mode= GPIO_Mode_OUT: Bu komut ile belirttiğimiz pinin çıkış olarak ayarlanmasını sağlıyoruz. GPIO_InitTypeDef yapısının bir elemanı olan ve GPIOMode_TypeDef tipindeki GPIO_Mode elemanının içeriği belirleniyor. GPIO_Mode_OUT(0x01) değeri pinler.GPIO_Mode değişkeni içerisine atanıyor.

pinler.GPIO_OType=GPIO_OType_PP:Çıkış tipini belirlemek için kullanılan fonksiyondur.Bu örnekte push-pull olarak ayarlanmıştır.

pinler.GPIO_Speed=GPIO_Speed_2MHz:Pinin hız ayarının yapmak için kullanılır.En düşük hız olan 2MHz ayarlanmıştır.

pinler.GPIO_PuPd=GPIO_PuPd_NOPULL:Pull-up ve Pull-down ayarlarının yapıldığı kısımdır.Burda pull-up ve pull-down direnci kullanılmamıştır.

GPIO_Init(GPIOC,&pinler):Yukarıdaki tanımlarda belirlediğimiz ayarların hangi port için olduğunu bu fonksiyonla bildiriyoruz.Bu fonksiyonun yaptığı iş pinler olarak tanımladığımız GPIO_InitTypeDef tipindeki pinler nesnesinin adresini gönderiyoruz.Adres atamamızın sebebi ise bu fonksiyonun tanımlamasında görüldüğü gibi GPIO_InitTypeDef* GPIO_InitStruct GPIO_InitTypeDef tipinde bir pointer tanımlanmasıdır.Pointerlar değer olarak adres göndermek zorundayız.Pointer kullanımı kalıcılık sağlamak içindir.

GPIO_SetBits(GPIOC,MAVI):Son komutumuz ise MAVI olarak tanımladığımız CPortunun 8 numaralı pinini lojik 1 yapma işlemidir.

                                               DOĞRUDAN ERİŞİMLE PROGRAMLAMA

Bundan sonra olabildiğince kullanmaya calışacağım periphal kütüphanenin fonskyonlarının az kullanıldığı komutlara geçiyorum.

RCC->AHBENR|=RCC_AHBENR_GPIOCEN;

Bu komut ile C portunun clock sinyalini aktif hale getiriyoruz.Bu işlemi mikrodenetleyici içerisindeki RCC_AHBENR registerındaki gerekli pin ayarlamalarıyla gerçekleştiriyoruz.Şimdi bunu nasıl yaptığına bakalım.Kütüphane içerisinde zincirleme bir şekilde bu registera erişim sağlanmaktadır.

#define RCC                 ((RCC_TypeDef *) RCC_BASE)

#define RCC_BASE              (AHBPERIPH_BASE + 0x00001000)

#define AHBPERIPH_BASE        (PERIPH_BASE + 0x00020000)

#define PERIPH_BASE           ((uint32_t)0x40000000)

RCTYPDEF

Görüldüğü gibi zincirleme bir şekilde RCC ye RCC_TypeDef tipinde bir adres atanmıştır.RCC bu adresi tutan bir pointerdır.Bu nedenle RCC ile RCC_TypeDef tipinin CR,CFGR,AHBENR gibi elemanlarına ulaşmak için . yerine -> kullanmamız gerekmektedir.

Şimdi ise RCC_AHBENR_GPIOCEN ifadesinin aslında ne olduğuna bakalım.

#define  RCC_AHBENR_GPIOCEN                  ((uint32_t)0x00080000)

Görüldüğü gibi biz RCC_AHBENR_GPIOCEN   ifadesini çağırarak ((uint32_t)0x00080000) hex sayısını çağırmış oluyoruz.Daha sonra bu hex sayıyı RCC_AHBENR registerının içine atıyoruz.Fakat bu işlemi yaparken | (or) işlemi kullanarak atıyoruz.Çünkü biz sadece ilgili bitlerin değişmesini istiyoruz ,eğer direk atama yaparsak diğer bitleri 0 yapmış oluruz.Yapılan işlem 0x00080000 sayısı ile RCC_AHBENR registerının içeriğini orlayıp tekrar RCC_AHBENR registerına atmaktır.Şimdi bu ifadenin registerda yapacağı değişikliğe bakalım;

RCC_AHB_REGİSTER

8 sayısı binary olarak 1000 ifadesine eşittir.Görüldüğü gibi 0x00080000 ifadesi ile bu registerdaki IOPCEN bitini 1 yapıyoruz ve C portunun clock sinyalini aktif ediyoruz.

GPIOC->MODER|=GPIO_MODER_MODER8_0;

C portunun ilgili pinin hangi modda kullanılacağını belirleyen komuttur.Üst tarafta yaptığımız zincir olayını burdada gösterelim.

#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOC_BASE            (AHB2PERIPH_BASE + 0x00000800)

#define AHB2PERIPH_BASE       (PERIPH_BASE + 0x08000000)

#define PERIPH_BASE           ((uint32_t)0x40000000)

GPIO_TYPDEF

Daha önce anlattığım gibi GPIOC  GPIO_TypeDef tipinde GPIOC_BASE adresini tutan bir pointerdır.Bu pointer GPIO_TypeDef’in elemanları olan MODER,OTYPER,PUPDR elemanlarına erişebilmektedir.Pointer olduğunu için bu erişimi . yerine -> operatörüyle yapılmaktadır.

Şimdi GPIO_MODER_MODER8_0        tanımlamasına bakalım.

#define GPIO_MODER_MODER8_0        ((uint32_t)0x00010000)

Biz GPIO_MODER_MODER8_0     ifadesini GPIOx_MODER registerına yükleyerek aslında 0x00010000 sayısını yüklemiş oluyoruz.Yine yükleme işlemini |(or) işlemi kullanarak yapıyoruz.Şimdi registerda neyi değiştirdiğimize bakalım.

GPIOx_Moder

Ayarlanabilecek 4 mod olduğu için her pin için 2 adet bit gerekmektedir.Yani ilk 2 bit 0.pinin modunu,ikinci 2 bit 1.pinin modunu… şeklinde devam etmektedir.Bizim gönderdiğimiz 0x00010000 verisi ise 8  numaralı pini 01 yani çıkış olarak ayarlamaktadır.

GPIOC->OTYPER&=~GPIO_OTYPER_OT_8;

 Bu komut ile çıkışın push-pull veya pull-up olma durumunu belirliyoruz. Şimdi GPIO_OTYPER_OT_8 ifadesinin ne anlama geldiğine bakalım.

#define GPIO_OTYPER_OT_8           ((uint32_t)0x00000100)

GPIOx_OTYPER registerı 32 bitlik bir registerdır fakat her pin için 2 adet çıkış durumu söz konusu olduğundan her pin tek bit ile kontrol edilebilmektedir.Bu register değerini atarken |(or) işlemi kullanılmamış veri terslenip GPIOx_OTYPER registerıyla andlenerek yine GPIOx_OTYPER registerında aktarılmıştır.Bu şekilde yapmamızın sebebi çıkışı push-pull yapmak istememizdir.Yani önceki atamaların aksine ilgili pini 0 yapıp ,diğer pinleri etkilememeyi amaçlıyoruz.

GPIO_OTYPER_OT_8 =0x00000100

~GPIO_OTYPER_OT_8 =0x11111011

Bu değer ile GPIOx_OTYPER registerı andlenirse 1 olan bitler aynı değerlerinde kalırken,pin 8’i ifade eden 9. pin 0 olarak ayarlanıcaktır.

OTYPER_REGISTER

GPIOC->OSPEEDR&=~GPIO_OSPEEDR_OSPEEDR8;

Bu komut ile GPIOx_OSPEEDR registerındaki ilgili bitleri değiştirerek pinin çalışma frekansını ayarlayabliliyoruz.3 hız seçeneği olduğu için her pin için 2 bitlik bir alan ayrılmıştır.

#define GPIO_OSPEEDR_OSPEEDR8     ((uint32_t)0x00030000)

Biz en düşük hızla yani 2MHz hızla çalışmak istiyoruz bu nedenle ilgili bitleri 00 yapmalıyız.OTyper için yaptığımız gibi ilgili bitleri sıfır yapıp diğer bitleri etkilememek için tersleyip andleme yönetemini kullanıyoruz.

SPEEDR_REGISTER

GPIOC->PUPDR&=~GPIO_PUPDR_PUPDR8;

Pinin pull-up/down veya no pull up/down olarak seçilmesi işleminin yapıldığı regiterdır.3 durum olduğu için en az 2 bit ile ayarlama işlemi yapılabilmektedir.Biz pinimizi nopull-up/down olarak kullanacağımız için ilgili pinin bitlerini 00 yapıp diğer bitleri etkilememeliyiz.Bunun için yine tersleyip andleme yöntemini kullanıyoruz.

#define GPIO_PUPDR_PUPDR8          ((uint32_t)0x00030000)

 

GPIOC->BSRR=MAVI;

GPIOx_BSRR registerı çıkışı bitsel olarak kontrol etmek için oluşturulmuş özel bir registerdır.GPIOx_ODR registerıyla görevi aynıdır fakat  GPIOx_ODR registerına veriler word(32bit) olarak gönderilir.Yani;

GPIOC->BSRR=MAVI: Bu ifade sadece 1 olan bitleri set eder diğer bitlerin değerlerine dokunmaz.

GPIOC->ODR=MAVI:Bu ifade ise 1 olan bitleri set ederken sıfır olanlarıda registera yazar.Bu diğer bitlerin değerlerinin istenmeyen şekilde değişmesine sebep olur.

GPIOC->ODR|=MAVI:Bu komut ile diğer bitleri değiştirmeden BSRR registerının yaptığı işlemin aynısı yapılabilir.Dikkat edilecek nokta |(or) işeminin kullanılmasıdır.Or işlemi sayesinde sadece ilgili bitler set edilip diğer bitlerin değeri değişmemiştir.

GPIOC->BRR=MAVI:Bu komut ise tamamen BSRR komutunun yaptığı işlemin tersini yapar.Yani mavi içerisinde set edilen biti 0 yapar.

NOT:AÇIKLAMALARDA GÖRDÜĞÜNÜZ GİBİ BİR VEYA DAHA FAZLA BİTİ SET EDİP DİĞER BİTLERİ ETKİLEMEK İSTEMİYORSANIZ |(OR) İŞLEMİNİ KULLANMANIZ GEREKİYOR.FAKAT EĞER BAZI BİTLERİ 0 YAPIP DİĞER BİTLERİ ETKİLEMEK İSTEMİYORSANIZ O BİTLERİ 1 YAPAN İFADELERİ TERSLEYİP &(AND) İŞLEMİNİ KULLANMANIZ GEREKMEKTEDİR.

Yorum bırakın