使用QueryPerformanceCounter(QPC)高精度计数器CPU 硬件计数器支持 微秒级,适合:步进电机脉冲、运动控制、IO 实时控制,完全满足发脉冲。采取子线程发脉冲,主线程(界面)实时响应停止按钮,设定转一圈脉冲数为3200个,程序功能步进电机正反转,可输入所要转的圈数,按停止按钮立即停止。

6408_demo_vcDlg.h
cpp
#if !defined(AFX_6408_DEMO_VCDLG_H__6F86E9CB_0D17_495C_A3C1_6DD1860E26B1__INCLUDED_)
#define AFX_6408_DEMO_VCDLG_H__6F86E9CB_0D17_495C_A3C1_6DD1860E26B1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif
#include "PC60002K.H"
class CMy6408_demo_vcDlg : public CDialog
{
public:
CMy6408_demo_vcDlg(CWnd* pParent = NULL);
enum { IDD = IDD_MY6408_DEMO_VC_DIALOG };
// 线程函数
static UINT SendPulseThread(LPVOID pParam);
protected:
HICON m_hIcon;
virtual void DoDataExchange(CDataExchange* pDX);
virtual BOOL OnInitDialog();
//{{AFX_MSG(CMy6408_demo_vcDlg)
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnBtnRunPos();
afx_msg void OnBtnRunNeg();
afx_msg void OnBtnStop();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
unsigned short m_nAddr;
double m_fCircle;
volatile int m_nStopFlag; // 停止标志
CString m_strCircle;
int m_nDir; // 方向 1正转 0反转
CWinThread* m_pThread; // 脉冲线程
};
#endif
6408_demo_vcDlg.cpp
cpp
#include "stdafx.h"
#include "6408_demo_vc.h"
#include "6408_demo_vcDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define PUL_CH 11
#define DIR_CH 12
#define PUL_PER_CIRCLE 3200
#define PULSE_HIGH_US 156
#define PULSE_LOW_US 156
// 微秒延时
void DelayUs(unsigned long us, volatile int *pStopFlag)
{
LARGE_INTEGER freq, now, end;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&now);
end.QuadPart = now.QuadPart + freq.QuadPart * us / 1000000;
while(1)
{
if(*pStopFlag) return;
QueryPerformanceCounter(&now);
if(now.QuadPart >= end.QuadPart) break;
}
}
// ==============================================
// ? 子线程:发脉冲(界面不会卡!停止立即响应!)
// ==============================================
UINT CMy6408_demo_vcDlg::SendPulseThread(LPVOID pParam)
{
CMy6408_demo_vcDlg* pDlg = (CMy6408_demo_vcDlg*)pParam;
long total = (long)(pDlg->m_fCircle * PUL_PER_CIRCLE);
DO6408Bit(pDlg->m_nAddr, DIR_CH, pDlg->m_nDir);
for(long i=0; i<total; i++)
{
if(pDlg->m_nStopFlag) break;
DO6408Bit(pDlg->m_nAddr, PUL_CH, 1);
DelayUs(PULSE_HIGH_US, &pDlg->m_nStopFlag);
DO6408Bit(pDlg->m_nAddr, PUL_CH, 0);
DelayUs(PULSE_LOW_US, &pDlg->m_nStopFlag);
}
DO6408Bit(pDlg->m_nAddr, PUL_CH, 0);
pDlg->m_pThread = NULL;
return 0;
}
// ===================== 下面全是原来代码,只改按钮函数 =====================
CMy6408_demo_vcDlg::CMy6408_demo_vcDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMy6408_demo_vcDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_nAddr = 0x100;
m_fCircle = 1.0;
m_nStopFlag = 0;
m_strCircle = _T("1.0");
m_pThread = NULL;
}
void CMy6408_demo_vcDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_CIRCLE, m_strCircle);
}
BEGIN_MESSAGE_MAP(CMy6408_demo_vcDlg, CDialog)
//{{AFX_MSG_MAP(CMy6408_demo_vcDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_POS, OnBtnRunPos)
ON_BN_CLICKED(IDC_BTN_NEG, OnBtnRunNeg)
ON_BN_CLICKED(IDC_BTN_STOP, OnBtnStop)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CMy6408_demo_vcDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
if(!OpenDevice6K())
AfxMessageBox(_T("打开PC6408板卡失败!"));
m_strCircle = _T("1.0");
UpdateData(FALSE);
DO6408Bit(m_nAddr,DIR_CH,0);
DO6408Bit(m_nAddr,PUL_CH,0);
return TRUE;
}
void CMy6408_demo_vcDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
CDialog::OnSysCommand(nID,lParam);
}
void CMy6408_demo_vcDlg::OnPaint()
{
if (IsIconic()){
CPaintDC dc(this);
SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);
int cx=GetSystemMetrics(SM_CXICON);
int cy=GetSystemMetrics(SM_CYICON);
CRect rc;GetClientRect(&rc);
int x=(rc.Width()-cx)/2,y=(rc.Height()-cy)/2;
dc.DrawIcon(x,y,m_hIcon);
}else CDialog::OnPaint();
}
HCURSOR CMy6408_demo_vcDlg::OnQueryDragIcon()
{
return (HCURSOR)m_hIcon;
}
// ===================== 正转(启动线程) =====================
void CMy6408_demo_vcDlg::OnBtnRunPos()
{
if(m_pThread != NULL) return; // 防止重复启动
UpdateData(TRUE);
m_fCircle = atof(m_strCircle);
if(m_fCircle <= 0){
AfxMessageBox(_T("圈数必须大于0!"));
return;
}
m_nDir = 1;
m_nStopFlag = 0;
// ? 启动子线程发脉冲(界面不卡!)
m_pThread = AfxBeginThread(SendPulseThread, this);
}
// ===================== 反转(启动线程) =====================
void CMy6408_demo_vcDlg::OnBtnRunNeg()
{
if(m_pThread != NULL) return;
UpdateData(TRUE);
m_fCircle = atof(m_strCircle);
if(m_fCircle <= 0){
AfxMessageBox(_T("圈数必须大于0!"));
return;
}
m_nDir = 0;
m_nStopFlag = 0;
m_pThread = AfxBeginThread(SendPulseThread, this);
}
// ===================== 停止(? 立即生效!) =====================
void CMy6408_demo_vcDlg::OnBtnStop()
{
m_nStopFlag = 1;
if(m_pThread)
{
WaitForSingleObject(m_pThread->m_hThread, 100);
m_pThread = NULL;
}
DO6408Bit(m_nAddr, PUL_CH, 0);
}