以前的版本应该是驱动下都可以用高精度,应用态下是低精度;现在变了,应该是微软要把 系统 高精度定时器管控起来,驱动下面也要用特定接口才行。
win10 64位下SetTimer设置的时间与延时的精确度均误差15ms,win10 32位下可以做到2ms精确时间。
修改win10 64位下的时针为高精度定时可以精确到ms。但是高精度定时这个数据类型是win8以后的版本才支持,所以在wdk7600编译都不能识别,把驱动移到VS2019上去编译才可以。编译后的驱动文件win10的32位,64位上面测试都正常了。
win7,32与64们下面使用高精度时钟驱动无法正常加载,设备管理器显示黄色感叹号,显示驱动文件已经被破坏或丢失,错误码39。
这个是为了测试做的延时函数:
void HAL_DelayMs_test (ULONG dwMilliSec)
{
LARGE_INTEGER Interval;
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
Interval.QuadPart = (LONGLONG)(dwMilliSec);
Interval.QuadPart *= 10000; // number of 100 ns intervals in 1 ms
Interval.QuadPart *= -1; // negative value indicates relative wait
KeDelayExecutionThread( KernelMode,FALSE, &Interval );
}
这是对它的调用
for( i=0;i<60;i++)
{
HAL_DelayMs_test (2);
KdPrint(("times :%d \n",i));
}
通过Dbgview看打印对比看到32位下面是延时了3MS,但是64位下面延时了15或者16MS,这个结果与KeSetTimer是一致的。
64位下面修改2ms的延时为50ms,100ms,1000ms,误差基本上都在15ms左右。
64bits的这个现象,有点象是按照windows的系统时钟在运行,windows的应用程序的定时器时间周期是15ms。
可以用ExSetTimerResolution(10000, TRUE);设置一下windows系统时钟分辨率,这是把整个windows的定时器时钟分辨率提升了,会影响整个系统比较耗电。这么验证一下,说明64bits windows10的timer精度可以很高。
(
例如,对于在 x86 处理器上运行的 Windows,系统时钟计时周期的默认时间间隔通常约为15毫秒,系统时钟计时周期之间的最小时间间隔约为1毫秒。 因此,默认解析计时器的过期时间 (如果未设置 EX_TIMER_HIGH_RESOLUTION 标志,则会在大约15毫秒内控制) ,但高分辨率计时器的过期时间可以在毫秒内进行控制。
若要创建高分辨率计时器,WDM 驱动程序将调用 ExAllocateTimer 例程,并在 Attributes 参数中设置 EX_TIMER_HIGH_RESOLUTION 标志。 当驱动程序调用 ExSetTimer 例程来设置高分辨率计时器时,操作系统会根据需要增加系统时钟的分辨率,使计时器的过期时间更精确地与 DueTime 和 Period 参数中指定的名义过期时间相对应。
Kernel-Mode Driver Framework (KMDF) 驱动程序可以调用 WdfTimerCreate 方法来创建高分辨率计时器。 在此调用中,驱动程序将指向 WDF_TIMER_CONFIG 结构的指针作为参数传递。 若要创建高分辨率计时器,驱动程序将此结构的 UseHighResolutionTimer 成员设置为 TRUE。 此成员是从 Windows 8.1 和 KMDF 版本1.13 开始的结构的一部分。
)
代码部分把以前的定时器部分:
KTIMER channel0AudioTimer; //定义DpcTimer定时器
KeInitializeTimer(&devext->channel0AudioTimer); //初始化定时器对象
KeInitializeDpc( &devext->channel0AudioDpc, channel0AudioDpcRoutine, devext );//初始化DPC对象
void channel0AudioDpcRoutine(struct _KDPC* p_dpc,PVOID context,PVOID arg1,PVOID arg2); //Dpc回调函数
KeSetTimer(&devext->channel0AudioTimer,largetime,&devext->channel0AudioDpc);
修改为:
PEX_TIMER channel0AudioTimer;
devext->channel0AudioTimer = ExAllocateTimer(channel0AudioDpcRoutine, devext,EX_TIMER_HIGH_RESOLUTION); //分配并初始化计时器对象
void channel0AudioDpcRoutine(PEX_TIMER Timer, PVOID context); //回调函数
{
...
PDEVICE_EXTENSION devext = (PDEVICE_EXTENSION)context;
....
}
ExSetTimer(devext->channel0AudioTimer, -30000, 0, NULL); //设置
如果想要精准的ms级别延时:
ExSetTimerResolution(10000, TRUE); //设置一下windows系统时钟分辨率
延时应用:
ExSetTimerResolution(0, FAUSE); //使用完后再取消