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("状态:正在停止...");
}
