LabwindowsCVI 实现高精度Timer

       在写程序中,会经常遇到与时间有关系的代码,比如延迟、周期性调用某函数、获取系统时间等等,如果时间定的不准确,可以想象该系统的不可靠性。在LabwindowsCVI中,有一种简单的定时器实现方式,可直接添加Timer定时器控件,然后设置Timer的调度周期和回调函数,这样主线程就会在周期内调用Timer的回调函数了,但这种方式的实现精度并不高,很容易受其它应用程序及主线程其它应用代码的阻塞。本章将介绍一种高精确定时方式的实现,其简单来说就是开一个优先级较高的线程,然后该线程查询系统的晶振时间,通过晶振时间来实现精确定时。下面将介绍LabwindowsCVI对线程的创建及系统晶振时间的读取。

线程:

       LabwindowsCVI对线程支持的API如下所示:

 

CmtNewThreadPool:

       CmtNewThreadPool用于创建一个线程池,该函数原型如下所示:

int CmtNewThreadPool (int maximumNumberOfThreads, CmtThreadPoolHandle *poolHandle);

其中maximumNumberOfThreads为该线程池线程的数量,poolHandle为创建成功后的线程池句柄。

 

 

CmtScheduleThreadPoolFunctionAdv:

       CmtScheduleThreadPoolFunctionAdv用于设置一个线程来执行任务函数,其函数原型如下所示:

int CmtScheduleThreadPoolFunctionAdv (CmtThreadPoolHandle poolHandle, CmtThreadFunctionPtr threadFunction, void *threadFunctionData, int threadFunctionPriority, CmtThreadFunctionCallbackPtr callbackFunction, unsigned int callbackEventMask, void *callbackData, unsigned int callbackThreadID, CmtThreadFunctionID *threadFunctionID);

其中poolHandle为CmtNewThreadPool创建的线程池句柄,threadFunction为线程函数即任务函数,threadFunctionData为线程函数的参数,threadFunctionPriority为调用线程函数线程的优先级,callbackFunction为线程回调函数,该函数在任务函数执行前后运行,callbackEventMask为线程回调函数事件的位屏蔽,callbackData为线程回调函数的参数,callbackThreadID为执行线程函数的线程ID,threadFunctionID为线程函数的ID。

 

 

CmtWaitForThreadPoolFunctionCompletion:

       CmtWaitForThreadPoolFunctionCompletion为等待线程函数的执行完成,其函数原型如下所示:

int CmtWaitForThreadPoolFunctionCompletion (CmtThreadPoolHandle poolHandle, CmtThreadFunctionID threadFunctionID, unsigned int options);

其中poolHandle为线程池的句柄,threadFunctionID为线程函数的ID,options为等待该线程函数执行完时是否处理事件。

 

线程函数:

线程函数也是任务函数,其函数的原型如下所示:

int CVICALLBACK ThreadFunction (void *functionData);

通常我们在线程函数中会执行一个死循环直到应用程序退出,否则该线程将占用系统资源而不释放,导致电脑系统卡顿。

晶振时间:

       LabwindowsCVI利用windows库里面的API来实现晶振时间的读取,其API如下所示:

 

QueryPerformanceCounter:

       QueryPerformanceCounter用于查询系统晶振计数,其函数原型如下所示:

WINBASEAPI BOOL WINAPI QueryPerformanceCounter(__out LARGE_INTEGER *lpPerformanceCount);

其中lpPerformanceCount为查询的晶振计数。

 

 

QueryPerformanceFrequency:

       QueryPerformanceFrequency用于查询晶振每秒的计数,其函数原型如下所示:

WINBASEAPI BOOL WINAPI QueryPerformanceFrequency(

__out LARGE_INTEGER *lpFrequency);

其中lpFrequency为查询的晶振每秒的计数。

项目实践:

       新建LabwindowsCVI工程,在c文件头文件声明最开始的地方添加#include <windows.h>声明,否则将与头文件utility.h和formatio.h命名冲突,导致编译通不过。工程代码如下所示:

#include <windows.h>
#include <ansi_c.h>
#include <utility.h>
#include <userint.h>
#include <cvirte.h>
#include "HighPrecisionTimerTest.h" 

static int panelHandle;
CmtThreadFunctionID backgroundThreadFunctionID;
volatile int AppRunningFlag = 0;
CmtThreadPoolHandle threadPoolHandle;
char errorStringBuffer[256];

int CVICALLBACK BackgroundThreadFunction (void *functionData); 

int CreateBackgroundThread(void)
{
    int ret = -1;
    ret = CmtNewThreadPool (1, &threadPoolHandle);    
    
    if(ret < 0)
    {
        CmtGetErrorMessage(ret,errorStringBuffer);
        printf("%s\r\n",errorStringBuffer);
    }
    else
    {
        ret = CmtScheduleThreadPoolFunctionAdv(threadPoolHandle,BackgroundThreadFunction,NULL,THREAD_PRIORITY_HIGHEST,NULL,EVENT_TP_THREAD_FUNCTION_END,NULL,RUN_IN_SCHEDULED_THREAD,&backgroundThreadFunctionID);
        
        if(ret < 0)
        {
            CmtGetErrorMessage(ret,errorStringBuffer);
            printf("%s\r\n",errorStringBuffer); 
        }
    }
    return ret;
}

int QuitBackgroundThread(void)
{
    CmtWaitForThreadPoolFunctionCompletion(threadPoolHandle,backgroundThreadFunctionID,OPT_TP_PROCESS_EVENTS_WHILE_WAITING);    
    return 0;
}
int QueryTickPeriod(LARGE_INTEGER *begin,LARGE_INTEGER *end,LONGLONG tick)
{
    if(end->QuadPart >= begin->QuadPart)
    {
        if((end->QuadPart - begin->QuadPart) >= tick)
        {
            return 1;    
        }
        else
        {
            return 0;    
        }
    }
    else
    {
        if((0xFFFFFFFFFFFFFFFF - begin->QuadPart + end->QuadPart) >= tick)
        {
            return 1;    
        }
        else
        {
            return 0;    
        }
    }
}
void Task1ms(void)
{
    static int cnt =0;
    if(cnt >= 1000)
    {
           printf("1s count\r\n");
        cnt = 0;
    }
    else
    {
        cnt ++;    
    }
}

int CVICALLBACK BackgroundThreadFunction (void *functionData)
{
    LARGE_INTEGER begin, end, ticksPerSecond;
    LONGLONG tickPeriod;
    AppRunningFlag = 1;
    QueryPerformanceFrequency (&ticksPerSecond);
    tickPeriod = ticksPerSecond.QuadPart/1000;//可修改tick的周期值
    while(AppRunningFlag)
    {
        QueryPerformanceCounter (&begin);
        QueryPerformanceCounter (&end);
        while(QueryTickPeriod(&begin,&end,tickPeriod) == 0) 
        {
            QueryPerformanceCounter (&end);    
        }
        Task1ms();
    }
    return 0;
}
int main (int argc, char *argv[])
{
    if (InitCVIRTE (0, argv, 0) == 0)
        return -1;    /* out of memory */
    if ((panelHandle = LoadPanel (0, "HighPrecisionTimerTest.uir", PANEL)) < 0)
        return -1;
    DisplayPanel (panelHandle);
    CreateBackgroundThread();
    RunUserInterface ();
    QuitBackgroundThread();
    DiscardPanel (panelHandle);
    return 0;
}

int CVICALLBACK quit (int panel, int control, int event,
                      void *callbackData, int eventData1, int eventData2)
{
    switch (event)
    {
        case EVENT_COMMIT:
            QuitUserInterface(0);
            AppRunningFlag = 0;
            break;
    }
    return 0;
}

实践效果:

       后台线程每秒钟打印 1s count,如下图所示:

后话:

       本测试工程实现了高精度的计时,用户可以将BackgroundThreadFunction当成工作线程,添加自己的其它任务代码。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值