IEEE754 단정밀(32Bit) 데이타와 float 형 변수의 상호 변환 - C++

Software/C++ Builder|2025. 3. 17. 16:05
반응형

계측기와 데이타를 주고 받는 경우 계측기에서 측정된 데이타가 ASCii 형태로 들어 오는 경우가 있다. 이럴 경우 데이타의 갯수가 짧은 경우에는 상관이 없지만 데이타 갯수가 수십 ~ 수백개가 될 경우 통신 속도문제로 데이타를 주고 받는데 시간이 많이 걸리게 된다. 

 

더군다나 ASCii 를 사용하게 되면 데이타는 더 길어질 수 밖에 없어서 시간이 더 많이 소요가 된다. 

이럴때 데이타의 길이를 줄이기 위해 계측기가 IEEE754형태의 단정밀로 변환해서 데이타를 주고 받을 수 있는 경우가 있는데 이럴경우 데이타의 길이를 1/3로 줄일 수 있다. (13byte 아스키값을 4byte 로 변형)

 

예 : +7.282600E+01  <-> {0xE9} {0xA6} {0x91} {0x42}

 

변환 방법은 간단하게 Union 사용하면 된다. 

 

union IEEE754_Float
{
    unsigned char uData[4] ;
    float fValue ;
} ;

 

 

IEEE754_Float data ;

data.fValue = 72.826 ;     // float 변수에 값을 넣으면 uData에 각각의 바이트로 자동으로 변환되어 저장

 

IEEE754_Float data ;

data. uData[0] = 0xE9 ;  // 각 바이트에 값을 넣으면 fValue 에 자동으로 변환된 float 값이 저장된다. 

data. uData[1] = 0xA6 ;

data. uData[2] = 0x91 ;

data. uData[3] = 0x42 ;

 

 

 

 

반응형

댓글()

VARIANT 형의 변수를 사용할 때 주의할 점 (C++)

Software/C++ Builder|2025. 3. 11. 15:18
반응형

최근 레이저의 광출력을 측정하는 계측기를 사용하는 과정에서 해당 계측기 업체가 제공하는 소스를 그대로 복사해서 함수를 하나 만들어서 사용을 했습니다. 

 

그런데 이 장비가 번인 장비여서 기본적으로 1000시간 이상 구동을 해야 하는데 200~300 시간 정도 지나면 프로그램이 다운이 되어 버리는 증상이 나타났습니다. 아무리 소스 코드를 봐도 오류를 찾을 수 없었는데 혹시나 해서 계측기 업체가 제공한 소스 코드를 Chat-GPT 에 돌려서 보니 VARIANT 형을 사용하는 과정에서 변수를 Clear 하지 않아서 오버플로우가 발생하는 현상이 있는 것을 찾아 냈습니다. 

아래 함수가 이번에 수정한 부분인데  VARIANT value, param1, param2;  이 세개의 변수가 VARIANT 형으로 선언이 되어 있고 그 중에서 value 변수는 배열 형식으로 데이타를 받아 오도록 되어 있습니다. 

 

VARIANT 변수가 단일 변수형식일 경우에는 상관 없다고 하는데 배열이나 문자열 같이 데이타가 큰 형식으로 변경이 될 경우에는 반드시 변수를 Clear 해주어야만 메모리 오버플로우가 발생하지 않습니다. 

 

아래 함수를 try finally 구문을 이용해서 함수가 마무리되면  VariantClear() 를 이용해서 메모리 해제를 시켜 주었고 이렇게 코드를 수정한 이후에는 프로그램이 다운되지 않고 정상적으로 잘 동작합니다. 

 

C++ builder 에서는 Variant 라는 형으로 VARIANT 형을 사용하는데 빌더에서 만든 Variant 형은 자동으로 메모리 해제가 되도록 프로그램 되어 있어서 사용자가 메모리 해제를 신경쓰지 않아도 됩니다. 

 

bool __fastcall TAging::readPowerData(const int Channel)
{
	VARIANT value, param1, param2;
	int check = -1 ;
	double Power ;
	bool result = true ;

	try
	{
		try
		{
			check = g_PowerMeter->GetData(ChannelInformation[Channel].Handle, 0, &value, &param1, &param2) ;

			if(check != 0) result = false ;
			else
			{
				std::vector<double> PowerData = getDoubles(value) ;

				if(PowerData.size() > 0)
				{
					Power = PowerData[0] ;
					Power = (Power * MachineData.PowerCalibration[Channel][0]) + MachineData.PowerCalibration[Channel][1] ;

					ChannelInformation[Channel].MeasData.Power = Power ;
				}
				else
				{
					result = false ;
				}
			}
		}
		catch(...)
		{
			check = -1 ;
			result = false ;
		}
	}
	__finally
	{
		VariantClear(&value);
		VariantClear(&param1);
		VariantClear(&param2);
	}

	return result ;
}

 

반응형

댓글()

HEX String 을 Integer 값으로 변경하는 방법

Software/C++ Builder|2023. 6. 7. 17:25
반응형

일반적으로 계측장비나 온도컨트롤러의 경우 계측값을 HEX로 표현하여 통신하는 경우가 많습니다.

수신된 데이타의 값이 Hex 문자열로 들어올 때 간단하게 정수값으로 변경하는 방법입니다. 

 

const char *hexstring = "abcdef0";

int number = (int)strtol(hexstring, NULL, 16);   // 16의 의미는 hexstring 이 16진수라는 의미입니다.

 

String 문자열에 0x 의 16진수 기호가 붙어 있을 경우는 아래와 같이 사용합니다. 

 

const char *hexstring = "0xabcdef0";

int number = (int)strtol(hexstring, NULL, 0);

반응형

댓글()

윈도우 강제 Shut Down 시키기

Software/C++ Builder|2023. 6. 7. 17:15
반응형

void __fastcall Windows_ShutDown(void)
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    LUID luid;
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken);
    LookupPrivilegeValue(NULL, "SeShutdownPrivilege", &luid);
    tp.PrivilegeCount = 1 ;
    tp.Privileges[0].Luid = luid ;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ;
    AdjustTokenPrivileges(hToken, false, &tp, 0, NULL, NULL) ;
    ExitWindowsEx(EWX_SHUTDOWN, 0);
}

반응형

댓글()

c++ Builder 외부 에디터 연결 사용방법

Software/C++ Builder|2023. 3. 31. 23:14
반응형
  1. 표준 에디터(IDE에서 제공하는)이외에, 타사의 프로그래밍 에디터를 사용하는 방법
  2. 메뉴의 Toos | Configure Toos...를 선택
  3. ADD 버튼을 click
  4. 임의의 "Title"을 입력
  5. 프로그램에 사용하는 "Program"을 지정(Browse 참조)
  6. 필요한 경우 "Working dir"를 설정
  7. 실행에 필요한 "Parameters"로 $EDAME 매크로를 선택(Macros button) ($EDAME 매크로는 편집중의 파일명을 인수로 한다.)
  8. Tools | ("Titel"에 입력했던 타이틀)을 선택하면 된다.

 

반응형

댓글()

Excel 설치없이 Excel 파일로 데이타 저장 C++

Software/C++ Builder|2023. 3. 23. 23:27
반응형

계측장비 프로그램을 하다보면 사용자들이 데이타를 엑셀 파일로 저장해 달라는 요구들이 있습니다. 

Excel 파일로 데이타를 저장하기 위해서는 기본적으로 Excel 프로그램이 설치되어 있어야 합니다. 

보통 프로그램은 제작을 해주고 엑셀은 사용자 측에서 설치하도록 요구를 합니다. 하지만 라이센스 문제로 엑셀을 설치하지 않은 경우가 종종 있습니다. 

 

그래서 Excel 프로그램이 설치되어 있지 않아도 Excel  파일로 데이타를 저장할 수 있는 라이브러리가 있어서 예제 프로그램을 올려 놓습니다. 

아래 예제는 C++ Builder 로 만들어져 있습니다. 

Excel_Format.zip
0.15MB

 

관련된 라이브러리 사이트 정보는 아래와 같습니다.

http://www.codeproject.com/Articles/42504/ExcelFormat-Library

반응형

댓글()

일본 Contec 사의 GPIB 카드 제어 클래스 C++

Software/C++ Builder|2023. 3. 23. 10:56
반응형

1. Device :  GP-IB(PCI)FL 

2. 제조사 : 일본 Contec (https://www.contec.com/

3. 국내 판매 : (주)엔씨텍크놀로지(http://www.da-view.com/

4. 사용용도 : GPIB 통신 카드 

5. 제어 클래스 

typedef enum {NONE, CRLF, CR, LF} Delimiters ;
typedef enum {WITHOUT_EOI, WITH_EOI} EOI ;

class TgpibPort
{
private :
protected :
	int FTimeout ;
	virtual void __fastcall setTimeout(const int Timeout) { FTimeout = Timeout ; }  ;
public :
	virtual bool __fastcall Initialize(void) = 0 ;
	virtual int __fastcall gpibPrint(int Address, AnsiString Command) = 0 ;
	virtual int __fastcall gpibInput(int Address, char* Buffer, int* Count) = 0 ;

	__property int Timeout = {read=FTimeout,  write=setTimeout} ;
};


#include "gpibac.h"   // 헤더파일은 드라이버를 설치하면 찾을 수 있습니다. 

class TContecGpib : public TgpibPort
{
private :
	void __fastcall setTimeout(const int Timeout) override final ;
public :
	TContecGpib() ;
	~TContecGpib() ;

	bool __fastcall Initialize(void) override final ;
	int __fastcall gpibSetup(Delimiters delim, EOI eoi) ;
	int __fastcall gpibPrint(int Address, AnsiString Command)  override final ;
	int __fastcall gpibInput(int Address, char* Buffer, int* Count) override final ;
};


TContecGpib::TContecGpib()
{

}
//---------------------------------------------------------------------------
TContecGpib::~TContecGpib()
{
	GpExit();
}
//---------------------------------------------------------------------------
bool __fastcall TContecGpib::Initialize(void)
{
	bool result = false ;
	int		Ifctime ;
	DWORD	Ret, mode ;

	Ret = GpExit();							// Keep off initialize repeat
	Ret = GpIni();							// GP-IB initialize

	if((Ret & 0x00FF) == 0)                 // Check of GpIni
	{
		GpBoardsts(0x0a, &mode);			// Read Master/Slave mode
		if(mode == 0)                       // mode == 0 (master), mode == 1 (slove)
		{
			Ifctime = 1;					// Default
			Ret = GpIfc(Ifctime);           // Interface Clear

			if((Ret & 0x00FF) == 0)         // Check of GpIfc
			{
				Ret = GpRen();              // Sets REN (Remote Enable) to true.
				if((Ret & 0x00FF) == 0) result = true ;          // Check of GpRen
			}
		}
	}

	return result ;
}
//---------------------------------------------------------------------------
void __fastcall TContecGpib::setTimeout(const int Timeout)
{
	DWORD Ret ;

	Ret = GpTimeout(Timeout);      	// Default(10000ms)
	if((Ret & 0x00FF) != 0)
	{
		FTimeout = Timeout ;
    }
}
//---------------------------------------------------------------------------
int __fastcall TContecGpib::gpibSetup(Delimiters Delim, EOI Eoi)
{
	DWORD Ret ;
	int result = 0 ;

	Ret = GpDelim(Delim, Eoi);      	// default delim = 1, Eoi = 1

	if((Ret & 0x00FF) != 0)   result = -1 ;

	return result ;
}
//---------------------------------------------------------------------------
int __fastcall TContecGpib::gpibPrint(int Address, AnsiString Command)
{
	int result = 0, srlen ;
	char* srbuf ;
	DWORD	MyAddr, Cmd[16], Ret;

	Ret = GpBoardsts(0x08, &MyAddr);            // Read MyAddress

	if((Ret & 0x00FF) != 0) result = -1 ;
	else
	{
		try
		{
			Cmd[0] = 2 ;          // Number of talkers and listeners ( = Number of listeners + 1)
			Cmd[1] = MyAddr ;     // Talker address
			Cmd[2] = Address ;    // Listener address

			srlen = Command.Length() ;
			srbuf = new char(srlen + 10) ;

			strcpy(srbuf, Command.c_str()) ;
			Ret = GpTalk(Cmd, srlen, (UCHAR*)srbuf) ;
		}
		__finally
		{
			delete[] srbuf ;
		}

		if(Ret != 0) result = -2 ;
	}

    return result ;
}
//---------------------------------------------------------------------------
int __fastcall TContecGpib::gpibInput(int Address, char* Buffer, int* Count)
{
	int result = 0 ;
	DWORD MyAddr, srlen, Cmd[16], Ret ;

	Ret = GpBoardsts(0x08, &MyAddr);     // Read MyAddress

	if((Ret & 0x00FF) != 0) result = -1 ;
	else
	{
		Cmd[0] = 2;
		Cmd[1] = Address;
		Cmd[2] = MyAddr;

		memset(Buffer, '\0', strlen(Buffer));

		srlen = *Count ;
		Ret = GpListen(Cmd, &srlen, (UCHAR*)Buffer);

		*Count = srlen ;

		if (Ret >= 3) result = -2 ;         // 0,1,2 : Normal completion
	}

	return result ;
}
//---------------------------------------------------------------------------
반응형

댓글()

Gradation 기능 구현 C++

Software/C++ Builder|2023. 3. 23. 10:35
반응형

측정된 데이타를 기반으로 데이타와 데이타 사이의 변화를 그라데이션으로 표현해야 하는 일이 있어서 만들어 본 예제 프로그램 입니다. 

 

1. 테스트 프로그램 구현 : 아래 이미지는 테스트 프로그램을 만들어 놓은 실행결과 입니다. 

gradation 테스트
gradation 테스트 프로그램

  (1) Color 버튼 클릭 : Min(Blue), Max(Red) 값을 기준으로 Value 에 해당하는 값을 색으로 표현합니다. 

  (2) button1  클릭 :  위의 9개 데이타를 기준으로 최대(Red), 최소(Blue)값을 찾고 좌측 이미지 영역에서 표와 동일하게 위치의 값을 할당한 후 중간 영역의 값들을 그라데이션 처리하여 표현하게 됩니다.  

 

  (3) 테스트 프로그램 소스파일 입니다. 

Gradation.zip
0.28MB

  (4) 소스는 C++ Builder 6.0 으로 제작되었습니다. 

반응형

댓글()