티스토리 뷰

Visual Studio 2012 사용


시리얼 통신을 해보자.


시리얼 관련 클래스를 만들고 통신 연결까지만 다뤄보도록 하자.

WINAPI 계열의 함수들을 사용할 예정이다.


Serial 통신을 하기 위해서 CreateFile() 함수를 사용한다. Serial을 하는데 파일이란 개념이 생소하긴 하지만, 리눅스나 윈도우에서는 Serial도 하나의 파일로 간주하여 관리하기 때문에 위의 함수를 사용할 수 있다. 커스텀 함수를 제외하고 사용할 함수는 CreateFile(), SetCommTimeouts(), SetCommState(), GetCommState()이다.


사용할 함수에 대해 알아보자.


1. 함수원형


(1) CreateFile() - Serial Device 핸들을 얻는다.

HANDLE CreateFileA(
  LPCSTR                lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

파라미터:

lpFileName

생성할 디바이스의 이름을 입력한다. 여기서는 \\.\COM포트번호를 입력한다

* 그냥 COM을 적어도되는 경우는 COM1~9번까지만 가능하다. COM10이상 부터는 위의 형식대로 적어야 제대로 인식 된다. (참고: 마소홈피)

dwDesiredAccess

허가 요청 관련 내용이다. GENERIC_READ | GENERIC_WRITE 사용한다.

dwShareMode

공유 모드이다. 여기서는 0을 사용한다.

lpSecurityAttributes

SECURITY_ATTRIBUTES 구조체 포인터. NULL을 사용한다.

dwCreationDisposition

파일이나 디바이스가 존재 하거나 존재 하지 않을 경우에 사용하는 액션이다. 우리는 디바이스를 사용하기 때문에 OPEN_EXISTING을 사용한다.

dwFlagsAndAttributes

파일이나 디바이스의 상태나 플래그 관련 파라미터다. FILE_ATTRIBUTE_NORMAL을 사용한다.

hTemplateFile

NULL을 사용한다.


(2) SetCommTimeouts() - 디바이스의 time-out에 관련된 내용을 설정한다.

BOOL SetCommTimeouts(
  HANDLE         hFile,
  LPCOMMTIMEOUTS lpCommTimeouts
);

파라미터:

hFile

Serial Device Handle이다.

lpCommTimeouts

COMMTIMEOUTS 구조체 포인터이다. (참고: COMMTIMEOUTS)


(3) SetCommState(), GetCommState() - DCB 구조체로 통신 상태를 설정하거나 가져온다. Baudrate 등의 통신 포트 관련 설정을 담당한다.

BOOL SetCommState(
  HANDLE hFile,
  LPDCB  lpDCB
);

BOOL GetCommState(
  HANDLE hFile,
  LPDCB  lpDCB
);

파라미터:

hFile

Serial Device Handle이다.

lpDCB

DCB 구조체 포인터이다. (참고: DCB)


2. 통신 클래스 추가(CSerialCom)

따로 상속 없이 통신 관련 클래스를 만들었다.


SerialCom.h

class CSerialCom
{
public:
	CSerialCom(void);
	~CSerialCom(void);
	HANDLE m_hComm;			//Handle of COM Port
	bool OpenConnection(BYTE nPort, DWORD nBaudrate, BYTE nSize, BYTE nParity, BYTE nStop);
	void CloseConnection(void);
	bool SetDCB(DWORD nBaudrate, BYTE nSize, BYTE nParity, BYTE nStop);
	bool SetTimeouts(void);
};


SerialCom.cpp

#include "SerialCom.h"

//1. 생성자
CSerialCom::CSerialCom(void)	
{
	m_hComm = NULL;
}

//2. 소멸자
CSerialCom::~CSerialCom(void)		
{
	CloseConnection();
}

//3. 통신 연결
bool CSerialCom::OpenConnection(BYTE nPort, DWORD nBaudrate, BYTE nSize, BYTE nParity, BYTE nStop)
{
	//이미 통신이 연결되어 있다면 통신 연결 해제 후 진행
	if(m_hComm != NULL)
		CloseConnection();
	
	//드라이버 핸들 생성
	char			szPort[15];
	wsprintf(szPort, "\\\\.\\COM%d", nPort);
	if((m_hComm = CreateFile(
		szPort,
		GENERIC_READ | GENERIC_WRITE,
		0, 
		NULL, 
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 
		NULL)) == (HANDLE) - 1) return (false);

	//TIME-OUT
	if(!SetTimeouts())
	{
		//Failed to set Comm Timeouts
		CloseHandle(m_hComm);
		return false;
	}

	//DCB Structure
	if (!SetDCB(nBaudrate, nSize, nParity, nStop))
	{
		//Failed to set DCB Structure
		CloseHandle(m_hComm);
		return false;
	}

	return true;
}

//4. 통신 연결 해제
void CSerialCom::CloseConnection(void)
{
	if(m_hComm==NULL)
		return;
	
	CloseHandle(m_hComm);
	m_hComm=NULL;
}

//5. DCB Structure 설정
bool CSerialCom::SetDCB(DWORD nBaudrate, BYTE nSize, BYTE nParity,  BYTE nStop)
{
	DCB dcb;

	dcb.DCBlength = sizeof(DCB);
	if(GetCommState(m_hComm, &dcb)==0)
	{
		//GetCommState Error
		CloseHandle(m_hComm);
		return false;
	}

	dcb.BaudRate = nBaudrate;
	dcb.ByteSize = nSize;
	dcb.Parity = nParity;
	dcb.StopBits = nStop;

	return (SetCommState(m_hComm, &dcb) != 0);	//C4800 해결
}

//6. Timeout 설정
bool CSerialCom::SetTimeouts(void)
{
	COMMTIMEOUTS	CommTimeOuts;	
	CommTimeOuts.ReadIntervalTimeout			= 0xFFFFFFFF;
	CommTimeOuts.ReadTotalTimeoutMultiplier		= 0; 
	CommTimeOuts.ReadTotalTimeoutConstant		= 1000; 
	CommTimeOuts.WriteTotalTimeoutMultiplier	= 0; 
	CommTimeOuts.WriteTotalTimeoutConstant		= 1000;
	return (SetCommTimeouts(m_hComm, &CommTimeOuts) != 0);	//C4800 해결
}

(1) 생성자: 통신 드라이버 핸들을 초기화한다.

(2) 소멸자: 통신 연결 해제 함수를 사용하여 만약 연결 해제가 안되어있다면 해제 후 종료한다.

(3) 통신연결: 통신 연결을 위해 드라이버 핸들 생성, Timeout 설정, DCB Structrue 설정한다.

(4) 통신해제: 통신 드라이버 핸들을 확인하여 연결 상태 검토 후 핸들을 초기화한다.

(5) DCB, Timeout설정: 통신 연결을 위해 사용한다. 모듈화시킴.


3. 실행 클래스

MFC 대화상자 기반 프로젝트를 생성했다. (이름은 CommTest)


(1) 선언

CommTestDlg.h

#pragma once
#include "SerialCom.h"

// CCommTestDlg 대화 상자
class CCommTestDlg : public CDialogEx
{
	//...
public:
	afx_msg void OnBnClickedBtnConnect();
	afx_msg void OnBnClickedBtnDisconnect();
	CSerialCom *m_comm;
	bool m_bSerialConnected;
};


연결과 연결해제 버튼을 2개 만들고, CSerialCom 클래스 포인터 변수와 연결 상태 변수를 추가하였다.


(2) 정의

CommTestDlg.cpp

// CCommTestDlg 메시지 처리기
BOOL CCommTestDlg::OnInitDialog()
{
	//...
	m_bSerialConnected=false;

	if(m_comm==NULL)
		m_comm = new CSerialCom();

	return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}

void CCommTestDlg::OnBnClickedBtnConnect()
{
	if(m_comm->OpenConnection(7,CBR_115200,8,NOPARITY,ONESTOPBIT) == true)
	{
		//Connection Success
		m_bSerialConnected=true;
	}
	else
	{
		//Connection Error
	}
}

void CCommTestDlg::OnBnClickedBtnDisconnect()
{
	m_comm->CloseConnection();
	m_bSerialConnected=false;
}


OnInitDialog() - 각 변수들을 초기화시킨다.

OnBnClickedBtnConnect() - 통신 연결 함수, OpenConnection()함수로 통신을 연결한다.

예제에서는 COM7포트, 115200 Baudrate, 8 Bytesize, No Parity, 1 Stopbit를 사용했다.

OnBnClickedBtnDisconnect() - 통신 연결 해제 함수


소스: CommTest .zip

암호: TripleJ



댓글