我有一个应用程序,我需要在
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,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,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 ); }
解决方法
您可以使用
SetThreadPriority
为关键线程赋予优先权.在这种情况下,您可能需要显式创建一个线程并使用
CreateWaitableTimerEx
,SetWaitableTimerEx
和
WaitForSingleObjectEx
而不是
CreateTimerQueueTimer
.确保关键线程永远不会在等待之间执行太长时间,否则Windows可能会停止正常工作.
如果最大延迟为100微秒,这可能还不够.您可能需要使用SetPriorityClass
函数将进程优先级类设置为REALTIME_PRIORITY_CLASS,但请确保您的程序永远不会占用cpu很长时间,否则Windows将无法正常工作.特别是,如果您的程序挂起,整个操作系统将挂起;在这种情况下,没有办法停止程序关闭电源.
即使这可能还不够. Windows不是一个实时操作系统,它可能无法让它做你想要的.