【问题标题】:Need to produce a stable 10mSec interrupt需要产生稳定的 10mSec 中断
【发布时间】:2012-05-23 23:45:52
【问题描述】:

我有一个应用程序,我需要在 Windows 7/32 位计算机上以 10 毫秒的速率 (100hz) 运行(该计算机也将同时运行其他应用程序)。此中断可能有一些最小延迟 (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 );
}

【问题讨论】:

  • 这需要驱动程序或自定义硬件。尝试 timeBeginPeriod 和 timeSetEvent 以获得不那么激烈的方法。

标签: windows timer interrupt


【解决方案1】:

您可以使用SetThreadPriority 为关键线程赋予优先级。在这种情况下,您可能需要显式创建一个线程并使用CreateWaitableTimerExSetWaitableTimerExWaitForSingleObjectEx 而不是CreateTimerQueueTimer。确保关键线程在等待之间永远不会花费太长时间执行,否则 Windows 可能会停止正常工作。

如果最大延迟为 100 微秒,这可能还不够。您可能需要使用SetPriorityClass 函数将进程优先级类设置为 REALTIME_PRIORITY_CLASS,但请确保您的程序永远不会长时间占用 CPU,否则 Windows 将停止正常工作。特别是,如果你的程序挂起,整个操作系统都会挂起;在这种情况下,除非关闭电源,否则无法停止程序。

即使这样可能还不够。 Windows 不是实时操作系统,它可能无法满足您的要求。

【讨论】:

    【解决方案2】:

    我对 Windows 和毫秒的经验是它不可靠。 我通过 Nusbio 设备用示波器测量了 Sleep api。 而 Sleep(0) 与根本不调用该方法不同。 Sleep(5) 和 Sleep(15) 有时会给出不一致的结果,有时等待是相同的。

    如果您想要这种准确性,您需要一个可以与您的 Windows 应用程序对话的微控制器。

    【讨论】:

    • 这是记录在案的行为。没有惊喜。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-28
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 2021-08-15
    • 2010-11-04
    • 1970-01-01
    相关资源
    最近更新 更多