Led Yakıp Söndürme Uygulaması
Standart uygulamamız sanırım sizinde tahmin ettiğiniz gibi bir led yak söndür uygulaması.Bir önceki yazımızda CoIDE nin nasıl kurulup yapılandırılacağını anlatırken standart bir uygulama ekleyerek Bllink adlı bir uygulama oluşturmuş ve bu uygulamayı derleyerek CoIDE kurulumumuzun doğru biçimde yapılandırıldığını sınamıştık.
Bu bölümde işte bu standart uygulamanın nasıl oluştuğunu hangi standart kütüphanelerin kullanıldığını neden kullanıldığını ve kodlarımızı satır satır açıklayacağız.
Umarim kafalarda soru işaretleri bırakmayan bir anlatım gerçekleştirmiş olurum. (Lütfen eleştirmekten çekinmeyin ki bende hem uslubumu hem anlatımımı mükemmelleştirebileyim.)
Eveeet gelelim maydanozun fayladalarına...
İlk olarak kodumuzu genel anlamda bir görelim :
/**
* Project template
*
* @author Tilen Majerle
* @email tilen@majerle.eu
* @website http://majerle.eu
* @version v1.0
* @gcc v4.7 20013qr3
* @ide CooCox CoIDE v1.7.6
*/
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
int main(void) {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_InitTypeDef GPIO_InitDef;
GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
//Initialize pins
GPIO_Init(GPIOG, &GPIO_InitDef);
volatile int i;
while (1) {
// Toggle leds
GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
// Waste some tome
for (i = 0; i < 500000; i++);
}
}
Öncelikle bu çalışmaları tüm dünya ile paylaşma nezaketini gösteren Sayın Tilen Majerle bir defa daha bu vesile ile teşekkür etmek istiyorum. Ki kodun başlığındaki tanımlama satırlarını özellikle kaldırmadım ki kendisinin emeğine saygısızlık etmiş olmayalım...
Kodumuzu açıklamaya başlıyoruz.
İlk olarak kodumuzun başında "#include" komutu ile başlayan üç adet tanımlama görülmektedir.
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
Bu komutlar yazılım boyunca kullanacağımız ve kod yazarken kullanacağımız bir takım ön tanımlı foksiyonları ve mikrokontrolcü çekirdek tanımlamalarını içeren kütüphanelerdir.
Bunlara kısaca bir göz atacak olursak ;
#include "stm32F4xx.h" komutu temel mikrokontrolcü çekirdek tanımlamalarını içeren ve yazılımımızın tamamında kullanmamızı gerektiren çekirdek registerlarını tanımlayan bir kütüphanedir ki olmazsa olmazımızdır diyebiliriz. Bu kütüphane olmadan CoIDE bizim hangi kontrolcüyü kullandığımızı ve ne için kod yazdığımızı anlamasına imkan yok.
Bu kütüphane stm32F4xx serisi mikro kontrollerin datasheet'lerinde belirtilen tüm işlem basamaklarının temllerini sisteme tanıtır.
Bu kütüphane aynı zamanda CoIDE kod alanının solunda yer alan ve project tabında gördüğümüz cmsis_boot ana kütüphanesinin de içeriğidir ki cmsis_boot eklenmediği taktirde kodumuz çalışmayacaktır.
Aynı şekilde cmsis_core ARM mimarisinin çekirdek yapısını tanımlaması sebebiyle bulunması zorunlu olan, cmsis_lib ise GPIO, SPI, DAC, ADC, USART, SPI ve benzeri yapıların alt kütüphanelerini barındıran ve tanımlamalarımızda bizlere kolaylık sağlayan bir ana kütüphanedir.
Bu kısmı daha fazla uzatmadan kısaca geçiyorum, daha fazla ayrıntılı bilgi almak istemeniz halinde STM32F4xx datasheet lerini ve STM sitesindeki diğer dökümanları okumanızı tavsiye ederim.
gelelim kodlarımıza...
Kodları açıklamaya başlamadan önce biraz daha kafanızı şişirmek sorunda olduğum ve ciddi ciddi anlatılması gereken cmsis_lib kütüphanesinde bulunan GPIO'yu irdelememiz gerekmekte.
Öncelikle GPIO ne demek ?
Genel Amaçlı Giriş/Çıkış anlamına gelen (General Purpose Input/Output) kelimelerinin kısatmasıdır.
Mikrokontrolcülerin dış dünyaya açıldıkları ve bizlerin yazılımla hükmettikleri pinlere verilen genel bir addır aslında.
Biz programımızda bu GPIO pinlerinden 2 tanesini kullanarak iki adet ledi yakıp söndürmeyi amaçladık. Ama nasıl ? bu GPIO pinlerine nasıl hükmedeceğiz ?
İşte işin can alıcı kısmı şimdi başlıyor !
GPIO pinlerini giriş yada çıkış olarak tanımlayabilir, düşük "0" yada yüksek "1" olarak ayarlayabilir, pinlerin işlemci içerisinde Pull Up dirençlerini aktif yada deaktif edebilir (amaç portları "unstate" "belirsiz durum" da kalmaktan kurtarmaktır), çıkış tipini belirleyebilir yada çalışma hızını tanımlayabiliriz.
Peki bütün bu tanımlamalar nasıl yapılacak ? (Biraz sabır bombayı patlatıyoruz.)
I/O pinleri ile çalışabilmek için ilk işlem pin clock(saat) larını set etmektir (ayarlamaktır).
Pin saatlerini aktif edebilmek için RCC tanımlayıcısını (registeri'nı) kullanmamız gerekecek. RCC (Reset and Clock Control) Sıfırlama ve Saat Kontrol anlamına gelir.
Bütün GPIO'lar AHB1 veri yolu üzerinde konumlanmıştır. (Bkz stm32F429ZI datasheet) Biz bu veri yolu üzerindeki GPIO G port'unu kullanacağız çünkü STM32F429I Discovery kartındaki kırmızı ve yeşil ledler bu portun PG13 ve PG14 numaralı pinlerine bağlıdır.
İşte bu ledleri yakabilmek için ilk kod satırımızda pinlerin clock larını aktif hale getirmemiz gerekiyor.
Bunuda ;
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOG, ENABLE);
kodu ile yapacağız.
Yukarıdaki kod parçacığında RCC tanımlayıcısına AHB1 veriyolundaki çevrebiriminin saat tanımlama parçacığına GPIOG portunu kullanmak istediğimizi ve bu portun saat çevrimini aktif hale getirmesini söyledik.
Bir sonraki adımda artık pin seçeneklerinin üzerinde oynayabilmek için GPIO_InitTypeDef tipinde bir değişken tanımlamamız gerekmekte.
Eğer projemize GPIO kütüphanesini tanımlamışsak ki #include "stm32f4xx_gpio.h" tanımıyla bunu yapmıştık bu tip değişkenini şu şekilde oluşturuyoruz ;
GPIO_InitTypeDef GPIO_InitDef;
Burada GPIO_InitDef Değişkeni GPIO_InitTypeDef tipinde tanımlanmıştır. Bu sayede pinlerimize ait tipler bu değişken altında kullanılabilir hale geldi.
GPIO_InitTypeDef tipinin pinlerin kullanımına yönelik 5 adet tanımlama tipi mevcuttur.
Bunlar sırasıyla :
- GPIO_Pin
Ayarlamak istediğimiz pin tanımını belirleyen tiptir.
- GPIO_Mode
Olay modlarını belirleyen tiptir.
- GPIO_OType
Çıkış türünü belirleyen tiptir.
- GPIO_PuPd
Pull Up dirençlerini belirleyen tiptir.
- GPIO_Speed
Pin saat hızlarını belirleyen tiptir.
Buradaki her bir tip tanımının kendisine göre seçenekleri vardır. Ki tek tek ele alacak olursak :
- GPIO_Pin Bu tip ile kullanacağını pinleri tanımlayabilirsiniz. Peki bunu nasıl yapabiliriz ? Kod örneklerini yazıp inceleyelim...
//Tek bir pin tanımlamak için örneğin GPIO_Pin_13
GPIO_InitDef.GPIO_Pin = GPIO_Pin_13;
// Eğer aynı ayarlarda daha fazla pin kullanmak isterseniz
// Komut aynı ayarlarda olan Pin 13 ve pin 14'ü tanımlar
GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
// Bu komut ise GPIO pinlerinin tamamını aynı ayarla tanımlar
GPIO_InitDef.GPIO_Pin = GPIO_Pin_All;
- GPIO_Mode : Pin Olay Modlarını Tanımlar ve 4 Seçeneği Mevcuttur
GPIO_Mode_IN : Pin'i giriş olarak tanımlamakta kullanılır.
GPIO_Mode_OUT : Pin'i çıkış olarak tanımlamakta kullanılır.
GPIO_Mode_AF : Pin'i alternatif fonksiyonlar için tanımlamakta kullanılır (SPI,USART,I2C vb).
GPIO_Mode_AN : Pin'i Analog olaraktanımlamakta kullanılır (ADC veya DAC).
- GPIO_OType : Pinlerin çıkış tiplerini belirlemek için kullanılır iki seçeneği mevcuttur.
GPIO_OType_PP : Çıkış tipini Push Pull yapar.
GPIO_OType_OD : Çıkış tipini Open Drain yapar.
- GPIO_PuPd : Pull Up dirençlerini aktif yada deaktif yapmakta kullanılır.
GPIO_PuPd_UP : Pull Up direncini aktif yapmakta kullanılır.
GPIO_PuPd_DOWN : Pull Down direncini aktif etmekte kullanılır.
GPIO_PuPd_NOPULL : Pull UP yada Pull Down dirençlerini deaktif eder.
- GPIO_Speed : Pinlerin çalışma hızlarını belirlemekte kullanılır ve dört seçeneği mevcuttur.
GPIO_Speed_100MHz : Pin çalışma hızını 100MHz'e tanımlar.
GPIO_Speed_50MHz : Pin çalışma hızını 50MHz'e tanımlar.
GPIO_Speed_25MHz : Pin çalışma hızını 25MHz'e tanımlar.
GPIO_Speed_2MHz : Pin çalışma hızını 2MHz'e tanımlar.Şu ana kadar GPIOG portunu kullanabilmek için hangi tanımlayıcıları kullanmamız gerektiğini, bu tanımlamalar için hangi tiplerin bulunduğunu ve nasıl tanımlama yapacağımızı anlamaya çalıştık.
Şimdi ise bu bilgiler ışığında, PG13 ve PG14 pinlerini kullanarak bordumuz üzerindeki kırmızı ve yeşil ledleri yakmaya çalışalım.
Öncelikle pin tanımlarımız nasıl olmalı ?
Biz pinleri kurarken ; çıkış olarak kullanmak üzere, Push Pull çıkış tipinde, Pull Up yada Down direnci kullanmadan 50MHz hızında bir port tanımı yapmak istiyoruz.
O halde kodumuz bu bilgiler ışığında şu şekilde yazılmalı.
- //GPIOG portunu tanımlayıp saatini aktive edelim
- RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOG, ENABLE);
- // GPIO_InitDef değişkenimizi GPIO_InitTypeDef tipinde oluşturalım.
- GPIO_InitTypeDef GPIO_InitDef;
- // Şimdi Pin13 ve Pin14 ü kullanacağımızı belirtiyoruz.
- GPIO_InitDef.GPIO_Pin = GPIO_Pin_13|GPIO_Pin14;
- // Çıkış Modunu Tanımlıyoruz
- GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
- // Çıkış Tipimizi Push Pull yapıyoruz
- GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
- // Push Pull Kullanmayacağımız için hepsini deaktif hale getiriyoruz
- GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
- // Ve pin çalışma Hızımız 2MHz olacak şekilde tanımlanacak
- GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
ama bu noktaya kadar yazdığımız kodda sisteme portları kur ve kullan demediğimizi farketmişsinizdir.
stm34F4xx'e bunu söylemek için GPIO_Init(); komutunu kullanmamız gerekiyor
Aşağıda ilk GPIO fonksiyonumuz olan GPIO_Init(); i çağıracağımız #include "stm32f4xx_gpio.h" kütüphanesindeki tanım görülmektedir.
/**
* @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_InitStruct.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
//Şimdi pinlerimizi kurma işlemini başlatalım ve yaptığımız tüm ayarları geçerli kılalım.GPIO_Init(GPIOG, &GPIO_InitDef);
Bu komutla STM32F4'e GPIOG portunu ve GPIO_InitDef tanımlarının tamamını kullanıma hazırla dedik.
Şu anda pinlerimiz ledlerimizi kontrol etmemiz için kullanımımıza hazır.
Fakat ledlerimiz hala kapalı konumda (yanmıyor). Onları açık konuma getirmeliyiz.
Bunu 3 şekilde yapabiliriz. Bunlar sırasıyla...
- // PG13 ve PG14 Pinlerinin durumlarını "Yüksek" (High) yada "1" yapalım
- GPIO_SetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
Ya da eğer istersek Ledlerimizi tekrar "Düşük" (Low) yada "0" yapmak istersek ;
- // PG13 ve PG14 Pinlerinin durumlarını "Düşük" (Low) yada "0" yapalım
- GPIO_ResetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
Veya Pinlerin durumları arasında geçiş yapmakta mümkün. Yani led durumu "Yüksek" (High) yada "1" ise "Düşük" (Low) yada "0" yapmak istersek yada yam tersini o zaman kod dizlimimiz şu şekilde olmalıdır :
- // PG13 ve PG14 pinlerinin durumlarını değiştirelim.
- // Eğer pinler "Yüksek" durumdaysa "Düşük" olacak
- // Eğer pinler "Düşük" durumdaysa "Yüksek" olacak
- GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
Bunun için öncelikli olarak bir "i" değişkeni tanımlayalım.
volatile int i;programımızın sürekli çalışmasını istiyoruz ki ledler birkere yanıp södüğünde program durmasın ve sürekli yanıp sönme gözlemleyebilelim.
Ki bunun içinde while komutu ile bir sonsuz döngü oluşturacağız ve led durumunu bu döngü içinde değiştireceğiz. Bu durumda kodumuz :
While (1) {İşte uygulamamız sona erdi.
GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
for (i=0; i<500000; i++);
}
Şimdi kodumuzu CoIDE ile derleyip ST-Link Utility ile STM32F429I Discovery karımıza yükleyelim.
Ve Sonuç...
Umarım açıklamalarım sizler için çok sıkıcı ve uzun olamamıştır uygulamaya ilişkin soru ve önerilerinizi benimle paylaşırsanız çok minnettar kalırım.
Hepinize bol kod dolu günler dilerim.

Hiç yorum yok:
Yorum Gönder