Milisaniye Mikrosaniye zaman ölçümü ve gecikme fonksiyonu oluşturma

İçerik:
1) Timer ile mikrosaniyelik (uS) gecikme fonksiyonu oluşturma
2) HAL ile milisaniyelik (mS) zaman ölçümü
3) DWT ile mikrosaniyelik (uS) zaman ölçümü
4) Timer ile mikrosaniyelik (uS) zaman ölçümü
1) Timer ile mikrosaniyelik (uS) gecikme fonksiyonu oluşturma




her iki clock hızları da 72 Mhz hıza sahip oldu. burada TIM1'i kullandığımızı varsayalım.

HAL_Delay() fonksiyonu ile istenilen milisaniyede gecikme oluşturabiliyoruz. Fakat daha hassas kontrol gerektiren sistemlerde mikrosaniye (uS) kullanmamız gerekebilir. Bunun için TIMER’larımızı kullanabiliriz. Yukarıda daha önce PWM frekansı hesaplaması yapmıştık. Buna benzer bir mantıkla hareket etmeliyiz. İşlemcimizin clock kaynağını yine daha önceki yaptığımız örneklerde olduğu gibi 8 Mhz HSE > PLLCLK > 72 Mhz olarak ayarlıyoruz. Bu uygulamalarda harici kristal osilatör kullanmak zaman hassasiyeti açısından önem arz etmektedir. İşlemcimizin clock hızını 72 Mhz ayarladığımız gibi Timerlarımızın hızları da aynı hıza sahip olacaktır.

dediğimiz zaman TIMER’ımız her 1 mikrosaniyede 1 defa up edilecektir.

Counter Period’umuz ise 16 bit yani 65 535 değeri ile adım perioduna sahiptir. Her adımın 1 uS olduğunu yukarıdaki hesaplamalar ile tanımlarsak bu fonksiyon en fazla 65535 mikrosaniyelik  delay fonksiyonu olabilir.

Fonksiyonu da yazarken buna uygun bir tanım ile yazacağız.

/* USER CODE BEGIN PM */

void delay_uS (uint16_t us); //fonksiyonumuzu başlık formunda tanımlıyoruz

/* USER CODE END PM */

 

  /* USER CODE BEGIN 2 */

  HAL_TIM_Base_Start(&htim1); //Timer’ımızı başlatıyoruz. Bu andan itibaren her 1uS sürede 1 adım artacaktır. 65535 değerine vardığında taşma durumu yaşanacak ve otomatik olarak sıfırlanacaktır.

 

  /* USER CODE END 2 */

 

  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

         delay_uS(50); //burada yazdığımız delay fonksiyonu ile 50 uS gecikme gerçekleştirilmesi için fonksiyon çağrılmıştır.

    /* USER CODE END WHILE */

 

    /* USER CODE BEGIN 3 */

  }

/* USER CODE BEGIN 4 */

void delay_uS (uint16_t us) // Timer’ın en fazla alabileceği ARR değeri 65535 (16bit) olduğu için fonksiyon tanımını buna uygun hale getiriyoruz

{

       __HAL_TIM_SET_COUNTER(&htim1,0); //doğru bir sayım için başlatıldığı anda delayı sıfırlıyoruz.

       while (__HAL_TIM_GET_COUNTER(&htim1) < us); //get_counter fonksiyonu ile sayımın değeri alınıyor eğer ki değer 50’nin altındaysa while koşuluna devam edecektir. 50 veya 50’den büyük bir değer olması durumunda döngüden çıkacaktır.

}

/* USER CODE END 4 */


2) HAL ile milisaniyelik zaman ölçümü

Bu kodda HAL_GetTick fonksiyonu ile sistem saatini milisaniye cinsinden sürekli güncellenir. uint32_t zaman2 değişkenimiz milisaniye türünden gecikmeyi ram belleğe kaydeder. Bu kod örneğinde zaman2 = 100 olur


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

         uint32_t zaman1 = HAL_GetTick();

         HAL_Delay(99);

         uint32_t zaman2 = HAL_GetTick() - zaman1;

    /* USER CODE END WHILE */


3) DWT ile mikrosaniyelik zaman ölçümü 

DWT (Data Watchpoint and Trace) birimindeki CYCCNT (Cycle Counter) register’ı kullanılır. DWT, ARM Cortex-M3 ve üzerinde olan işlemcilerinin bir parçasıdır ve yüksek hassasiyetle zaman ölçümü sağlar. Bunu STM32F103C8T6 işlemcimiz için incelersek;

    yani 13.79 nanosaniyelik bir çözünürlüğe sahip olur. Bu da mikro saniye ölçümü için yeterince hassastır.

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

// DWT Başlatma

void DWT_Init(void)

{

    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;

    DWT->CYCCNT = 0;

    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

}

// Mikrosaniye cinsinden zaman alma

uint32_t DWT_GetMicros(void)

{

    return (DWT->CYCCNT / (SystemCoreClock / 1000000)); // SystemCoreClock kaç hertz ise

}

// Taşmayı dikkate alarak geçen süreyi hesaplama

uint32_t DWT_GetDeltaMicros(uint32_t start_time)

{

    uint32_t current_time = DWT_GetMicros();

    if (current_time >= start_time)

    {        return (current_time - start_time);    }

    else

    {        return (0xFFFFFFFF - start_time + current_time + 1);    }

}

/* USER CODE END 0 */

 

  /* USER CODE BEGIN 2 */

  DWT_Init();

  /* USER CODE END 2 */

/* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

         uint32_t start_time, elapsed_time;

         start_time = DWT_GetMicros();

         HAL_Delay(1); // 2ms bekleme

         // Geçen süreyi hesapla

         elapsed_time = DWT_GetDeltaMicros(start_time);

    /* USER CODE END WHILE */



4) Timer ile mikrosaniyelik zaman ölçümü
 "Timer ile mikrosaniyelik (uS) gecikme fonksiyonu oluşturma" altında yapılan konfigürasyonu yine aynen gerçekleştiriyoruz.

/* USER CODE BEGIN 0 */

uint32_t baslangic = 0;

  HAL_TIM_Base_Start(&htim1);

//timer değerinde taşma olursa complementer işlemi uygulanarak çıkarma yapılır

uint32_t bitis = 0;

/* USER CODE END 0 */

/* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

 

  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

        __HAL_TIM_SET_COUNTER(&htim1, 0);

        baslangic = __HAL_TIM_GET_COUNTER(&htim1);

        HAL_Delay(1);

        bitis = Timer_GetElapsed(&htim1, baslangic);

    /* USER CODE END WHILE */

 

    /* USER CODE BEGIN 3 */

  }

 

/* USER CODE BEGIN 4 */

uint32_t Timer_GetElapsed(TIM_HandleTypeDef *htim, uint32_t timer_start) {

    uint32_t timer_end = __HAL_TIM_GET_COUNTER(htim);  // Timer pointer'ı ile sayaç değeri alınır

 

    if (timer_end >= timer_start) {

        return timer_end - timer_start;

    } else {

        return (0xFFFFFFFF - timer_start) + timer_end + 1;

    }

}

/* USER CODE END 4 */


Yorumlar