1 Eylül 2016 Perşembe

4 - STM32F4 ile Timer Kesmesi

Merhaba Arkadaşlar,

         Sıradaki örneğimiz Stm32f4 ile Timer kesmesi nasıl yapılır bunun hakkında kısa bilgi ardından da kod paylaşımı yapılacaktır.

Öncelikle STM32F4 işlemcisi 14 adet Timer’a sahiptir. Bunlar:

Timer1 ve Timer8 (ikisi de 16 bit) gelişmiş özelliklere sahiptirler.  

TIM2 (16bit), TIM3 (32bit), TIM4 (32bit) ve TIM5(16bit) genel amaçlı kullanım için uygundurlar.

Timer9’dan Timer14’e kadar olanlar da farklı ayarlanabilir özelliklere sahip olan timer’lardır.

Timer6(16Bit) ve Timer7(16Bit) basit özellikleri olan timer’lardır.

Aşağıda bu timerların gösterildiği bus hatlarına bakabilirsiniz:



Datasheet’lerden daha detaylı bilgilere ulaşabilirsiniz. Burada ise Timer2 ile bir örnek yapılacaktır.
Öncelikle Timer için Clock hattının aktifleştirilmesi gerekmektedir. Yukarıda da görüldüğü üzere Timer2 APB1 hattına bağlıdır. O halde:
/* timer2 Periph clock hatti aktif edilir */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM2 APB1’e bağlı gözüküyor. APB1’in çalışma hızı 42 MHz. Ancak Datasheet’e bakıldığında önemli bir uyarı ile karşılaşıyoruz:

       APB2’ye bağlı olan zamanlayıcılar için clock hattı 168Mhz’e kadar olabilir, APB1 içinse 84Mhz olabilir. Burada bir ikilem var gibi duruyor ancak datasheet’te bunu şöyle açıklıyor:  APB ön bölücü değeri 1 ise timer clock hattı da aynı frekansta çalışır, ancak ön bölücü değeri 1 değilse veya 1’den farklı bir değerde ise timer clock hattı APB hattının 2 katı hızda çalışır.

Timer2’ye baktığımızda APB1 bus hattına bağlıdır. Bu hattın clock frekansı 42 Mhz. Daha önce CMSIS klasöründe oluşturduğumuz system_stm32f4xx.c dosyasında ön bölücü değeri 4 olarak kullanıldığı için bu hat 42*2 yani 84 Mhz clock frekansında çalışmaktadır. Daha detaylı bilgiye datasheet’ten bakılabilir.

Prescaler değeri ise:      Timer hızı  = Bus hızı / (prescaler + 1)  formülünden bulunur.

O halde 0.5 sn’lik timer kesmesi için:

0.5sn = 1/0.5 = 2Hz frekansa eşittir.

Öncelikle 2Khz (2000Hz) için:            2000 = 84Mhz(buz hızı) /(prescaler+1)
                                                             2000 = 84000000 / (PRSC + 1) = > PRSC = 41999 olmaktadır.

Periyodu da biz 1000’e kadar saydırırsak:             2000hz / 1000 = 2Hz
                                                                                2Hz = ½ = 0.5sn demektir.

Prescaler değeri: 41999
Periyod: 1000 -1 = 999 (sayıma 0’dan başladığı için 1 eksiği olur)
0.5sn için değerlerimizi yukarıdaki gibi hesaplarız.

Kod yazma kısmına geçebiliriz. 
     Öncelikle projemize timer kütüphanesinin eklenmesi gerekmektedir. Daha önceki konularda bu anlatıldığı için burada değinilmeyecektir. Ayrıca main.c dosyasına kodu yazarken en üstte #include "stm32f4xx_tim.h" kodunu yazmayı unutmayın. 

TIM_TimeBaseInitTypeDef                        TIM_TimeBaseStructure;                            //timer için
NVIC_InitTypeDef                                         NVIC_InitStructure;                                      //kesme için
Port yönlendirmeleri ana döngü içerisinde tanımlanır.
/*timer2 Periph clock hatti aktif edilir */     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
Timer kodları ise:
TIM_DeInit(TIM2); //daha önce timer ayarlamaları yapıldı ise temizle
 TIM_TimeBaseStructure.TIM_ClockDivision = 0;             //gonderilen clock bilgisinin kac parça halinde gönderilecegini gosterir
TIM_TimeBaseStructure.TIM_CounterMode    = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period    = 1000-1;                             //periyod girilir
TIM_TimeBaseStructure.TIM_Prescaler              = 42000-1;                         //prescaler değeri girilir
TIM_TimeBaseInit( TIM2,&TIM_TimeBaseStructure);   //timer2’ye ait olduğu belirtilir
TIM_Cmd(TIM2, ENABLE);                         //timer2 aktif edilir
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                              //timer kesmesi bayrağı aktif edilir
               
//Kesme için gerekli açıklamaları daha önceki yazımızda bulabilirsiniz.
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0x00; //farkli türler arasi oncelik
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0x00; //kendi turunun icindeki oncelik
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init(&NVIC_InitStructure);

Kesme fonksiyonu:
void TIM2_IRQHandler()
{
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) == 1 ) //kesme bayrağı 1 mi?
        {
                TIM_ClearITPendingBit(TIM2, TIM_IT_Update);             //bayrağı temizle
                GPIO_ToggleBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
        }
}

/*************************************************************
Aşağıda tüm kodları baştan aşağı sıra ile yazılmıştır:

#include "stm32f4xx.h"                               //stm32f4 kütüphanesi
#include "stm32f4xx_gpio.h"                    //GPIO kütüphanesi
#include "stm32f4xx_rcc.h"                       // RCC clock kütüphanesi
#include "stm32f4xx_tim.h"


void TIM2_IRQHandler()
{
                if(TIM_GetITStatus(TIM2, TIM_IT_Update) == 1 )          //kesme bayrağı set oldu mu?
                {
                TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                             //bayrağı sıfırla
                GPIO_ToggleBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
                }
}


//Ana fonksiyon
int main(void)
{
                TIM_TimeBaseInitTypeDef        TIM_TimeBaseStructure;
                NVIC_InitTypeDef                          NVIC_InitStructure;
                GPIO_InitTypeDef  GPIO_InitStructure;                              // Port yönlendirmesi

  /* GPIOD Periph clock hatti aktif edilir */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* timer2 Periph clock hatti aktif edilir */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
  /* PD12, 13, 14 ve PD15 pinleri kullanilacak */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
               
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                              //Pinler cikis olarak belirlendi
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                               //Pin PushPull olarak ayarlandi
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;     //GPIO Bus hizi 100 MHz ayarlandi
GPIO_Init(GPIOD, &GPIO_InitStructure);           //Yukarida tanimlanan bilgileri GPIOD adresine ait oldugu belirtilir

 TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_ClockDivision= 0;                              //gonderilen clock bilgisinin kac parça halinde gönderilecegini gosterir
TIM_TimeBaseStructure.TIM_CounterMode    = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period                   = 1000-1;
TIM_TimeBaseStructure.TIM_Prescaler                              = 42000-1;
TIM_TimeBaseInit( TIM2,&TIM_TimeBaseStructure);
               
TIM_Cmd(TIM2, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
               
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0x00; //farkli türler arasi oncelik
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //kendi turunun icindeki oncelik,
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
                              
GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
                                              
  while (1)            //Sonsuz donguye girilir
                               {                                            
                                              
                               }
}

Aşağıda kodun resimleri bulunmaktadır.


İyi Çalışmalar.

                                                                                                                                              

6 yorum:

  1. sunu merak ediyorum mesela tımer 2 saymaya başladı 1 periyod sonucu timer kesmesi olustu kesme fonksiyonuna gitti bundan sonra kesme fonksiyonu icra edilirken timer hemen saymaya mı baslar yoksa timer fonksiyonu bitince mi baslar

    YanıtlaSil
    Yanıtlar
    1. Bu yorum yazar tarafından silindi.

      Sil
    2. Bu yorum yazar tarafından silindi.

      Sil
    3. Bu yorum yazar tarafından silindi.

      Sil
    4. ISR programı çalışır timer aynı anda saymaya devam eder.
      Örneğin 100 ms aralıklarla kesme oluşturup 150 msde execute edilebilecek bir ISR programı varsa program arada bir tane kesmeyi atlar çünkü mikro işlemcilerde(tabi nasıl programladığına da bağlı nested interrupts yoksa) ISR devreye girdiğinde kesme dallaması disable edilir.

      Sil
  2. Bu yorum yazar tarafından silindi.

    YanıtlaSil