研华USB4711A采集卡是一款USB接口的采集卡,笔记本上就可以用,不用专门要ISA或者PCI插槽,价格上倒是比较贵,AI最多可以到150KS/s。这里记录高速中断模式采集使用方法。
windows平台:xp sp3
框架:vs2010 MFC 单文档
采集速度:4通道,每通道200HZ
采集模式:使用FIFO
==============================================================
- 安装研华设备管理器、4711驱动,再装下研华光盘给的MFC例子,里面AD_INT和MAD_INT是官方给的高速采集demo。
- 将研华给的头文件及lib库文件添加到工程文件夹里。本站下载在这里,工程属性-linker-input-additinal dependencies里添加adsapi32.lib,工程属性-linker-general-additinal library dependencies里添加adsapi32.lib所在目录,工程.h文件里包含头文件#include "Driver.h"
- .h文件里添加变量声明
LRESULT m_ErrCode; LONG m_DriverHandle;ULONG m_dwDeviceNum; DEVFEATURES m_DevFeatures;ULONG m_gwActualBufSize;USHORT m_GainCode;USHORT m_gwActiveBuf; // return by FAICheckUSHORT m_gwOverrun; // return by FAICheck, FAITransferUSHORT m_gwStopped; // return by FAICheckULONG m_gulRetrieved; // return by FAICheckUSHORT m_gwHalfReady; // return by FAICheckPT_DeviceGetFeatures m_ptDevFeatures;// PT_FAIIntStart m_ptFAIIntStart; // FAIIntStart tablePT_FAIIntScanStart m_ptFAIIntScanStart; // m_ptFAIIntScanStart tablePT_FAITransfer m_ptFAITransfer; // FAITransfer tablePT_FAICheck m_ptFAICheck; // FAICheck tablePT_AllocateDMABuffer m_ptAllocateDMABuffer; // buffer tablePT_EnableEvent m_ptEnableEvent; // Enable eventPT_CheckEvent m_ptCheckEvent; // Check eventUSHORT m_CyclicCount;CWinThread* m_pEventThread;HGLOBAL m_hUserBuf;HGLOBAL m_hBuf;ULONG m_ulInterruptCount;ULONG m_ulOverRunCount;ULONG m_ulBuffCount;//OpenEvent dialog get follow parbool m_bGetParOk;//int m_GainOption;USHORT m_Gain[4];int m_Model;int m_Triggering;int m_Buffer;int m_DataType;int m_Event;int m_PacerRate;int m_Conv;CString m_InputRange;int m_ScanChannel;int m_FifoSize;BOOL m_EnableFifo;LPVOID temp;void adInterruptEvent();void adBufChangeEvent();void adOverrunEvent();void adTerminateEvent();
- .cpp的构造函数里初始化参数,这里直接设定了,没用自带demo从对话框配置参数。
m_gwActualBufSize = 0;m_ulBuffCount = 0;m_ulInterruptCount = 0;m_ulOverRunCount = 0;m_Conv = 128 ; //单次采集个数m_Gain[0] = 4 ; //增益选项 10v-4 5v-0 m_Gain[1] = 0 ;m_Gain[2] = 0 ;m_Gain[3] = 0 ;m_Model = 1 ; //是否循环模式m_Triggering = 0 ; //内触发模式m_Buffer = 0 ; m_DataType = 1 ; //0-二进制值 1-电压值 m_dwDeviceNum = 0 ; //管理器里设备编号m_Event = 1 ; //事件使能m_GainCode = 0 ; //内触发模式m_PacerRate = 800 ; //采样频率单位 HZ USB4711A form 1 Hz to 150 kHz 但是是8个通道累积达到单通道最高150/8m_InputRange = _T("") ; //m_FifoSize = 64 ; //设定FIFO大小 7411为1024 buffer大小应该是FIFO/2 大小的整数倍(偶数),m_EnableFifo = TRUE ; //使用FIFOm_bGetParOk = true ;
- 开启采集
// Step 1: Open Devicem_ErrCode = DRV_DeviceOpen(m_dwDeviceNum, (LONG far *)&m_DriverHandle);CString s;if (m_ErrCode != SUCCESS){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);s = m_szErrorMsg;AfxMessageBox(s);return;}// Step 2: Get device featuresm_ptDevFeatures.buffer = (LPDEVFEATURES)&m_DevFeatures;m_ptDevFeatures.size = sizeof(DEVFEATURES);if ((m_ErrCode = DRV_DeviceGetFeatures(m_DriverHandle,(LPT_DeviceGetFeatures)&m_ptDevFeatures)) != SUCCESS){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);s = m_szErrorMsg;AfxMessageBox(s);DRV_DeviceClose((LONG far *)&m_DriverHandle);return;}// Step 3: Allocate memory for driverif((m_hBuf=(USHORT far *)GlobalAlloc(GHND,sizeof(USHORT) * m_Conv)) == 0){ AfxMessageBox(_T("高速缓存不足!"));DRV_DeviceClose((LONG far *)&m_DriverHandle);return;}// Step 4: Allocate memory for Voltage data or Raw dataif((m_hUserBuf=(FLOAT far *)GlobalAlloc(GHND,sizeof(FLOAT) * m_Conv )) == 0){ AfxMessageBox(_T("高速缓存不足!"));DRV_DeviceClose((LONG far *)&m_DriverHandle);return;}// Prepare some informations to runm_ptFAIIntScanStart.buffer = (USHORT far *)GlobalLock(m_hBuf);/* */m_ptFAITransfer.DataBuffer = (FLOAT far *)GlobalLock(m_hUserBuf);// Step 5: Enable event featurem_ptEnableEvent.EventType = ADS_EVT_INTERRUPT |ADS_EVT_BUFCHANGE |ADS_EVT_TERMINATED |ADS_EVT_OVERRUN;m_ptEnableEvent.Enabled = m_Event;m_ptEnableEvent.Count = m_EnableFifo ? m_FifoSize : 1;if ((m_ErrCode = DRV_EnableEvent(m_DriverHandle,(LPT_EnableEvent)&m_ptEnableEvent)) != 0){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);s = m_szErrorMsg;AfxMessageBox(s);GlobalUnlock(m_hBuf);GlobalUnlock(m_hUserBuf);GlobalFree(m_hBuf);GlobalFree(m_hUserBuf);DRV_DeviceClose((LONG far *)&m_DriverHandle);return;}// Step 6: Start Interrupt transferm_ptFAIIntScanStart.TrigSrc = m_Triggering;m_ptFAIIntScanStart.SampleRate = m_PacerRate;m_ptFAIIntScanStart.StartChan = 0;m_ptFAIIntScanStart.NumChans = 4;m_ptFAIIntScanStart.GainList = &m_Gain[0];m_ptFAIIntScanStart.count = m_Conv;m_ptFAIIntScanStart.cyclic = m_Model;if (m_EnableFifo && m_FifoSize)m_ptFAIIntScanStart.IntrCount = m_FifoSize;elsem_ptFAIIntScanStart.IntrCount = 1;if ((m_ErrCode = DRV_FAIIntScanStart(m_DriverHandle,(LPT_FAIIntScanStart32)&m_ptFAIIntScanStart)) != 0){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);s = m_szErrorMsg;AfxMessageBox(s);GlobalUnlock(m_hBuf);GlobalUnlock(m_hUserBuf);GlobalFree(m_hBuf);GlobalFree(m_hUserBuf);DRV_DeviceClose((LONG far *)&m_DriverHandle);return;}m_CyclicCount = 0; if (m_Event){m_pEventThread = AfxBeginThread(EventThread,this);}m_ulInterruptCount=0;m_ulBuffCount=0; m_ulOverRunCount=0;
- 几个配合函数照抄demo里的函数
void CUSB4711AIINTView::adInterruptEvent(){return;}void CUSB4711AIINTView::adOverrunEvent(){// clear overrunif ((m_ErrCode = DRV_ClearOverrun(m_DriverHandle)) != 0){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);CString s;s = m_szErrorMsg;AfxMessageBox(s);return ;}return;}void CUSB4711AIINTView::adTerminateEvent(){// Get real voltage of buffer from driverm_ptFAITransfer.ActiveBuf = 0; // single bufferm_ptFAITransfer.DataType = m_DataType;m_ptFAITransfer.start = 0;m_ptFAITransfer.count = m_Conv;m_ptFAITransfer.overrun = &m_gwOverrun;if ((m_ErrCode = DRV_FAITransfer(m_DriverHandle,(LPT_FAITransfer)&m_ptFAITransfer)) != 0){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);CString s;s = m_szErrorMsg;AfxMessageBox(s);return ;}// Close driverDRV_DeviceClose((LONG far *)&m_DriverHandle);GlobalUnlock(m_hBuf);GlobalUnlock(m_hUserBuf);GlobalFree(m_hBuf);GlobalFree(m_hUserBuf);return;}UINT EventThread( LPVOID pParam ){USHORT usEventType;LONG ErrCde;CUSB4711AIINTView* pView = (CUSB4711AIINTView*)pParam;pView->m_ulInterruptCount=0;pView->m_ulBuffCount=0; pView->m_ulOverRunCount=0;while(1){// Check messagepView->m_ptCheckEvent.EventType = &usEventType;if ((pView->m_Triggering) || (pView->m_Model) ){pView->m_ptCheckEvent.Milliseconds = INFINITE;}else{pView->m_ptCheckEvent.Milliseconds = 1000 * (pView->m_Conv / pView->m_PacerRate) + 1000;}if ((ErrCde = DRV_CheckEvent(pView->m_DriverHandle,(LPT_CheckEvent)&pView->m_ptCheckEvent)) != 0){ AfxMessageBox(_T("Check Event Error !"));return 0;}// Process interrupt eventif (usEventType & ADS_EVT_INTERRUPT){pView->adInterruptEvent();pView->m_ulInterruptCount++;}// Process buffer change eventif (usEventType & ADS_EVT_BUFCHANGE){pView->m_ulBuffCount++; pView->adBufChangeEvent();}// Process overrun eventif (usEventType & ADS_EVT_OVERRUN){pView->m_ulOverRunCount++;pView->adOverrunEvent();}// Process terminate eventif (usEventType & ADS_EVT_TERMINATED){pView->adTerminateEvent(); return 0;}}AfxEndThread(0,true);return 0;}
- 最关键的步骤在函数
这里涉及到FIFO工作模式,在这个程序里,一次采集128个数据,半个buffer就是64,buffer每半满,系统会产生一个HalfReady,此时读取driver缓存里的数据,不会产生错误。void CUSB4711AIINTView::adBufChangeEvent(){m_ptFAICheck.ActiveBuf = &m_gwActiveBuf;m_ptFAICheck.stopped = &m_gwStopped;m_ptFAICheck.retrieved = &m_gulRetrieved;m_ptFAICheck.overrun = &m_gwOverrun;m_ptFAICheck.HalfReady = &m_gwHalfReady;if ((m_ErrCode = DRV_FAICheck(m_DriverHandle,(LPT_FAICheck)&m_ptFAICheck)) != 0){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);CString s;s = m_szErrorMsg;AfxMessageBox(s);return ;}if( m_gwHalfReady == 1 ){m_ptFAITransfer.ActiveBuf = 0; // single bufferm_ptFAITransfer.DataType = m_DataType;m_ptFAITransfer.start = 0;m_ptFAITransfer.count = m_Conv/2;m_ptFAITransfer.overrun = &m_gwOverrun;if ((m_ErrCode = DRV_FAITransfer(m_DriverHandle,(LPT_FAITransfer)&m_ptFAITransfer)) != 0){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);CString s;s = m_szErrorMsg;AfxMessageBox(s);return ;}temp = (FLOAT far *)m_ptFAITransfer.DataBuffer;for (int i=0;i<64;i++){ x[i] = (i + 64 * m_CyclicCount * 2) * 1.0 ;y[i] = ((FLOAT far *)temp)[i];}}else if( m_gwHalfReady == 2 ){m_ptFAITransfer.ActiveBuf = 0; // single bufferm_ptFAITransfer.DataType = m_DataType;m_ptFAITransfer.start = m_Conv/2;m_ptFAITransfer.count = m_Conv/2;m_ptFAITransfer.overrun = &m_gwOverrun;if ((m_ErrCode = DRV_FAITransfer(m_DriverHandle,(LPT_FAITransfer)&m_ptFAITransfer)) != 0){DRV_GetErrorMessage(m_ErrCode,(LPSTR)m_szErrorMsg);CString s;s = m_szErrorMsg;AfxMessageBox(s);return ;}temp = (FLOAT far *)m_ptFAITransfer.DataBuffer;for (int i=0;i<64;i++){x[i+64] = (i + 64 * (m_CyclicCount * 2 + 1)) * 1.0 ;y[i+64] = ((FLOAT far *)temp)[i];}m_CyclicCount++;}return;}