在不采用硬件计时器的情况下如何创建更精确的计时器

在不采用硬件计时器的情况下如何创建更精确的计时器?最精确周期能否达到1毫秒? 

对于精确值的要求不同,所采用的办法不同。以下阐述几种办法。 

1、在单线程中循环调用API Sleep函数,Sleep函数精确程度为如果Sleep(N),那么实际睡眠时间在N到N+1毫秒之间。而且还要注意调用Sleep的线程优先级的问题。如果任务过多并且此线程优先级低,那误差就更大些。 

2、调用API QueryPerformanceCounter函数,举例如下: 

 1 LARGE_INTEGER  liFrequency; 
 2 if (QueryPerformanceFrequency(&liFrequency))  // 查询系统时钟的频率,这里将返回1000  
 3 {
 4      liFrequency.QuadPart /= 1000;
 5      LARGE_INTEGER  liTimeOut; 
 6      if (QueryPerformanceCounter(&liTimeOut))   //得到截至到当前累计发生的系统时钟中断次数 
 7      {
 8           liTimeOut.QuadPart += liFrequency.QuadPart;   ///计算下一秒到来时总的中断次数是多少
 9           LARGE_INTEGER  liCurrent;
10           do
11           {
12                     QueryPerformanceCounter(&liCurrent);    // 循环查询累计的的中断次数 
13           } while (liCurrent.QuadPart < liTimeOut.QuadPart); ///到达下一秒
14      }
15 }  

调用QueryPerformanceCounter同调用Sleep在本质上都是一样的,都是在单线程中无限循环等到周期一到执行任务,相比较 QueryPerformanceCounter要比Sleep更精确些,越精确就越要求线程的优先级,保障线程能够正常得到处理器。 

3、以上办法难以保证周期精确到1毫秒并且WINCE系统稳定地运行,所以要从中断入手。

以x86平台为例

(1)先在Timer.c中将默认的 SetTimer0 (TIMER_COUNT) 中的 TIMER_COUNT /=2,SetTimer0函数负责设置系统时钟的频率,默认1毫秒发生一次中断,如果除以2就是0.5毫秒发生一次中断。

(2)然后在fwpc.c文件中修改ISR函数PeRPISR,因为原来默认是1毫秒发生一次中断,在处理INTR_TIMER0时系统负责累计计数、管理线程的调度,返回相应的SYSINTR值,而我们没有办法再添加代码返回自己定义的SYSINTR值,所以现在要修改原来的处理代码,例如设置一个BOOL型变量,TRUE就执行原来默认的代码,而FALSE就返回我们自己定义的SYSINTR值,这样即不影响原来的ISR处理,又加入了我们的中断响应代码。ISR返回我们定义的SYSINTR后WINCE内核激活相对应的EVENT事件,我们就可以在我们编写的IST里处理任务了。 

 

如何改系统调度的默认时间片值?  更改schedule.c文件中的dwDefaultThreadQuantum 变量,然后重新编译该文件并SYSGEN。调用API CeGetThreadQuantum就知道更改是否生效。 

posted @ 2016-03-08 14:25  91program  阅读(344)  评论(0编辑  收藏  举报