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);
}
相关推荐
啊啊啊啊啊!!!!17 小时前
【c++】stack和queue的接口使用以及底层实现
开发语言·c++
(Charon)19 小时前
【C++】锁与原子操作(四):自旋锁的完整实现与性能优化
c语言·开发语言·c++
ShineWinsu20 小时前
对于Linux:五种IO模型以及非阻塞IO的详细解析
linux·c++·面试·io·阻塞·非阻塞·fcntl
呜喵王阿尔萨斯21 小时前
extern “C“ in C++
c语言·c++·算法
乐观勇敢坚强的老彭21 小时前
C++信奥静态数组和动态数组
数据结构·c++·算法
gumichef1 天前
第一章:面向对象核心——类和对象深度讲解
开发语言·c++
ao-weilai1 天前
C++基础:类和对象
开发语言·c++
郝学胜-神的一滴1 天前
[简化版 GAMES 104] 现代游戏引擎 04:从0到1构建你的游戏世界
c++·游戏·unity·游戏引擎·软件工程·unreal engine
Bryce学亮1 天前
FileLine,基于 Qt 6 + QML 构建的跨平台文件传输与即时通讯工具
数据库·c++·人工智能·python·qt·github
旖旎夜光1 天前
LeetCode 991: 坏了的计算器(贪心算法) —— 题解
数据结构·c++·算法·leetcode·贪心算法