MFC开关量输出发脉冲实例

使用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);
}
相关推荐
卷无止境2 天前
C++ 的Eigen 库全解析
c++
卷无止境2 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端
郝学胜_神的一滴2 天前
CMake 27:缓存变量的特性、语法、类型与实操全解
c++·cmake
博客18004 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴4 天前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
众少成多积小致巨5 天前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
clint4569 天前
C++进阶(1)——前景提要
c++
夜悊9 天前
C++代码示例:进制数简单生成工具
c++
郝学胜_神的一滴9 天前
CMake 021: IF 条件判据详诠
c++·cmake
_wyt00110 天前
洛谷 B3930 [GESP202312 五级] 烹饪问题 题解
c++·gesp