2021. 1. 10. 14:30ㆍ장비제어개발관한이야기
오늘 포스팅할 내용은 타이머관련한 내용입니다.
장비제어를 하다 보면 실제로 시간개념이 많이 들어갑니다.
- 500ms 동안 실린더를 작동하고 다시 실린더 동작을 원래 대로 돌아가라.
- 3000ms 동안 카메라에서 응답이 없다면 알람을 발생하여라.
- 200ms 후에 모터구동을 시작하여라
꼭 장비제어 뿐만 아니라 알고리즘의 걸리는 시간이 측정 쓰레드의 생성시간 등등 안쓰는데가 많습니다.
간단히는 Sleep(500); 등의 구문으로 대기하는 경우가 많죠. 하지만 장비제어서는 정확한 시간관리가 필요하기 때문에 MFC 개발을 하게 되면 QueryPerformanceFrequency() 를 이용하여 시간을 파악하여 동작을 시킵니다.
다른 분야의 분들도 많이 쓰는 API라 생각됩니다.
매번 WINAPI를 호출해서 사용하는것은 소스도 더럽고 그럴리는 없지만 QueryPerformanceFrequency를 대체해야 된다고 했을경우 랩핑클래스로 구현하는것이 유리하다고 생각해서 하나 작성하였습니다. 주로 많이 쓰는 Case 위주로 랩핑클래스를 구성 해보았습니다.
밑에 소스는 그 랩핑한 클래스 입니다. 윈도우 환경에서는 큰 수정없이 바로 쓸수 있어 파일첨부합니다.
QueryPerformanceFrequency API 하나만을 응용해서 만든 랩핑 클래스로 ms us 100ms 단위로 체크 할수 있는 기능이 특별하다고 하면, 특별한 기능이겠습니다.
한번 보시면 알수 있습니다. 소스코드입니다.
* 헤더파일
// Timer.h: interface for the CTimer class.
//
//////////////////////////////////////////////////////////////////////
#pragma once
class CTimer
{
public:
CTimer();
virtual ~CTimer();
private:
int m_QueryInitialized;
__int64 m_Frequency;
double m_100msFrequency;
double m_msFrequency;
double m_usFrequency;
__int64 m_Begin;
private:
BOOL InitTimer();
public:
void Delay(int time);
void StartTimer() { QueryPerformanceCounter((LARGE_INTEGER *) &m_Begin); }
long Get_secTime();
long Get_usTime();
long Get_msTime();
long Get_100msTime();
BOOL TimeOver(long time);
BOOL TimeOverus(long time);
};
.CPP
// Timer.cpp: implementation of the CTimer class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MFrequencyTimer.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CTimer::CTimer()
{
InitTimer();
}
CTimer::~CTimer()
{
}
BOOL CTimer::InitTimer()
{
m_QueryInitialized = QueryPerformanceFrequency((LARGE_INTEGER*)&m_Frequency);
if(!m_QueryInitialized)
{
m_Frequency = 1;
}
m_100msFrequency = m_Frequency / 10.;
m_msFrequency = m_Frequency / 1000.;
m_usFrequency = m_Frequency / 1000000.;
if(!m_QueryInitialized) return FALSE;
else return TRUE;
}
void CTimer::Delay(int d)
{
QueryPerformanceCounter((LARGE_INTEGER*) &m_Begin);
while(Get_msTime() < d);
}
long CTimer::Get_secTime()
{
__int64 End;
QueryPerformanceCounter((LARGE_INTEGER*) &End);
return (long)((End - m_Begin)/ m_Frequency);
}
long CTimer::Get_usTime()
{
__int64 End;
QueryPerformanceCounter((LARGE_INTEGER*) &End);
return (long)((End - m_Begin)/ m_usFrequency);
}
long CTimer::Get_msTime()
{
__int64 End;
QueryPerformanceCounter((LARGE_INTEGER*) &End);
return (long)((End - m_Begin)/ m_msFrequency);
}
long CTimer::Get_100msTime()
{
__int64 End;
QueryPerformanceCounter((LARGE_INTEGER*) &End);
return (long)((End - m_Begin)/ m_100msFrequency);
}
BOOL CTimer::TimeOver(long time)
{
if(Get_msTime() > time) return TRUE;
else return FALSE;
}
BOOL CTimer::TimeOverus(long time)
{
if(Get_usTime() > time) return TRUE;
else return FALSE;
}
밑에 소스는 실제로 장비개발시에 시간 대기하는 예제 입니다.
BOOL MCommonStageUnit::SetStageVacuum(BOOL bVacuum, int nTimeOut)
{
int ret = SetIOOutPutID(STAGE_OUT_VACUUM_ON,bVacuum);
if(ret) return ret;
BOOL b = FALSE;
if(nTimeOut < 0 ) return TRUE;
CTimer tm;
tm.StartTimer();
for(;;)
{
b = IsStageDetectVacuum();
if(bVacuum)
{
if(b) break;
}
else
{
if(!b){
b = TRUE;
break;
}
}
if(tm.TimeOver(nTimeOut)) return FALSE;
Sleep(1);
}
BOOL bCheck = GetIOOutPutOnOff(STAGE_OUT_VACUUM_ON);
if(bCheck != bVacuum) return FALSE;
return b;
}
위에 함수는 스테이지 구동에 필요한 기능중 하나로서 진공을 형성한후 실제로 nTimeOut 안에 진공센서의 일정량의 진공 상태를 형성 되었는지 체크하는 함수 입니다.
StartTimer(); 로 시작을 시키고 시작 TimeOver로 시간경과를 체크하고 있습니다. 그리 복잡한 소스는 아니기 때문에 활용하는데 문제는 각자 만들어서 잘 썼으면 합니다.
나머지 활용은 금방 파악하실거라 생각됩니다. 그럼 오늘도 즐거운 프로그래밍 하세요.
'장비제어개발관한이야기' 카테고리의 다른 글
간단한 장비제어를 위한 시리얼 통신(C++/MFC) (3) | 2021.01.07 |
---|---|
[UTIL] Beyond Compare 없으면 안됩니다. (1) | 2021.01.07 |
Bayer 변환과 카메라 제어 (0) | 2021.01.06 |
장비제어에서 소켓통신이 필요한 순간... (1) | 2021.01.06 |
심플하고 강력한 MFC,C++ 용 XML 파서(CMarkup) (0) | 2021.01.05 |