如何測量代碼運(yùn)行時(shí)間
01示波器
測量一段代碼運(yùn)行時(shí)間第一時(shí)間想到的當(dāng)然是示波器了,在測量開始的代碼前面拉高某個(gè)GPIO,在結(jié)束測量的位置拉低這個(gè)GPIO,直接使用示波器查看這個(gè)GPIO的高電平時(shí)間長度即可,就是我們要測量的這段代碼的運(yùn)行時(shí)間。
那么直接上示例,為了模擬代碼運(yùn)行一段時(shí)間,這里我直接采用之前文章《STM32的四種延時(shí)方法》直接延時(shí)。
- while (1)
- {
- GPIO_SetBits(GPIOE,GPIO_Pin_4); //熄滅LED燈
- delay_ms(500);//延時(shí)500ms
- GPIO_ResetBits(GPIOE,GPIO_Pin_4);//點(diǎn)亮LED燈
- delay_ms(500);//延時(shí)500ms
- }
延時(shí)500ms時(shí)波形如下:
當(dāng)修改代碼,延時(shí)100ms時(shí)。
- while (1)
- {
- GPIO_SetBits(GPIOE,GPIO_Pin_4); //熄滅LED燈
- delay_ms(100);//延時(shí)100ms
- GPIO_ResetBits(GPIOE,GPIO_Pin_4);//點(diǎn)亮LED燈
- delay_ms(100);//延時(shí)100ms
- }
波形如下:
測量準(zhǔn)確無誤,但是他的缺點(diǎn)也很明顯啊,需要示波器,示波器一般很笨重的,即使是輕便的示波器,也需要接硬件,還是很麻煩的,而且需要一個(gè)空閑的GPIO,測量的這段代碼中,不能使用到這個(gè)GPIO。
02定時(shí)器測量
定時(shí)器不僅僅我們可以實(shí)現(xiàn)我們之前講解的《基礎(chǔ)定時(shí)功能》《PWM輸出功能》《輸入捕獲功能》《觸摸按鍵功能》,還可以用于測量一段代碼的運(yùn)行時(shí)間。在學(xué)習(xí)使用定時(shí)器測量代碼運(yùn)行時(shí)間之前,如果對(duì)定時(shí)器不了解的同學(xué)先看剛剛提到的定時(shí)器的文中,重點(diǎn)文章《STM32基礎(chǔ)定時(shí)器簡介》。本篇文章不再講解定時(shí)器的基礎(chǔ)功能。
定時(shí)器本質(zhì)上就是向上累加的計(jì)數(shù)器(如果配置成向上計(jì)數(shù)時(shí)),所以我們?cè)跍y量開始的代碼前面讀取定時(shí)器的計(jì)數(shù)器,在結(jié)束測量的位置再讀取定時(shí)器的計(jì)數(shù)器,獲得兩次的差值,這樣就可以計(jì)算出這段代碼的運(yùn)行的時(shí)間。這就是簡單的原理,下面直接擼代碼。
首先配置定時(shí)器,這里我使用定時(shí)器3,配置定時(shí)器的計(jì)數(shù)器每增加1,表示100us。并且將溢出值設(shè)置為最大。
- 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);
- }
測量代碼運(yùn)行時(shí)間的代碼如下,這里進(jìn)行了防溢出的處理。
- while (1)
- {
- GPIO_SetBits(GPIOE,GPIO_Pin_4); //熄滅LED燈
- delay_ms(100);//延時(shí)100ms
- GPIO_ResetBits(GPIOE,GPIO_Pin_4);//點(diǎn)亮LED燈
- old_counter = TIM_GetCounter(TIM3);
- delay_ms(100);//延時(shí)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;
- }
上述代碼延時(shí)100ms,通過定時(shí)器測量結(jié)果同樣為100ms,準(zhǔn)確無誤。如下所示:
這樣有的同學(xué)可能已經(jīng)聯(lián)想到了,上述代碼完全可以封裝成一個(gè)函數(shù)如下:
- 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);
- }
這樣就可以實(shí)現(xiàn),測量兩次調(diào)用這個(gè)接口的是時(shí)間差,如下,可以準(zhǔn)確測得兩次調(diào)用Time_Difference_ms這個(gè)函數(shù)的時(shí)間差是100ms。
上述代碼經(jīng)過封裝,可以測量代碼兩次運(yùn)行到相同位置的時(shí)間差。將程序再進(jìn)化一下。
- 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);
- }
這樣就可以得到多個(gè)位置兩次運(yùn)行到相同位置的時(shí)間差。
當(dāng)然,這樣也存在缺點(diǎn):
1、需要占用一個(gè)定時(shí)器
2、按上述配置,最長測量時(shí)間為0XFFFF*0.1=6553.5ms=6.553.5s。
本文轉(zhuǎn)載自微信公眾號(hào)「 知曉編程 」
【編輯推薦】