STM32 – EXTERNAL INTERRUPT (STDPeriph)
Herkese merhabalar, bu yazımda External Interrupt yani harici kesmeleri STDPeriph kütüphanesi ile işleyeceğiz. Ben STM32F407VG kartını kullanacağım burda sizler istediğiniz kartı kullanabilirsiniz ama dökümandan hangi faz hattına hangi EXTI bağlı buna dikkat edin , mesela D portunu açılırken AHB1 üzerinden açılır fakat STM32F100RB kartı APB2 üzerinden açılır bu yüzden dökümanıza göre hareket edin.
Kodlar yukardan aşağıya doğru tek tek açıklanarak gidildi ve en sonunda tamamı verildi.
1-Kütüphaneyi ekliyoruz
#include "stm32f4xx.h"
2-Gpio , Exti ve Nvic kullacağımız için kütüphaneden bunları çağırıp uygun bir değişken ismi belirliyoruz.
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InicStrucutre;
GPIO (Genel amaçlı çevre birimleri); led veya buton gibi çevre birimlerini kullanmamıza olanak sağlar
EXTI (Harici kesem); Dışarıdan ekleyeceğimiz bir donanım ile kesmeye sokuyruz .
NVIC (Kesme Denetleyicisi); Cihaza birden fazla kesme gelir bu kesmlerin hangisi daha önce çalıştırılacak veya diğer ayarları nasıl olacak sorusuna cevap veren birim budur, kısacası kesmeleri kontrol eden birimdir.
3- void GPIOConfig() adında bir fonksiyon açıp içerisinde GPIO ayarlarını yapıyoruz.
Bu iki satırlık kod AHB1 faz hattından bulunan GPIOD ve GPIOA hattlarını Aktif eder (Clock’larını aktif eder). Sizin kartınız farklıysa AHB1 faz hattı yerine başka faz hattı olaolabilir.
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
Altaki kodlar ; GPIO için gerekli olan ayarlamalarını sağlar
// LEDS configuration
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD,&GPIO_InitStructure);
GPIO_Mode_OUT –> Modunu çıkış olarak gelirledik.
GPIO_OType_PP –> Çıkış olarak ayarlanan modu ‘Push Pul’ olacağını söyledik.
GPIO_Pin_12 –> 12. 13. 14. 15. pinleri kullanacağımı söyledik
GPIO_PuPd_NOPULL –> Pull-up ve Pull-down Kullanmaycağımı belirledik
GPIO_Speed_50MHz –> Bu pinlerin çalışma hızını 50Mhz olarak belirledik
GPIO_Init() –> En sonunda ‘init’ yani başlat diyerek tüm işlemleri kaydettik
// BUTTON configuration
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_Mode_IN –> Modunu giriş olarak ayarladık
GPIO_Pin_0 –> Pin olarak 0. pini seçtik
GPIO_PuPd_DOWN –>Pull-down kullanacağımızı belirtik
GPIO_Speed_50MHz –> Bu pinlerin çalışma hızını 50Mhz olarak belirledik
GPIO_Init() –> En sonunda ‘init’ yani başlat diyerek tüm işlemleri kayıt ettik
4- void EXTIConfig() adında bir fonksiyon açıp içerisinde EXTI ‘ye ait ayarları yapıyoruz.
APB2 Faz hatında bulunan SYSCFG hattını a ktif eder , çünkü EXTI birimi ‘SYSCFG ‘ hatının içerisindedir. Sizin kartınız farklıysa bu yer farklı bir faz hattı olabilir.
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,GPIO_PinSource0);
STM32 mikrodenetleyicilerinde, harici kesme girişleri, sistemde belirli bir olay gerçekleştiğinde programın kesintiye uğramasına ve olayı ele almasına izin verir. Bu olaylar, harici bir sinyal veya bir GPIO pimi durumundaki değişiklikler gibi birçok farklı şey olabilir.
SYSCFG_EXTILineConfig() fonksiyonu, hangi GPIO piminden kesmenin alınacağını ve bu kesmenin hangi kesme hattına (interrupt line) yönlendirileceğini yapılandırmak için kullanılır. Burada kullanılan parametreler aşağıdaki gibidir:
EXTI_PortSourceGPIOA: Kesmenin hangi GPIO bağlantısından alınacağını belirler. Bu durumda, kesme A portundaki bir pimden (GPIOA) gelecektir.GPIO_PinSource0: Hangi GPIO piminin kesmeyi tetikleyeceğini belirtir. Bu durumda, PA0 pimi kesmeyi tetikleyecektir.
Bu kod, bir kez yapılandırıldıktan sonra, mikrodenetleyiciye bağlı bir harici kesme girişi (örneğin, PA0) etkinleştirildiğinde, ilgili kesme işleyicisinin çağrılmasına neden olacaktır.
Altaki kodun açıklaması aşağıda maddeler halinde verilmiştir.
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
EXTI_Line0;
Portların P0’ları EXTI0’a , P1’leri EXTI1’e , P15’leri EXTI15’e bağlı.
EXTI0 –> LINE0
EXTI1 –> LINE1
EXTI2 –> LINE2 ,bu şekilde devam ediyor.
Biz sıfıncı hatta bağladık ve port olarak PA’yı seçtik , bunun için artık EXTI0 hattını kullanamayacağız.

ENABLE –> Line hattını aktif ettik
EXTI_Mode_Interrupt –> Exti’nin modunu Interrupt yani kesme olarak ayarladık (‘Event’ seçeneğide olabilirdi)
EXTI_Trigger_Rising –> Exti’nin tetikleme türü Yükselen olarak ayarladık (sinyal düşükten yükseğe geçerken tetikle demek)
EXTI_Init() –> Tüm ayarları kayıt ettik.
5- Aynı fonksiyonun içerisine devam ediyoruz , burda yapacğımız işlem Kesme işlemini kontrol eden yapı olacak.
// Kesmeyi Kontrol eden yapı
NVIC_InicStrucutre.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InicStrucutre.NVIC_IRQChannelCmd = ENABLE;
NVIC_InicStrucutre.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InicStrucutre.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InicStrucutre);
NVIC_IRQChannel = EXTI0_IRQn;
Bu kod çok önemlidir , bizim kesme yapacağımız hat EXTI0/LINE0 , Peki bu kesme işlemini ben nerede yazacağım nerede işleme sokacağım?
İşte bu kod bunun cevabı.
EXTI0_IRQn kodunun son ‘n’ harfini silin ve oraya ‘Handler’ yazın , EXTI0_IRQHandler şeklinde olacak.
Eğer siz EXTI3 hattını kullandıysanız o zaman EXTI3_IRQHandler olarak değiştireceksiniz ama atama işlemi sadece STM32F407VG için geçerli.
STM32F407VG için geçerli olan atama ;

Burda; EXT0_IRQn –> EXTI Line0(sıfır) –> EXT0_IRQHandler()
EXTI1_IRQn –> EXTI Line1(bir) –> EXT1_IRQHandler() . . . . . aritmetik olarak gidiyor.
STM32100RB için geçerli olan atama ;

Burda; EXTI0_IRQn –> EXTI Line0(sıfır) –> EXT0_IRQHandler()
EXTI3_IRQn –> EXTI Line3(sıfır) –> EXT3_IRQHandler()
EXTI5_9_IRQn –> EXTI Line(5 – 9) arası –> EXT5_9_IRQHandler()
EXTI15_10_IRQn –> EXTI Line(15 – 10) arası –> EXT15_10_IRQHandler()
Yani dökümanınıza bakarak bu atama işlemlerini yapın. Biz “407vg” ile yolumuza devam edelim.
NVIC_IRQChannelCmd = ENABLE; –> Belirlediğimiz atama işlemini Aktifleştirdik.
NVIC_IRQChannelPreemptionPriority = 0; –> Çoklı Kesme hatları kullandığımızda öncelik belirtir (0-15 kadar değer alır).
NVIC_IRQChannelSubPriority = 0; –> Çoklı Kesme hatları kullandığımızda öncelik belirtir (0-15 kadar değer alır).
–> Alından değerler 0(sıfır) en önce , 15(onbeş) en son öncelikli anlamına gelir.
NVIC_Init() –> Yapılan işlemleri kayıt ettik.
6- Şimdi Kesme aktif olunca çalışacak fonksiyonumuzu yazalım.
Bizm kullanacağımız hat ” EXT0_IRQn –> EXTI Line0(sıfır) –> EXT0_IRQHandler() ” budur , buradan foknsiyon olarak tanımlanacak kısım EXT0_IRQHandler() budur.
void EXTI0_IRQHandler() adında bir fonksiyon oluşturup içerisine kesmeye girince ne olmasını istiyorsanız onun kodunu yazırsonuz.
Buraya kadar yetiyor aslında fakat biz işimizi garantiye alalım ve daha kaliteli bir içerik çıkartalım.
Kesme işlemi devreye girince kod çalışacak ama bunu yazılımda özellikle belirlemedik ,kodun içerisinde bunu nasıl belirleyeceğiz ?
Cevap if() yapısı veya While() döngüsü kullanarak . Biz if yapısı ile yolumuza devam edelim.
if(EXTI_GetITStatus(EXTI_Line0) == SET)
Bu kod ; EXTI ye bağlı Kesme Durumunu kontrol eder, fakat hangi hattdaki kesmeyi? İşte bu sorunun cevabıda parantez içerisinde yer alır.
EXTI_Line0 bu hat bizim LINE0(sıfır) hattımızdır ve biz butonu bu hatta bağladık (PA0->LINE0).
Eğer kesme gerçekleşmiş ise EXTI_GetITStatus(EXTI_Line0) bu kod ‘SET’ kesme gerçekleşmemiş ise ‘RESET’ dönecektir. Şayet ‘SET’ dönerse if yapısının içerisine girecek ve Kesme işlemi durumunda ne yaptırdıysak o olacaktır.
if(EXTI_GetITStatus(EXTI_Line0) == SET){
GPIO_ResetBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
for(int i=0; i<7200000; i++);GPIO_SetBits(GPIOD,GPIO_Pin_12);
for(int i=0; i<7200000; i++);
GPIO_SetBits(GPIOD,GPIO_Pin_13);
for(int i=0; i<7200000; i++);
GPIO_SetBits(GPIOD, GPIO_Pin_14);
for(int i=0; i<7200000; i++);
GPIO_SetBits(GPIOD,GPIO_Pin_15);
for(int i=0; i<7200000; i++);
GPIO_ResetBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
for(int i=0; i<7200000; i++);
//----------------------------------------------------------------------------------------------
EXTI_ClearITPendingBit(EXTI_Line0);
}
Bu kod ; ilk önce 4 ledi de söndürüyor sonra belirli aralıklar ile ledleri tek tek yakıyor en son 4 ledin 4 de yanınca kodum bitiyor.
Kod biterken EXTI_ClearITPendingBit(EXTI_Line0); kodunu görüyoruz , bu kod kesme işlemi bitiğinde Kesme Durumunu eski haline getiriyor
yani bir daha aynı kesmeye girdiğimizde sanki hiç girmemiş gibi davransın demek bu şekilde Kesme Durumunu çıkışta Resetliyoruz.
7- Ana kod;
int main(void)
{
GPIOConfig();
EXTIConfig();
while (1)
{
GPIO_ToggleBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
for(int i=0; i<3600000; i++);
}
}
Bu kod; ilk olarak yukarda yaptığımız fonksiyonları burda çağırdık ama dikkat edin “EXTI0_IRQHandler” kodunu çağırmadık çünkü bu kodu sistem otamatik olarak NVIC yapısında çağırıyor. Fonksiyonları çağırıp GPIO ve EXTI yapılarını başlattık ardından while() içerisine benim ana kodumu yazdım yani cihaz çalışırken ne yapılması isteniyorsa onu yazıyoruz.
Burda 4 ledi de belirli saniye aralıklarla yak ve söndür yaptık.
Tüm Kod:
#include "stm32f4xx.h"
GPIO_InitTypeDef GPIO_InitStructure; // for GPIO
EXTI_InitTypeDef EXTI_InitStructure; // for EXTI (External Interrupt)
NVIC_InitTypeDef NVIC_InicStrucutre; // for NVIC (Kesmeleri Kontrol etmek )
void GPIOConfig(){
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); // GPIO PORT D Enable for LEDS
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); // GPIO PORT A Enable for BUTTON
// LEDS configuration
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD,&GPIO_InitStructure);
// BUTTON configuration
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void EXTIConfig(){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,GPIO_PinSource0);
//Interrupt işlemini button ile yapacağız
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
// Kesmeyi Kontrol eden yapı
NVIC_InicStrucutre.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InicStrucutre.NVIC_IRQChannelCmd = ENABLE;
NVIC_InicStrucutre.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InicStrucutre.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InicStrucutre);
}
void EXTI0_IRQHandler(){
if(EXTI_GetITStatus(EXTI_Line0) == SET){
GPIO_ResetBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
for(int i=0; i<7200000; i++);
GPIO_SetBits(GPIOD,GPIO_Pin_12);
for(int i=0; i<7200000; i++);
GPIO_SetBits(GPIOD,GPIO_Pin_13);
for(int i=0; i<7200000; i++);
GPIO_SetBits(GPIOD, GPIO_Pin_14);
for(int i=0; i<7200000; i++);
GPIO_SetBits(GPIOD,GPIO_Pin_15);
for(int i=0; i<7200000; i++);
GPIO_ResetBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
for(int i=0; i<7200000; i++);
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
int main(void)
{
GPIOConfig();
EXTIConfig();
while (1)
{
GPIO_ToggleBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
for(int i=0; i<3600000; i++);
}
}

