本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!前端
在作單片機項目開發的過程當中,在特殊應用中對代碼執行的時間有着嚴格的要求,那麼如何準確的測試出每一個函數的的運行速度是多快呢?一般用單片機測試的方法就是經過示波器觀察。ios
好比如今要測試使用二分查找法,在數組中查找一個數字須要屢次時間,測試方法爲:每運行一次查找算法,就讓LED引腳電平翻轉一次,而後使用示波器觀察LED引腳的波形,大概就能測試出這個算法的執行時間了。算法
測試代碼以下:後端
#include "iostm8s103F3.h"
#include "led.h"
#include "find.h"
void sysclkinit( void ) {
CLK_SWR = 0xe1; //HSI爲主時鐘源 16MHz CPU時鐘頻率
CLK_CKDIVR = 0x00; //CPU時鐘0分頻,系統時鐘0分頻
}
void main( void ) {
sysclkinit(); //時鐘初始化
__asm( "sim" ); //禁止中斷
led_init();
__asm( "rim" ); //開啓中斷
while( 1 )
{
LED = !LED;
val = binary_search( ( int* )volref, 500, 0, sizeof( volref ) / sizeof( volref[0] ) );
}
}
複製代碼
binary_search爲二分查找法函數,在100個數據的數組中查找數字500是否存在,LED每翻轉一次,執行一次函數。而後經過示波器觀察LED的波形。數組
能夠看到LED引腳的高低電平時間都爲164us,說明這個二分查找法查找數字500所用的時候爲164us。LED引腳自己的翻轉速度小於0.1us,因此LED引腳翻轉自己使用的時間在這裏能夠忽略不計。markdown
這樣在單片機中能夠經過LED引腳的翻轉經過示波器來觀察要測試的函數具體執行所佔用的時間。app
這樣測試積極精確,可是也比較麻煩,每次測試的時候,還必需要經過硬件電路才能測試,那麼能不能不用硬件電路,直接經過軟件測試呢?方法固然是有的,能夠在Windows中在C編譯器中經過軟件仿真,測試每一個函數執行的時間。ide
這裏使用的編譯器爲 Dev-C++,這個編譯器裏面能夠直接運行單片機中寫好的C函數,而後經過系統提供個幾個時間函數,就能夠準確測試出函數運行時間了。函數
系統提供的能夠測試函數有下面幾個post
The clock() function returns an approximation of processor time used by the program.
The value returned is the CPU time used so far as a clock_t; to get the number of seconds used, divide byCLOCKS_PER_SEC. If the processor time used is not available or its value cannot be represented, the functionreturns the value (clock_t) -1.
簡單而言,就是該程序從啓動到函數調用佔用CPU的時間。這個函數返回從「開啓這個程序進程」到「程序中調用clock()函數」時之間的CPU時鐘計時單元(clock tick)數。
函數原型以下:
返回值類型爲clock_t,實際上是一個長整形。
調用這個函數的時候,會返回一個CPU當前時間計數值。要測試時間的話,在函數以前前調用一次clock()函數,將當前時間計數值存儲起來。而後調用要測試的函數,測試函數結束以後,在調用一次clock()函數,讀取當前的時間計數值,而後用這個計數值減去函數執行前的時間計數值,就能夠計算出來函數執行所用的時間,這個時間單位默認爲ms。
2.GetTickCount()函數
GetTickCount返回(retrieve)從操做系統啓動所通過(elapsed)的毫秒數,它的返回值是DWORD,也是一個長整型數。
它的用法和clock()函數基本同樣,在函數執行前調用一次GetTickCount()函數,而後執行函數,函數執行完成後再調用一次GetTickCount()函數,而後計算兩次測時間差,這個單位也是ms。
在Windows系統中感受ms很短,可是對於單片機來講ms時間仍是比較長的,好多函數的執行時間遠遠小於1ms,若是用上面這兩種方法測試的話,許多函數的執行時間是測試不出來的。那麼就須要使用更高精度的測試函數。
調用這個函數會返回硬件支持的高精度計數器的頻率。注意這個返回的是系統的計時器值,不是時間值。上面兩個函數返回的是系統的時間值,而這個函數返回的是系統的計數器值,這個計數器的值至關於時間值來講,精度就高不少了,大多數的精度均可以達到us級。
這個函數在使用前首先要調用QueryPerformanceFrequency()函數獲取系統的計數頻率,也就是1s鍾系統會計數多少次。
而後使用QueryPerformanceCounter()獲取在程序運行先後的計數器值,而後用兩次計數器值的差除以計數的頻率,就能計算出函數執行所使用的時間。
下面開始使用Dev C++軟件測試這三種函數。
編寫測試代碼:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
//待測試函數
void fun(void) {
sleep(1);
}
typedef union _LARGE_INTEGER {
struct {
long LowPart ;// 4字節整型數
long HighPart;// 4字節整型數
};
long long QuadPart;// 8字節整型數
} LARGE_INTEGER;
int main(int argc, char *argv[]) {
int i = 0,val = 0;
clock_t startTime,endTime;
int time = 0;
// 方法 1
startTime = clock(); //計時開始
fun(); //調用函數
endTime = clock(); //計時結束
printf(" 1:程序運行時間爲: %d ms\r\n\r\n\r\n",(endTime - startTime));
//方法 2
startTime = GetTickCount(); //計時開始
fun(); //調用函數
endTime = GetTickCount(); //計時結束
printf(" 2:程序運行時間爲: %d ms\r\n\r\n\r\n",(endTime - startTime));
//方法 3
LARGE_INTEGER secondcount= {0};
LARGE_INTEGER startcount= {0};
LARGE_INTEGER stopcount= {0};
QueryPerformanceFrequency(&secondcount); //獲取每秒多少CPU Performance Tick 單位us
printf(" 3:系統計數頻率爲: %d \r\n",secondcount.QuadPart);
QueryPerformanceCounter(&startcount); //計時開始
fun(); //調用函數
QueryPerformanceCounter(&stopcount); //計時結束
time=( ((stopcount.QuadPart - startcount.QuadPart)*1000*1000)/secondcount.QuadPart);
printf(" 程序運行時間爲: %d us\r\n\r\n",time);
system("pause");
return 0;
}
複製代碼
運行結果以下
這裏的測試函數實際爲 sleep(1); 也就是休眠1s鍾,而後使用3種方法分別測試函數執行時間。
使用clock()函數測試代碼執行時間爲1000ms,使用GetTickCount()函數測試代碼執行時間爲998ms,使用QueryPerformanceCounter()函數測試代碼執行時間爲999630us,也就是999.63ms。經過QueryPerformanceFrequency()函數讀取到系統1s鐘的計數次數爲2630703次。
經過系統自帶的時間函數就能夠直接測試每一個函數執行的時間,這樣就能夠不使用硬件電路,就能夠直接對比不一樣的函數執行效率了。