SysTick timer, Cortex-M çekirdeğinde bulunan temel zamanlayıcıdır. Yani başka bir deyişle bu timerı STM32 serilerinin üreticisi ST firması değil de çekirdek üreticisi ARM sağlar. Delay fonksiyonlarında kullanılır, işlemci kapasitesini harcamaz, güç tüketimi sağlar ve doğrudan çekirdek içine tasarlanmıştır. Diğer timerların farklı modları (input capture, output capture vs.) olduğu için normal delay fonksiyonlarında bu timerları kullanmak tercih edilmez, bu birden fazla çevre biriminin aynı anda çalıştığı gelişmiş sistemlerde, işlemci gücünü ve kaynaklarını boşa kullanmak gibi olur. Sistem zamanlayıcısı SysTick, 24 bitlik bir geri sayım zamanlayıcısıdır. Bunu Gerçek Zamanlı İşletim Sistemi (RTOS) tick timer veya basit bir sayaç olarak kullanılır 0 ile 16.777.215 arasında sayar.
SysTick timerı kullanmak için kütüphanesi oluşturulur ve projeye dahil edilerek tekrar yazılmak zorunda kalınmatan tekrar kullanılabilir. Kütüphane için 2 dosya gereklidir. Bunlardan biri .h uzantılı dosyadır, bu dosyada kartın kendi kütüphanesi ve .c uzantılı dosyada oluşturulan fonksiyonlar yer alır. Diğer dosya .c uzantılı dosyadır. Burada SysTick ayarlamaları yapılır ve .h uzantılı dosyanın buraya dahil edilmesi gerekmektedir. SystemCoreClock/1000 yapılma nedeni işlemci örneğin 1 snde 168 mHz ile çalışır, bu 1 saniyede 168 milyon clock darbesi demektir. 1000’e bölünüyor yani 1 saniye 1000’e bölünüyor 1 milisaniye oluyor, kesme süresi 1 ms oluyor. 1000'e bölünmesiyle 1 ms'lik bir sistem timer elde ediliyor. Yani 1 ms'de bir SysTick_Handler(void) fonksiyonu çağırılır. /1000 kısmı değiştirilerek istenilen zaman oluşturulabilir. /1000 yerine /1000000 yapılırsa 1us olur, /10 yapılırsa 100ms olur. Genel kullanımı /1000 yani 1ms olacak şekildedir.
Bu servo uygulamasında TIM2 ile servo kontrolü yapılmış ve PWM mode (output compare mode) olarak kullanılmıştır. PWM mode darbe pals genişlik modülasyonudur. PWM sinyalinin çalışma döngüsü (duty cycle) genişletilerek çıkış sinyali elde etmeyi sağlar. Duty cycle, BTJ veya MOSFET gibi anahtarlama elemanı olarak kullanılan transistörlerin açık/kapalı durumlarına yani anahtara basma sürelerine göre değişir. Duty cycle değiştirilerek çıkışlardaki voltaj değeri de değiştirilebilmektedir.
Duty Cycle şu formüle göre hesaplanır:
Bir anahtarlama süresi sonunda çıkış voltajı da şu şekilde hesaplanır:
STM’de frekans ve duty cycle hesaplama:
Örneğin 1 kHz çalışma frekansında prescelar 10 olarak ayarlanırsa timer clock 2.4 Mhz olur. 1 kHz= 2.4/(Timer Period+1)'den timer periodun 2399 olarak ayarlanması gerekir. Duty cycle %25 ise TIM pulse=((2399+1)*0.25/100)-1'den TIM pulse 599 bulunur.
Bu uygulamada prescelar 100 olarak ayarlanmış ve timer clock 0.24 Mhz olmuştur. Servonun datasheetinden hangi frekans kaç derece için gerekli o bilgiler öğrenilmiş ve oradan da gerekli timer pulse değerleri elde edilmiştir. Örneğin 0 derece için 1.5 ms çalışması gerekmektedir, hesaplamalar yapıldığında da 0 derece için TIM pulse 359 olarak elde edilir. 90 derece için 2 ms çalışması gerekir ve TIM pulse 480 , -90 derece için 1ms çalıştırılır TIM pulse 240 ayarlanır.
Kullanılan Malzemeler, Devre Şeması ve Kodlar:
Servo motor
Jumper Kablolar
STM32VL Discovery Kartı
#include "stm32f10x.h" // Device header
#include "stm32f10x_tim.h" // Keil::Device:StdPeriph Drivers:TIM
#include "delay.h" // olusturulan sysTick timer için delay.h kütüphanesinin eklenmesi gerekir
void gpioConfig(); // pinlerin ayarlanmasi için fonksiyon
void timerConfig(); // timerin ayarlanmasi için fonksiyon
void pwmConfig(uint16_t timerPulse); // pwm modunun ayarlanmasi icin fonksiyon
int main(){
gpioConfig();
timerConfig();
DelayInit(); // stsTickin ayarlari ve update edilmesi
uint16_t servoArray[]={359,480,240}; //0,90 ve 180 derece için belirlenmis TIM pulselar için olusturulan array
while(1){
for(int i=0; i<=2; i++){ // while içinde önce 0 sonra 90 ve sonra 180 dereceye gidecek belli bir bekleme bulunmakta arada
pwmConfig(servoArray[i]);
delayms(1000);
}
}
}
void gpioConfig(){
GPIO_InitTypeDef GPIOInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // A portunun 0. pini servonun sinyal pinine baglanacak, A portu için clock hatti aktif ediliyor
GPIOInitStructure.GPIO_Mode=GPIO_Mode_AF_PP; // Pin modu seçildi, timer kullanilacagi için af ayarlandi
GPIOInitStructure.GPIO_Pin=GPIO_Pin_0; // 0. pin belirlendi
GPIOInitStructure.GPIO_Speed=GPIO_Speed_50MHz;// hiz ayarlandi
GPIO_Init(GPIOA,&GPIOInitStructure); // pin konfigürasyonunun yapildigi bildirildi
}
void timerConfig(){
TIM_TimeBaseInitTypeDef TIMERInitStructure;
RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM2, ENABLE); //A0 için TIM2 kullanilacak, APB1 clock hattina bagli. CH1 de sonra aktif edilmeli
TIMERInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; // clock bölümü yapiliyor
TIMERInitStructure.TIM_CounterMode=TIM_CounterMode_Up; // yukari dogru sayan counter mode seçildi
TIMERInitStructure.TIM_Prescaler=100; //prescaler 100 olarak ayarlandi
TIMERInitStructure.TIM_Period=4799; // 50 hz frekans için hesaplamalardan period 4799 olarak bulundu
TIM_TimeBaseInit (TIM2,&TIMERInitStructure); //timer için ayarlamalarin yapildigi bildirildi
TIM_Cmd(TIM2, ENABLE);
}
void pwmConfig(uint16_t timerPulse){
TIM_OCInitTypeDef TIMOC_InitStructure;
TIMOC_InitStructure.TIM_OCMode=TIM_OCMode_PWM1; //timerin output conpara modunda kullanilacagi ve %75lik duty cycle ile calisacagi bildiriliyor. PWM2 olsa %25lik duty cycle ile calisirdi
TIMOC_InitStructure.TIM_OutputState=TIM_OutputState_Enable; // output durumu için karsilastirma yapilacak enable edildi
TIMOC_InitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIMOC_InitStructure.TIM_Pulse=timerPulse; // TIM pulselera göre servonun dereceler kontrol edilecek
TIM_OC1Init(TIM2,&TIMOC_InitStructure); // output compare modu için ayarlama yapildigi bildiriliyor. Channel 1'e bagli A0'sa bulunan TIM2.
TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);
}
Systick için oluşturulan .c ve .h kodları:
#include "delay.h" //.c dosyasina olusturulan .h uzantili dosya eklenmelidir
static __IO uint32_t counter; // counter volatile olarak tanimlandi
void SysTick_Handler(){ // Systick için kesme fonksiyonu
if(counter>0){
counter--;
}
}
void delayms (uint32_t time){ // delay fonksiyonu
counter=time; // time countera ataniyor
while(counter); //counter 0 olana kadar time bitene kadar yani çalisacak
}
void DelayInit(void){ //initialize donksiyonu
SystemCoreClockUpdate(); // çekirdegin saati update ediliyor
SysTick_Config(SystemCoreClock/1000); //1000e bölerek 1 ms olacak sekilde ayarlaniyor sysTick
}
#ifndef __DELAY_H
#define __DELAY_H
#ifdef __cplusplus
extern "C" { // C kodunun C++ ile kullanilabilmesini saglar.
#endif
#include "stm32f10x.h" //kartin headeri ekleniyor
void DelayInit(void); // .c uzantili dosyada kullanilan fonskiyon
void delayms(uint32_t time); // .c uzantili dosyada kullanilan fonskiyon
#ifdef __cplusplus
}
#endif
#endif
Comments