ESM7000是支持正版WEC7 / Linux的双核Cortex-A7工业级工控主板,支持双网口、双CAN、6路串口、触摸屏显示接口等,广泛应用于工控智能终端设备。根据客户的应用需求,我们为ESM7000增加了输入脉冲计数功能,支持对几赫兹到数十兆赫兹的输入脉冲信号进行准确计数,实现脉冲数量统计,脉冲频率换算功能。
ESM7000 WinCE / Linux工控主板
1. 实现原理
对于低频脉冲信号计数,可通过简单的GPIO中断来实现。当输入脉冲频率超过数千赫兹时,频繁的GPIO中断会降低系统性能,并存在丢数风险,所以对高速脉冲计数通常需要专门的硬件来实现。
ESM7000主CPU为NXP的i.MX7D,我们利用了i.MX7D的通常定时器(GPT)的Capture功能来实现对高速脉冲的硬件计数。脉冲计数涉及到两个输入信号:1)被测信号——脉冲信号输入;2)测量周期控制信号——用于触发CPU Capture功能实现计数捕捉。
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
#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;
}