WinCE工控主板支持高速脉冲计数

 2025-3-18 17:19:41     作者:刘乾坤     联系作者    

ESM7000是支持正版WEC7 / Linux的双核Cortex-A7工业级工控主板,支持双网口、双CAN、6路串口、触摸屏显示接口等,广泛应用于工控智能终端设备。根据客户的应用需求,我们为ESM7000增加了输入脉冲计数功能,支持对几赫兹到数十兆赫兹的输入脉冲信号进行准确计数,实现脉冲数量统计,脉冲频率换算功能。

3.png

ESM7000 WinCE / Linux工控主板

 1、实现原理 

对于低频脉冲信号计数,可通过简单的GPIO中断来实现。当输入脉冲频率超过数千赫兹时,频繁的GPIO中断会降低系统性能,并存在丢数风险,所以对高速脉冲计数通常需要专门的硬件来实现。

ESM7000主CPU为NXP的i.MX7D,我们利用了i.MX7D的通常定时器(GPT)的Capture功能来实现对高速脉冲的硬件计数。脉冲计数涉及到两个输入信号:1)被测信号——脉冲信号输入;2)测量周期控制信号——用于触发CPU Capture功能实现计数捕捉。

2.png

ESM7000脉冲计数功能对应的GPIO如下所示:

ESM7000 Pin

ESM7000 GPIO

功能说明

D9

GPIO8

测量周期控制信号输出

D10

GPIO9

测量周期控制信号输入

D15

GPIO14

脉冲信号输入

测量周期控制信号由驱动程序从GPIO8输出,所以实际应用时,需要将GPIO8与GPIO9短接(建议使用0R电阻短接)。GPIO14为被测脉冲信号输入,需要注意输入信号电平不能直接3.3V,否则必须通过电平转换后才能接入。

 2、应用程序 

ESM7000脉冲计数功能的设备驱动名为“CNT1:”,ESM7000所有GPIO在系统上电后的缺省状态为GPIO输入上拉,打开“CNT1:”后,GPIO8,GPIO9, GPIO14会自动切换为脉冲计数功能引脚。

在应用程序中设置测量周期后,驱动程序就开始对输入脉冲连续计数,DeviceIoControl会在每个测量周期自动返回,并运回脉冲计数值。

完整的应用程序代码如下:

#include "stdafx.h"
#include <winioctl.h>
#include "bsp_drivers.h"
 
BOOL bThreadStop = FALSE;
DWORD   dwCountingPeriod;
DWORD   max = 0, min = 0xffffffff;
 
DWORD WINAPI CntThread(PVOID pArg)
{
    BOOL bRet;
    DWORD   dwTimeout;
    DWORD   dwCount;
    HANDLE  hCnt;
    
    hCnt = (HANDLE)pArg;
    dwTimeout = INFINITE;
    while (!bThreadStop) {
        // 等待获取脉冲计数值
        bRet = DeviceIoControl(hCnt,      // file handle to the driver
            IOCTL_WAIT_FOR_EVENT,        // I/O control code
            NULL,                       // in buffer
            0,                          // in buffer size
            &dwCount,                    // out buffer
            sizeof(DWORD),                   // out buffer size
            NULL,                           // pointer to number of bytes returned
            NULL);                          // ignored (=NULL)
 
        if(bRet) {           
            if(dwCount > max){
                max = dwCount;
                if(min != 0xffffffff)
                    printf("max:%d min:%d Frequency:%.2fKHz\r\n", 
                        max, min, (float)dwCount/(float)dwCountingPeriod);
            }
            if(dwCount < min){
                min = dwCount;
                printf("max:%d min:%d Frequency:%.2fKHz\r\n", 
                    max, min, (float)dwCount/(float)dwCountingPeriod);
            }
        }
    }
    
    return 0;
}
 
int _tmain(int argc, _TCHAR* argv[])
{   
    int     num = 10;
 
    HANDLE hCnt = CreateFile(L"CNT1:", 0, 0,  NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);    HANDLE hThread = CreateThread(NULL, 0, CntThread, (LPVOID)hCnt, 0, NULL);
    
    // 配置并启动计数
    dwCountingPeriod = 1000;     // 计数周期,单位毫秒(可设置范围1ms ~ 1000ms)
    DeviceIoControl(hCnt,        // file handle to the driver
            IOCTL_GENERIC_START, // I/O control code
            &dwCountingPeriod,   // in buffer
            sizeof(DWORD),       // in buffer size
            NULL,               // out buffer
            0,                  // out buffer size
            NULL,               // pointer to number of bytes returned
            NULL);  
 
    while(num--) {
        Sleep(1000);
    }
 
    /* 可调用IOCTL_GENERIC_STOP临时停止计数,调用IOCTL_GENERIC_SETUP再次开始计数   */
    DeviceIoControl(hCnt, IOCTL_GENERIC_STOP, NULL, 0, NULL, 0, NULL, NULL); 
 
    bThreadStop = TRUE;
    
    CloseHandle(hThread);
    CloseHandle(hCnt);
    return 0;
}