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.
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.
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ıtlaSilBu yorum yazar tarafından silindi.
SilBu yorum yazar tarafından silindi.
SilBu yorum yazar tarafından silindi.
SilISR programı çalışır timer aynı anda saymaya devam eder.
SilÖ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.
Bu yorum yazar tarafından silindi.
YanıtlaSil