
Bu yazımda bir genel amaçlı zamanlayıcı kullanarak bir PWM sinyalinin sinyalinin darbe genişliğini ölçmeyi anlatacağım. Bu işlemleri bir STM32 mikrodenetleyici üzerinden anlatıyor olsamda mantığını anladıktan sonra herhangi bir mikrodenetleyiciyi kullanarak aynı ölçümleri yapabilirsiniz.
Öncelikle konuya başlamadan önce Zamanlayıcının ne olduğunu açıklamak istiyorum. Zamanlayıcı(timer) içerisinde bir adet sayıcı barındıran en önemli çevrebirimlerinden biridir. Her ne kadar zamanlayıcı olarak adlandırılsada donanım olarak özünde bir sayıcıdır zaman sayma işlemi yapmaz sadece kendisine gelen saat frekansı ile orantılı olarak lineer sayma işlemi gerçekleştirir ve biz bu sayma işleminin hızını kullanarak zaman bilgisine ulaşırız. Ölçmek istediğimiz zaman aralığında sayıcının kaç defa saydığını ölçerek ve bu değeri sayıcı frekansıyla çarparak o zaman aralığını hesaplayabiliriz.
PWM(Pulse Width Modulation), darbe genişliği modülasyonu bir kare dalga sinyalin doluluk oranı(duty cycle) nı değiştirerek o sinyalin analog çıktısını kontrol ettiğimiz yöntemdir. Özellikle mikrodenetleyici gibi sadece 0 ve 1 lerden oluşan dijital sistemlerde analog çıktı oluşturmanın en kolay yollarından birisidir. Fakat, bu yazımızda bu sinyalin analog karşılığından ziyade bu kare dalga sinyalin frekansı ve darbe genişliği ile ilgileneceğiz.

Yukarıda ki gibi bir PWM sinyalin frekansını ölçmek için yapmamız gereken şey iki yükselen kenar arasında geçen zamanı ölçmektir. Bu işlemi yaparken timer input capture modunu kullanmak gayet basit. Yapacağımız işlem özünde, ilk yükselen kenar anındaki sayıcı değerini bir değişkene kaydedip ikinci yükselen kenardaki sayıcı değerini yeni bir değişkene kaydedip daha sonra farklarını almaktır.
Darbe genişliğini ölçmek için ise , ilk yükselen kenarda kaydettiğimiz sayıcı değerinden sonra kesme polaritesini düşen kenara ayarlayıp bir sonraki düşen kenar anındaki sayıcı değerini yakalayıp aynı işlemi yapmalıyız.
Timerımızı input capture modu nda ayarladığımız zaman bu bahsettiğim yükselen ve düşen kenar kesmeleri oluştuğu anda sayıcı değeri donanım tarafından CCRx yazmacına kaydedilir ve biz bu CCR yazmacının değerini okuyarak işlem yapabiliriz.
Yukarıdaki fonksiyon ile timer2 nin 2 nolu kanalı input capture olarak ayarlandı ve Nvic tarafında kesmesi aktif edildi. Şimdi sıra bu yükselen ve düşen kenar kesmeleri oluştuğu zaman yapacağımız işleme geldi.
void timer2_init(void)
{
// 1 - timer2 nin clock unu aktif et
RCC->APB1ENR |= (1<<0);
// 2 - input pinin bagli oldugu gpioA clock unu aktif et
RCC->AHB1ENR |= (1<<0);
// 3 - PA1 pinin GPIO ayarlarini yap
GPIOA->MODER |= (1<<3);
GPIOA->MODER &= ~(1<<2); // Alternate function olarak ayarla
GPIOA->AFR[0] = 0b000000000010001; // AF1 olarak belirle
// 4 - timer2 ayarlarini yap
TIM2->PSC = 99;
TIM2->ARR =4000000;
TIM2->CR1 |= (1<<0); // sayıcı aktif
TIM2->CCMR1 |= (1<<8); // CC2 channel is configured as input, IC2 is mapped on TI2.
TIM2->CCER |= (1<<4); // yakalama aktif
TIM2->DIER |= (1<<0); // update interrupt aktif
TIM2->DIER |= (1<<2); //ch2 interrupt aktif
TIM2->CCER &= ~TIM_CCER_CC2P; // polarity mode yükselen kenar
// 5 - nvic tarafinda timer2 ayarlarini yap
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 0x03);
}
void TIM2_IRQHandler(void)
{
if(TIM2->SR & TIM_SR_CC2IF)
{
if((TIM2->CCER & TIM_CCER_CC2P)==0) // kanalin aktif olmasi kesmenin oradan gelecegi anlamina gelmez/gpio pinini kontrol et
{
ch2yukselen = TIM2->CCR2; // yukselen kenar degerini kaydet
TIM2->CCER |= TIM_CCER_CC2P; // polariteyi düsen kenar olarak degistir
}
else
{
ch2dusen = TIM2->CCR2;
fark = ch2dusen- ch2yuselen; // dusen kenar degerini kaydet ve yukselen kenar degerinden cikar
if(fark< 0)fark += 0xFFFF; // eger sonuc negatifse taban tumleme yap
if(fark< 2010 && fark> 990)ch2=fark;
TIM2->CCER &= ~TIM_CCER_CC2P; // polariteyi yukselen kenar olarak ayarla
}
TIM2->SR &= ~TIM_SR_CC2IF; // kesme bayrağını sıfırla
}
}
yukarıda ki kesme fonksiyonu ile yükselen kenar ile düşen kenar arasındaki zamanı ölçerek darbe genişliğini belirleyebiliriz.
Timer ın sayıcısının çalışma frekansı, bağlı olduğu clock hattının prescaler değerinin bir fazlasına bölündüğündeki değere eşittir. Tİmer2 ikin bağlı olduğu clock hattı 100Mhz de çalışmakta iken ben precaler değerine 99 atayınca sayıcı frekansım 1 Mhz olmaktadır. Yani her 1 mikrosaniyede bir sayacaktır. ARR yazmacı ise sayıcımın maksimum değerini belirtmektedir ve bu uygulamada spesifik bir değer vermemiz gerekmiyor.