我有一个应用程序,我需要在Windows 7/32位计算机上以10毫秒的速率(100赫兹)运行(它也将同时运行其他应用程序)。此中断可能会有一些最迟(100uSec)响应,但不能长时间漂移。我有一个程序,我已加载并使用NtSetTimerResolution将计时器设置为10毫秒分辨率,然后使用CreateTimerQueue / CreateTimereQueueTimer函数创建一个计时器,其中一个回调例程切换GPIO引脚(暂时) - 这会产生预期的方波,只要我不对系统做任何其他事情。当我开始其他几个过程时,方波的精确度就会消失。有没有办法在定时器中断上获得更高的优先级(或者是否有我可以使用的另一个定时器),这将产生更稳定的输出(可能是SMI)?我的代码如下所示,使用Windows DDK的x86检查构建环境构建,并从具有管理员权限的命令shell运行:
/*
Abstract:
Simple console test app for a 10mSec timer interrupt service
Enviroment:
Administrator Mode
*/
/* INCLUDES */
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#include <strsafe.h>
#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <mswsock.h>
#pragma warning(disable:4127) // condition expression is constant
FARPROC pNtQueryTimerResolution;
FARPROC pNtSetTimerResolution;
static HANDLE NTDLLModuleHandle;
static HINSTANCE hInpOutDll;
typedef void ( __stdcall *lpOut32 )( short , short );
typedef short ( __stdcall *lpInp32 )( short );
typedef BOOL ( __stdcall *lpIsInpOutDriverOpen )( void );
//Some global function pointers (messy but fine for an example)
lpOut32 gfpOut32;
lpInp32 gfpInp32;
lpIsInpOutDriverOpen gfpIsInpOutDriverOpen;
void CALLBACK TimerProc(void* lpParameter,
BOOLEAN TimerOrWaitFired);
// MAIN
VOID __cdecl main( void )
{
ULONG ulMinRes = 0;
ULONG ulMaxRes = 0;
ULONG ulCurRes = 0;
HANDLE phNewQueue;
HANDLE phNewTimer;
phNewQueue = CreateTimerQueue( );
NTDLLModuleHandle = LoadLibrary( "NTDLL.DLL" );
if( NULL == NTDLLModuleHandle )
{
return;
}
// Get the function pointers,
pNtQueryTimerResolution = GetProcAddress( NTDLLModuleHandle, "NtQueryTimerResolution" );
pNtSetTimerResolution = GetProcAddress( NTDLLModuleHandle, "NtSetTimerResolution" );
if( ( pNtQueryTimerResolution == NULL ) || ( pNtSetTimerResolution == NULL ) )
{
printf( "unable to link to ddl\n\n\n\n\n\n" );
return;
}
pNtQueryTimerResolution( &ulMinRes, &ulMaxRes, &ulCurRes );
printf( "MMR: %d %d %d\n", ulMinRes, ulMaxRes, ulCurRes );
ulMaxRes = 100000;
pNtSetTimerResolution( ulMaxRes, TRUE, &ulCurRes );
pNtQueryTimerResolution( &ulMinRes, &ulMaxRes, &ulCurRes );
printf( "MMR: %d %d %d\n", ulMinRes, ulMaxRes, ulCurRes );
//Dynamically load the DLL at runtime (not linked at compile time)
hInpOutDll = LoadLibrary( "InpOut32.DLL" );
if( hInpOutDll != NULL )
{
gfpOut32 = ( lpOut32 )GetProcAddress( hInpOutDll, "Out32" );
gfpInp32 = ( lpInp32 )GetProcAddress( hInpOutDll, "Inp32" );
gfpIsInpOutDriverOpen
= ( lpIsInpOutDriverOpen )GetProcAddress( hInpOutDll, "IsInpOutDriverOpen" );
if( gfpIsInpOutDriverOpen( ) )
{
gfpOut32( 0xA01, 0x00 );
}
else
{
printf( "unable to create timer system\n\n\n\n\n\n" );
return;
}
}
CreateTimerQueueTimer( &phNewTimer, phNewQueue, TimerProc, NULL, 0, 10,
WT_EXECUTEINTIMERTHREAD );
do
{
Sleep( 1 );
} while( TRUE );
}
void CALLBACK TimerProc(void* lpParameter,
BOOLEAN TimerOrWaitFired)
{
WORD wData;
UNREFERENCED_PARAMETER ( lpParameter );
UNREFERENCED_PARAMETER ( TimerOrWaitFired );
wData = gfpInp32( 0xA00 );
wData++;
gfpOut32( 0xA00, wData );
}
答案 0 :(得分:2)
您可以使用SetThreadPriority
优先处理关键线程。在这种情况下,您可能需要明确创建一个线程并使用CreateWaitableTimerEx
,SetWaitableTimerEx
和WaitForSingleObjectEx
而不是CreateTimerQueueTimer
。确保关键线程在等待之间不会花太长时间执行,否则Windows可能会停止正常工作。
如果最大延迟为100微秒,这可能还不够。您可能需要使用SetPriorityClass
函数将进程优先级类设置为REALTIME_PRIORITY_CLASS,但请确保您的程序永远不会占用CPU很长时间,否则Windows将无法正常工作。特别是,如果您的程序挂起,整个操作系统将挂起;在这种情况下,没有办法阻止程序关闭电源。
即使这可能还不够。 Windows不是一个实时操作系统,它可能无法满足您的要求。
答案 1 :(得分:0)
我对Windows和毫秒的经验是它不可靠。 我用Nusbio设备用示波器测量了Sleep api。 而Sleep(0)与完全不调用该方法不同。 睡眠(5)和睡眠(15)在某个时间等待相同时给出不一致的结果。
如果您想要这种精确度,您需要一个微控制器,它可以与您的Windows应用程序通信。