如何測量程式碼執行時間

Fireflycjd發表於2021-08-25

01、示波器

測量一段程式碼執行時間第一時間想到的當然是示波器了,在測量開始的程式碼前面拉高某個GPIO,在結束測量的位置拉低這個GPIO,直接使用示波器檢視這個GPIO的高電平時間長度即可,就是我們要測量的這段程式碼的執行時間。

那麼直接上示例,為了模擬程式碼執行一段時間,這裡我直接採用之前文章《STM32的四種延時方法》直接延時。

  while (1)
  {
    GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄滅LED燈                     
    delay_ms(500);//延時500ms
    GPIO_ResetBits(GPIOE,GPIO_Pin_4);//點亮LED燈                     
    delay_ms(500);//延時500ms
  }

延時500ms時波形如下

圖片

當修改程式碼,延時100ms時

  while (1)
  {
    GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄滅LED燈                     
    delay_ms(100);//延時100ms
    GPIO_ResetBits(GPIOE,GPIO_Pin_4);//點亮LED燈                     
    delay_ms(100);//延時100ms
  }

波形如下

圖片

測量準確無誤,但是他的缺點也很明顯啊,需要示波器,示波器一般很笨重的,即使是輕便的示波器,也需要接硬體,還是很麻煩的,而且需要一個空閒的GPIO,測量的這段程式碼中,不能使用到這個GPIO。

02、定時器測量

定時器不僅僅我們可以實現我們之前講解的《基礎定時功能》《PWM輸出功能》《輸入捕獲功能》《觸控按鍵功能》,還可以用於測量一段程式碼的執行時間。在學習使用定時器測量程式碼執行時間之前,如果對定時器不瞭解的同學先看剛剛提到的定時器的文中,重點文章《STM32基礎定時器簡介》。本篇文章不再講解定時器的基礎功能。

定時器本質上就是向上累加的計數器(如果配置成向上計數時),所以我們在測量開始的程式碼前面讀取定時器的計數器,在結束測量的位置再讀取定時器的計數器,獲得兩次的差值,這樣就可以計算出這段程式碼的執行的時間。這就是簡單的原理,下面直接擼程式碼。

首先配置定時器,這裡我使用定時器3,配置定時器的計數器每增加1,表示100us。並且將溢位值設定為最大。

void TIM_Config(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  /* TIM3 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  
  TIM_TimeBaseStructure.TIM_Period = 0xFFFF-1;
  TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) ((SystemCoreClock / 2) / 10000) - 1;
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  TIM_Cmd(TIM3, ENABLE);
}

測量程式碼執行時間的程式碼如下,這裡進行了防溢位的處理

  while (1)
  {
    GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄滅LED燈                     
    delay_ms(100);//延時100ms
    GPIO_ResetBits(GPIOE,GPIO_Pin_4);//點亮LED燈
    old_counter = TIM_GetCounter(TIM3);
    delay_ms(100);//延時100ms
    couter_current = TIM_GetCounter(TIM3);
    if(couter_current > old_counter)
      counter = couter_current - old_counter;
    else
      counter = couter_current + 0XFFFF - old_counter;
    time_ms = counter / 10;
  }

上述程式碼延時100ms,通過定時器測量結果同樣為100ms,準確無誤。如下所示:

圖片

這樣有的同學可能已經聯想到了,上述程式碼完全可以封裝成一個函式如下
float Time_Difference_ms(void)
{
  static uint32_t old_counter;
  uint32_t counter,couter_current;
  couter_current = TIM_GetCounter(TIM3);
  if(couter_current > old_counter)
    counter = couter_current - old_counter;
  else
    counter = couter_current + 0XFFFF - old_counter;
  old_counter = couter_current;
  return (counter / 10);
}

這樣就可以實現,測量兩次呼叫這個介面的是時間差,如下,可以準確測得兩次呼叫Time_Difference_ms這個函式的時間差是100ms。

圖片

上述程式碼經過封裝,可以測量程式碼兩次執行到相同位置的時間差。將程式再進化一下
float Time_Difference_ms(uint8_t flg)
{
  static uint32_t old_counter[5];
  uint32_t counter,couter_current;
  couter_current = TIM_GetCounter(TIM3);
  if(couter_current > old_counter[flg])
    counter = couter_current - old_counter[flg];
  else
    counter = couter_current + 0XFFFF - old_counter[flg];
  old_counter[flg] = couter_current;
  return (counter / 10);
}

這樣就可以得到多個位置兩次執行到相同位置的時間差。

當然,這樣也存在缺點:

1、需要佔用一個定時器

2、按上述配置,最長測量時間為0XFFFF*0.1=6553.5ms=6.553.5s。

 

KeilIAR的工程檔案下載地址:

PCB和工程程式碼開源地址:

https://github.com/strongercjd/STM32F207VCT6

 

點選檢視本文所在的專輯,STM32F207教程

相關文章