一、前言

  因为接手的一个项目要做到精确到1ms以内的定时触发功能,在测试过 Sleep(DWORD millsecond)函数的准确度之后,该函数不能满足要求。上网查询了相询了相关资料,现将测试过程总结一下,方便自己以后翻阅。

二、测试过程

  1.开发平台:系统windows 7 + vs2013 + win32

  2.相关代码

  代码1如下所示:

emwin延时刷新 ms延时程序_emwin延时刷新

emwin延时刷新 ms延时程序_emwin延时刷新_02

1 #include "stdafx.h"
  2 #include <iostream>
  3 #include <vector>
  4 #include "math.h"
  5 #include "windows.h"
  6 #include "stdio.h"
  7 
  8 using namespace std;
  9 
 10 //是否调用Sleep()函数的阈值
 11 #define VALUE_NO_SLEEP 8
 12 
 13 
 14 
 15 ///
 16 //函数功能:精确延时函数
 17 //函数参数:延时时间
 18 //返回值:实际延时时间
 19 double MyDelay(double millsecond)
 20 {
 21     LARGE_INTEGER litmp;
 22     LONGLONG qt1, qt2;
 23     double dft, dff, dfm;
 24 
 25     //获得时钟频率
 26     QueryPerformanceFrequency(&litmp);//获得时钟频率
 27     dff = (double)litmp.QuadPart;
 28 
 29     //获得初始值
 30     QueryPerformanceCounter(&litmp);
 31     qt1 = litmp.QuadPart;
 32 
 33     double delayTime = 0;
 34     if (millsecond > VALUE_NO_SLEEP)        //10ms 的效果会比较好,效果好于5ms、6ms、8ms
 35     {
 36         Sleep(millsecond - VALUE_NO_SLEEP);
 37     }
 38 
 39     //程序延时
 40     do
 41     {
 42         //除法运算用于耗时
 43         double tmp = 1.0 / 3;
 44         QueryPerformanceCounter(&litmp);
 45         qt2 = litmp.QuadPart;
 46 
 47         //获得精确时间值,转到毫秒单位上
 48         dft = (double)(qt2 - qt1)/dff;
 49         //dft = dfm / dff;
 50         //printf("当前用时: %.3f 毫秒\n", dft*1000.0);
 51     } while (dft * 1000 < millsecond);
 52     //结束时用时
 53     //printf("实际用时: %.3f 毫秒\n", dft*1000.0);
 54     return dft*1000.0;
 55 
 56 }
 57 
 58 
 59 
 60 int _tmain(int argc, _TCHAR* argv[])
 61 {
 62 
 63 
 64     double time = MyDelay(45);
 65     printf("实际延时时间:%.3f\n", time);
 66 
 67 
 68     //测试一:
 69     //记录时间
 70     vector<double> record;
 71 
 72     LARGE_INTEGER ts, te, tc;
 73     double ds, de;
 74     LONGLONG qts, qte;
 75     //获取时钟频率
 76     QueryPerformanceFrequency(&tc);
 77     ds = (double)tc.QuadPart;
 78 
 79     for(int i=0;i<50;++i)
 80     {
 81         //获取初始值
 82         QueryPerformanceCounter(&ts);
 83         qts = ts.QuadPart;
 84 
 85         //做运算,用于耗时
 86         double arr[20480] = {0.0};
 87         for(int i=0;i<20480;++i)
 88         {
 89             arr[i] = double(i+1)/3;
 90         }
 91         //精确获取计算时间
 92         QueryPerformanceCounter(&ts);
 93         qte = ts.QuadPart;
 94 
 95         //获得精确时间值,转到毫秒单位上
 96         de = (double)(qte - qts) / ds;
 97         //实际耗时
 98         de *= 1000.0;    
 99         printf("除法运算耗时:%.3f毫秒\n", de);
100         record.push_back(de);
101         double tmp = MyDelay(50.0 - de);
102         printf("精确延时:%.3f毫秒\n",tmp);
103         record.push_back(tmp);
104         //实际共耗时
105         QueryPerformanceCounter(&ts);
106         qte = ts.QuadPart;
107         //获得精确时间值,转到毫秒单位上
108         de = (double)(qte - qts) / ds;
109         //实际耗时
110         de *= 1000.0;
111         printf("实际共耗时:%.3f毫秒\n\n",de);
112         record.push_back(de);
113     }
114 
115     FILE* fp = fopen("record.txt", "a+");
116     if(fp != NULL)
117     {
118         for(int i=0;i<record.size();++i)
119         {
120             char info[16] = {0};
121             sprintf(info, "%.4f\n", record[i]);
122             fwrite(info,1,strlen(info), fp);
123         }
124         fclose(fp);
125     }
126     else
127     {
128         fclose(fp);
129         return -1;
130     }
131 
132     system("pause");
133     return 0;
134 }

View Code

  代码1的命令行输出不满足设计想法,输出如下所示:

emwin延时刷新 ms延时程序_emwin延时刷新

emwin延时刷新 ms延时程序_emwin延时刷新_02

//单独测试MyDelay(45)的输出结果
实际延时时间:45.836

除法运算耗时:0.526毫秒
精确延时:49.474毫秒
实际共耗时:51.900毫秒

除法运算耗时:0.499毫秒
精确延时:49.501毫秒
实际共耗时:51.882毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:51.820毫秒

除法运算耗时:0.500毫秒
精确延时:49.500毫秒
实际共耗时:51.792毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:51.805毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:51.696毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:52.944毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:54.605毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.843毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.848毫秒

除法运算耗时:0.500毫秒
精确延时:49.500毫秒
实际共耗时:52.955毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.718毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.433毫秒

除法运算耗时:0.303毫秒
精确延时:49.698毫秒
实际共耗时:51.968毫秒

除法运算耗时:0.298毫秒
精确延时:49.702毫秒
实际共耗时:52.010毫秒

除法运算耗时:0.309毫秒
精确延时:49.691毫秒
实际共耗时:53.467毫秒

除法运算耗时:0.300毫秒
精确延时:49.700毫秒
实际共耗时:51.943毫秒

除法运算耗时:0.295毫秒
精确延时:49.705毫秒
实际共耗时:52.539毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.724毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.609毫秒

除法运算耗时:0.500毫秒
精确延时:49.500毫秒
实际共耗时:52.753毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:52.756毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.622毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.799毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.687毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.875毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:52.738毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:52.864毫秒

除法运算耗时:0.523毫秒
精确延时:49.477毫秒
实际共耗时:54.418毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.700毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:53.040毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.781毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:53.402毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:54.049毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.694毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.861毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:52.686毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.691毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.738毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.646毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:53.498毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.701毫秒

除法运算耗时:0.506毫秒
精确延时:49.495毫秒
实际共耗时:54.056毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.662毫秒

除法运算耗时:0.501毫秒
精确延时:49.499毫秒
实际共耗时:52.678毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.821毫秒

除法运算耗时:0.503毫秒
精确延时:49.497毫秒
实际共耗时:52.664毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.749毫秒

除法运算耗时:0.502毫秒
精确延时:49.498毫秒
实际共耗时:52.671毫秒

除法运算耗时:0.500毫秒
精确延时:49.500毫秒
实际共耗时:52.922毫秒

View Code

  

  再次查看代码时,产生疑惑:是不是多余的乘法运算和printf()输出导致【实际共耗时】与【除法运算耗时】、【精确延时】的加和相差较大的现象。立即着手屏蔽这些代码,并且只记录每次for循环开始时刻的精确时间,代码2如下所示:

emwin延时刷新 ms延时程序_emwin延时刷新

emwin延时刷新 ms延时程序_emwin延时刷新_02

1 #include "stdafx.h"
  2 #include <iostream>
  3 #include <vector>
  4 #include "math.h"
  5 #include "windows.h"
  6 #include "stdio.h"
  7 
  8 using namespace std;
  9 
 10 
 11 #define VALUE_NO_SLEEP 8
 12 
 13 
 14 
 15 ///
 16 //函数功能:精确延时函数
 17 //函数参数:延时时间
 18 //返回值:实际延时时间
 19 double MyDelay(double millsecond)
 20 {
 21     LARGE_INTEGER litmp;
 22     LONGLONG qt1, qt2;
 23     double dft, dff, dfm;
 24 
 25     //获得时钟频率
 26     QueryPerformanceFrequency(&litmp);//获得时钟频率
 27     dff = (double)litmp.QuadPart;
 28 
 29     //获得初始值
 30     QueryPerformanceCounter(&litmp);
 31     qt1 = litmp.QuadPart;
 32 
 33     double delayTime = 0;
 34     if (millsecond > VALUE_NO_SLEEP)
 35     {
 36         Sleep(millsecond - VALUE_NO_SLEEP);
 37     }
 38 
 39     //程序延时
 40     do
 41     {
 42         //除法运算用于耗时
 43         double tmp = 1.0 / 3;
 44         QueryPerformanceCounter(&litmp);
 45         qt2 = litmp.QuadPart;
 46 
 47         //获得精确时间值,转到毫秒单位上
 48         dft = (double)(qt2 - qt1) / dff;
 49         //dft = dfm / dff;
 50         //printf("当前用时: %.3f 毫秒\n", dft*1000.0);
 51     } while (dft * 1000 < millsecond);
 52     //结束时用时
 53     //printf("实际用时: %.3f 毫秒\n", dft*1000.0);
 54     return dft*1000.0;
 55 
 56 }
 57 
 58 
 59 int _tmain(int argc, _TCHAR* argv[])
 60 {
 61 
 62     //测试MyDelay函数
 63     double time = MyDelay(45);
 64     printf("实际延时时间:%.3f\n", time);
 65 
 66 
 67     //测试二:不做冗余的计算和打印,只记录循环开始的精确时间
 68     //记录时间
 69     vector<LONGLONG> record2;
 70     LARGE_INTEGER ts, te, tc;
 71     double ds, de;
 72     LONGLONG qts, qte;
 73     //获取时钟频率
 74     QueryPerformanceFrequency(&tc);
 75     ds = (double)tc.QuadPart;
 76     //循环1000次,以便观察,消除偶然性
 77     for (int i = 0; i < 1000; ++i)
 78     {
 79         //获取初始值
 80         QueryPerformanceCounter(&ts);
 81         qts = ts.QuadPart;
 82         record2.push_back(qts);
 83         //做运算
 84         double arr[20480] = { 0.0 };
 85         for (int i = 0; i < 20480; ++i)
 86         {
 87             arr[i] = double(i + 1) / 3;
 88         }
 89 
 90         //除法运算实际耗时
 91         QueryPerformanceCounter(&ts);
 92         qte = ts.QuadPart;
 93         //获得精确时间值,转到毫秒单位上
 94         de = (double)(qte - qts) / ds * 1000.0;
 95         //printf("除法运算耗时:%.3f毫秒\n", de);
 96         double tmp = MyDelay(50.0 - de);
 97         //去除多余的计算和查询时间,每次只记录循环开始的精确时间
 98     }
 99 
100     FILE* fp = fopen("record.txt", "w+");
101     char *data = new char[10240];
102     memset(data, 0, sizeof(data));
103     if (fp != NULL)
104     {
105         for (int i = 0; i < record2.size() - 1; ++i)
106         {
107             //输出前后两次记录值之间的差值,即一次循环的耗时
108             de = (double)(record2[i + 1] - record2[i]) / ds * 1000.0;
109             char info[16] = { 0 };
110             sprintf(info, "%.4f\n", de);
111             strcat(data, info);
112         }
113         fwrite(data, 1, strlen(data), fp);
114         fclose(fp);
115         delete[]data;
116         data = NULL;
117     }
118     else
119     {
120         fclose(fp);
121         return -1;
122     }
123 
124     system("pause");
125     return 0;
126 }

View Code

  代码2的输出这里就不贴出了。有兴趣的可以自己测试一下,如果有问题,可以联系我,大家一起讨论和学习。

三、参考资料

1、精确获取时间(QueryPerformanceCounter)  
2、如何做到精确延时