高精度微秒延时函数实现顺控工控项目实例

1、用高精度微秒延时函数,做一个顺控工控项目程序,点击 启动顺控:正常执行 加压→保持→平衡→检测→排气 整套流程,时间按编辑框设置(0.01s 精度)。

2、流程运行中任意时刻点击 停止流程:立即置位停止标志。

3、volatile int g_StopFlag 全局标志被所有延时函数轮询检测,响应及时;停止操作是软停止,不会强制杀线程,工控场景安全稳定;再次点击「启动顺控」会自动清空停止标志,重新开始一轮流程。

SeqControlDlg.h

cpp 复制代码
#include "stdafx.h"
#include "SeqControl.h"
#include "SeqControlDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// 全局停止标志
volatile int g_StopFlag = 0;

CSeqControlDlg::CSeqControlDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSeqControlDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CSeqControlDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	// 原有控件绑定
	DDX_Control(pDX, IDC_STATUS, m_Status);
	DDX_Control(pDX, IDC_STEP_TIME, m_StepTime);
	DDX_Control(pDX, IDC_EDIT_EXHAUST, m_EditExhaust);
	DDX_Control(pDX, IDC_EDIT_TEST, m_EditTest);
	DDX_Control(pDX, IDC_EDIT_BALANCE, m_EditBalance);
	DDX_Control(pDX, IDC_EDIT_HOLD, m_EditHold);
	DDX_Control(pDX, IDC_EDIT_PRESS, m_EditPress);
	// 新增阀门控件绑定
	DDX_Control(pDX, IDC_VALVE_CLAMP, m_ValveClamp);
	DDX_Control(pDX, IDC_VALVE_IN, m_ValveIn);
	DDX_Control(pDX, IDC_VALVE_BAL, m_ValveBal);
	DDX_Control(pDX, IDC_VALVE_EXH, m_ValveExh);
}

BEGIN_MESSAGE_MAP(CSeqControlDlg, CDialog)
	//{{AFX_MSG_MAP(CSeqControlDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
	ON_BN_CLICKED(IDC_BTN_STOP, OnBtnStop)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CSeqControlDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	// 初始化时间参数默认值
	m_EditPress.SetWindowText("2.00");
	m_EditHold.SetWindowText("5.00");
	m_EditBalance.SetWindowText("1.50");
	m_EditTest.SetWindowText("3.20");
	m_EditExhaust.SetWindowText("2.50");
	m_StepTime.SetWindowText("步骤用时:0.00 s");
	// 初始化所有阀门为关闭状态
	UpdateValveDisplay(false, false, false, false);
	return TRUE;
}

// 统一更新4个阀门文本显示的封装函数
void CSeqControlDlg::UpdateValveDisplay(bool clamp, bool inValve, bool balValve, bool exhValve)
{
	m_ValveClamp.SetWindowText(clamp ? "夹紧阀:开启" : "夹紧阀:关闭");
	m_ValveIn.SetWindowText(inValve ? "进气阀:开启" : "进气阀:关闭");
	m_ValveBal.SetWindowText(balValve ? "平衡阀:开启" : "平衡阀:关闭");
	m_ValveExh.SetWindowText(exhValve ? "排气阀:开启" : "排气阀:关闭");
}

void CSeqControlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	CDialog::OnSysCommand(nID, lParam);
}

void CSeqControlDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this);
		SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CSeqControlDlg::OnQueryDragIcon()
{
	return (HCURSOR)m_hIcon;
}

// 微秒级高精度延时基础函数
void CSeqControlDlg::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;
	}
}

// 带界面刷新的秒级高精度延时
void CSeqControlDlg::Delay_001Sec(double sec, volatile int *pStopFlag, CStatic* pTimeCtrl)
{
	LARGE_INTEGER freq, start, now;
	QueryPerformanceFrequency(&freq);
	QueryPerformanceCounter(&start);

	double totalSec = sec;
	double elapsed = 0.0;
	double lastUpdate = 0.0;

	while (elapsed < totalSec)
	{
		if (*pStopFlag) break;

		QueryPerformanceCounter(&now);
		elapsed = (double)(now.QuadPart - start.QuadPart) / freq.QuadPart;

		// 每0.01秒刷新一次时间显示
		if (elapsed - lastUpdate >= 0.01)
		{
			CString str;
			str.Format("步骤用时:%.2f s", elapsed);
			pTimeCtrl->SetWindowText(str);
			lastUpdate = elapsed;
		}
		DelayUs(100, pStopFlag);
	}

	// 步骤结束最终刷新时间
	CString strFinal;
	strFinal.Format("步骤用时:%.2f s", elapsed);
	pTimeCtrl->SetWindowText(strFinal);
}

// 核心顺序流程线程
UINT __cdecl CSeqControlDlg::SequenceThread(LPVOID pParam)
{
	CSeqControlDlg *pDlg = (CSeqControlDlg*)pParam;
	g_StopFlag = 0;

	CString str;
	double tPress, tHold, tBalance, tTest, tExhaust;

	// 读取界面设置的各阶段时长
	pDlg->m_EditPress.GetWindowText(str); tPress = atof(str);
	pDlg->m_EditHold.GetWindowText(str);  tHold = atof(str);
	pDlg->m_EditBalance.GetWindowText(str); tBalance = atof(str);
	pDlg->m_EditTest.GetWindowText(str); tTest = atof(str);
	pDlg->m_EditExhaust.GetWindowText(str); tExhaust = atof(str);

	// ==========1.加压阶段:夹紧1、进气1、平衡1、排气0==========
	pDlg->m_Status.SetWindowText("状态:正在加压...");
	pDlg->UpdateValveDisplay(true, true, true, false);
	pDlg->Delay_001Sec(tPress, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========2.保持阶段:夹紧1、进气1、平衡1、排气0==========
	pDlg->m_Status.SetWindowText("状态:压力保持中...");
	pDlg->UpdateValveDisplay(true, true, true, false);
	pDlg->Delay_001Sec(tHold, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========3.平衡阶段:夹紧1、进气0、平衡1、排气0==========
	pDlg->m_Status.SetWindowText("状态:压力平衡中...");
	pDlg->UpdateValveDisplay(true, false, true, false);
	pDlg->Delay_001Sec(tBalance, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========4.检测阶段:夹紧1、进气0、平衡0、排气0==========
	pDlg->m_Status.SetWindowText("状态:数据检测中...");
	pDlg->UpdateValveDisplay(true, false, false, false);
	pDlg->Delay_001Sec(tTest, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========5.排气阶段:夹紧1、进气0、平衡1、排气1==========
	pDlg->m_Status.SetWindowText("状态:排气泄压中...");
	pDlg->UpdateValveDisplay(true, false, true, true);
	pDlg->Delay_001Sec(tExhaust, &g_StopFlag, &pDlg->m_StepTime);

	// 排气全部结束:所有阀门复位关闭
	pDlg->UpdateValveDisplay(false, false, false, false);
	pDlg->m_StepTime.SetWindowText("步骤用时:完成");
	pDlg->m_Status.SetWindowText("状态:流程全部完成!");
	return 0;
}

// 启动按钮响应
void CSeqControlDlg::OnBtnStart()
{
	AfxBeginThread(SequenceThread, this);
}

// 停止按钮响应:所有阀门立即复位关闭
void CSeqControlDlg::OnBtnStop()
{
	g_StopFlag = 1;
	UpdateValveDisplay(false, false, false, false);
	m_Status.SetWindowText("状态:正在停止...");
}

SeqControlDlg.cpp

cpp 复制代码
#include "stdafx.h"
#include "SeqControl.h"
#include "SeqControlDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// 全局停止标志
volatile int g_StopFlag = 0;

CSeqControlDlg::CSeqControlDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSeqControlDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CSeqControlDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	// 原有控件绑定
	DDX_Control(pDX, IDC_STATUS, m_Status);
	DDX_Control(pDX, IDC_STEP_TIME, m_StepTime);
	DDX_Control(pDX, IDC_EDIT_EXHAUST, m_EditExhaust);
	DDX_Control(pDX, IDC_EDIT_TEST, m_EditTest);
	DDX_Control(pDX, IDC_EDIT_BALANCE, m_EditBalance);
	DDX_Control(pDX, IDC_EDIT_HOLD, m_EditHold);
	DDX_Control(pDX, IDC_EDIT_PRESS, m_EditPress);
	// 新增阀门控件绑定
	DDX_Control(pDX, IDC_VALVE_CLAMP, m_ValveClamp);
	DDX_Control(pDX, IDC_VALVE_IN, m_ValveIn);
	DDX_Control(pDX, IDC_VALVE_BAL, m_ValveBal);
	DDX_Control(pDX, IDC_VALVE_EXH, m_ValveExh);
}

BEGIN_MESSAGE_MAP(CSeqControlDlg, CDialog)
	//{{AFX_MSG_MAP(CSeqControlDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
	ON_BN_CLICKED(IDC_BTN_STOP, OnBtnStop)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CSeqControlDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	// 初始化时间参数默认值
	m_EditPress.SetWindowText("2.00");
	m_EditHold.SetWindowText("5.00");
	m_EditBalance.SetWindowText("1.50");
	m_EditTest.SetWindowText("3.20");
	m_EditExhaust.SetWindowText("2.50");
	m_StepTime.SetWindowText("步骤用时:0.00 s");
	// 初始化所有阀门为关闭状态
	UpdateValveDisplay(false, false, false, false);
	return TRUE;
}

// 统一更新4个阀门文本显示的封装函数
void CSeqControlDlg::UpdateValveDisplay(bool clamp, bool inValve, bool balValve, bool exhValve)
{
	m_ValveClamp.SetWindowText(clamp ? "夹紧阀:开启" : "夹紧阀:关闭");
	m_ValveIn.SetWindowText(inValve ? "进气阀:开启" : "进气阀:关闭");
	m_ValveBal.SetWindowText(balValve ? "平衡阀:开启" : "平衡阀:关闭");
	m_ValveExh.SetWindowText(exhValve ? "排气阀:开启" : "排气阀:关闭");
}

void CSeqControlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	CDialog::OnSysCommand(nID, lParam);
}

void CSeqControlDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this);
		SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CSeqControlDlg::OnQueryDragIcon()
{
	return (HCURSOR)m_hIcon;
}

// 微秒级高精度延时基础函数
void CSeqControlDlg::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;
	}
}

// 带界面刷新的秒级高精度延时
void CSeqControlDlg::Delay_001Sec(double sec, volatile int *pStopFlag, CStatic* pTimeCtrl)
{
	LARGE_INTEGER freq, start, now;
	QueryPerformanceFrequency(&freq);
	QueryPerformanceCounter(&start);

	double totalSec = sec;
	double elapsed = 0.0;
	double lastUpdate = 0.0;

	while (elapsed < totalSec)
	{
		if (*pStopFlag) break;

		QueryPerformanceCounter(&now);
		elapsed = (double)(now.QuadPart - start.QuadPart) / freq.QuadPart;

		// 每0.01秒刷新一次时间显示
		if (elapsed - lastUpdate >= 0.01)
		{
			CString str;
			str.Format("步骤用时:%.2f s", elapsed);
			pTimeCtrl->SetWindowText(str);
			lastUpdate = elapsed;
		}
		DelayUs(100, pStopFlag);
	}

	// 步骤结束最终刷新时间
	CString strFinal;
	strFinal.Format("步骤用时:%.2f s", elapsed);
	pTimeCtrl->SetWindowText(strFinal);
}

// 核心顺序流程线程
UINT __cdecl CSeqControlDlg::SequenceThread(LPVOID pParam)
{
	CSeqControlDlg *pDlg = (CSeqControlDlg*)pParam;
	g_StopFlag = 0;

	CString str;
	double tPress, tHold, tBalance, tTest, tExhaust;

	// 读取界面设置的各阶段时长
	pDlg->m_EditPress.GetWindowText(str); tPress = atof(str);
	pDlg->m_EditHold.GetWindowText(str);  tHold = atof(str);
	pDlg->m_EditBalance.GetWindowText(str); tBalance = atof(str);
	pDlg->m_EditTest.GetWindowText(str); tTest = atof(str);
	pDlg->m_EditExhaust.GetWindowText(str); tExhaust = atof(str);

	// ==========1.加压阶段:夹紧1、进气1、平衡1、排气0==========
	pDlg->m_Status.SetWindowText("状态:正在加压...");
	pDlg->UpdateValveDisplay(true, true, true, false);
	pDlg->Delay_001Sec(tPress, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========2.保持阶段:夹紧1、进气1、平衡1、排气0==========
	pDlg->m_Status.SetWindowText("状态:压力保持中...");
	pDlg->UpdateValveDisplay(true, true, true, false);
	pDlg->Delay_001Sec(tHold, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========3.平衡阶段:夹紧1、进气0、平衡1、排气0==========
	pDlg->m_Status.SetWindowText("状态:压力平衡中...");
	pDlg->UpdateValveDisplay(true, false, true, false);
	pDlg->Delay_001Sec(tBalance, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========4.检测阶段:夹紧1、进气0、平衡0、排气0==========
	pDlg->m_Status.SetWindowText("状态:数据检测中...");
	pDlg->UpdateValveDisplay(true, false, false, false);
	pDlg->Delay_001Sec(tTest, &g_StopFlag, &pDlg->m_StepTime);
	if(g_StopFlag) {
		pDlg->UpdateValveDisplay(false, false, false, false);
		pDlg->m_StepTime.SetWindowText("步骤用时:已停止");
		pDlg->m_Status.SetWindowText("状态:已手动停止");
		return 0;
	}

	// ==========5.排气阶段:夹紧1、进气0、平衡1、排气1==========
	pDlg->m_Status.SetWindowText("状态:排气泄压中...");
	pDlg->UpdateValveDisplay(true, false, true, true);
	pDlg->Delay_001Sec(tExhaust, &g_StopFlag, &pDlg->m_StepTime);

	// 排气全部结束:所有阀门复位关闭
	pDlg->UpdateValveDisplay(false, false, false, false);
	pDlg->m_StepTime.SetWindowText("步骤用时:完成");
	pDlg->m_Status.SetWindowText("状态:流程全部完成!");
	return 0;
}

// 启动按钮响应
void CSeqControlDlg::OnBtnStart()
{
	AfxBeginThread(SequenceThread, this);
}

// 停止按钮响应:所有阀门立即复位关闭
void CSeqControlDlg::OnBtnStop()
{
	g_StopFlag = 1;
	UpdateValveDisplay(false, false, false, false);
	m_Status.SetWindowText("状态:正在停止...");
}
相关推荐
j_xxx404_1 小时前
Linux线程池硬核解析:从固定线程池、单例线程池到线程安全、死锁与锁模型|附源码
linux·运维·服务器·c++·安全·ai
牛油果子哥q1 小时前
【C++静态成员】C++静态成员终极精讲:静态成员变量、静态成员函数、内存布局、对象共享机制、工程实战、深浅坑点与面试满分总结
c++·面试
晚风吹红霞1 小时前
深入剖析二叉搜索树:从原理到实现,从单key到key/value模型
c++
我是一颗柠檬1 小时前
C++最全面复习:从入门到精通(2026年)
开发语言·c++·visualstudio
lilili也1 小时前
C++:lamda表达式
c++
坚果派·白晓明1 小时前
[鸿蒙PC三方库移植适配] 使用 AtomCode + Skills 自动完成libhv鸿蒙化适配
c++·华为·ai编程·harmonyos·atomcode
2301_789015621 小时前
Linux基础开发工具一:软件包管理器、vim编辑器
linux·服务器·c语言·汇编·c++·编辑器·vim
玖玥拾1 小时前
C/C++ 基础笔记(十)
c语言·c++
Frank学习路上1 小时前
【C++】面试:指针与引用
c++·面试