[C/C++] 시리얼 통신 (Serial Port)
2009. 10. 26. 10:42 in Programming/C/C++

최근 회사에서 GPS 수신을 위해 Serial 통신 관련 개발을 잠깐 하게되어 포스팅 합니다.
어짜피 GPS가 아니더라도 Serial 통신이란게 어짜피 Com Port 를 통해 Read Write 하는 구조는 같고, 이외에도 써먹을만한데는 많을 것 같아 적어두면 좋겠다 했죠 :)
Serial 통신은 Port의 Open과 Close, 그리고 Read, Write 의 네가지로 모든 것이 이루어집니다. 좀더 깊게 들어간다면 BaudRate, StopBit, Parity 등 알아야 할 것이 많지만, 저는 기본적으로 사용 방법정도만 설명할 생각입니다.
이쪽 전문가가 아니기 때문도 있구요.
아래는 통신을 간단하게 사용하기 위한 클래스입니다.
- SerialPort.h
- class CSerialPort
- {
- public:
- CSerialPort(void);
- virtual ~CSerialPort(void);
- private:
- HANDLE m_hComm;
- DCB m_dcb;
- COMMTIMEOUTS m_CommTimeouts;
- bool m_bPortReady;
- bool m_bWriteRC;
- bool m_bReadRC;
- DWORD m_iBytesWritten;
- DWORD m_iBytesRead;
- DWORD m_dwBytesRead;
- public:
- void ClosePort();
- bool ReadByte(BYTE &resp);
- bool ReadByte(BYTE* &resp, UINT size);
- bool WriteByte(BYTE bybyte);
- bool OpenPort(CString portname);
- bool SetCommunicationTimeouts(DWORD ReadIntervalTimeout,
- DWORD ReadTotalTimeoutMultiplier, DWORD ReadTotalTimeoutConstant,
- DWORD WriteTotalTimeoutMultiplier,DWORD WriteTotalTimeoutConstant);
- bool ConfigurePort(DWORD BaudRate, BYTE ByteSize, DWORD fParity,
- BYTE Parity,BYTE StopBits);
- }
- SerialPort.cpp
- #include "SerialPort.h"
- CSerialPort::CSerialPort()
- {
- }
- CSerialPort::~CSerialPort()
- {
- }
- bool CSerialPort::OpenPort(CString portname)
- {
- m_hComm = CreateFile(L"//./" + portname,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- 0,
- OPEN_EXISTING,
- 0,
- 0);
- if(m_hComm == INVALID_HANDLE_VALUE)
- {
- return false;
- }
- else
- return true;
- }
- bool CSerialPort::ConfigurePort(DWORD BaudRate, BYTE ByteSize, DWORD fParity,
- BYTE Parity, BYTE StopBits)
- {
- if((m_bPortReady = GetCommState(m_hComm, &m_dcb))==0)
- {
- MessageBox(L"GetCommState Error", L"Error", MB_OK + MB_ICONERROR);
- CloseHandle(m_hComm);
- return false;
- }
- m_dcb.BaudRate = BaudRate;
- m_dcb.ByteSize = ByteSize;
- m_dcb.Parity = Parity ;
- m_dcb.StopBits = StopBits;
- m_dcb.fBinary = true;
- m_dcb.fDsrSensitivity = false;
- m_dcb.fParity = fParity;
- m_dcb.fOutX = false;
- m_dcb.fInX = false;
- m_dcb.fNull = false;
- m_dcb.fAbortOnError = true;
- m_dcb.fOutxCtsFlow = false;
- m_dcb.fOutxDsrFlow = false;
- m_dcb.fDtrControl = DTR_CONTROL_DISABLE;
- m_dcb.fDsrSensitivity = false;
- m_dcb.fRtsControl = RTS_CONTROL_DISABLE;
- m_dcb.fOutxCtsFlow = false;
- m_dcb.fOutxCtsFlow = false;
- m_bPortReady = SetCommState(m_hComm, &m_dcb);
- if(m_bPortReady == 0)
- {
- MessageBox(L"SetCommState Error", L"Error", MB_OK + MB_ICONERROR);
- CloseHandle(m_hComm);
- return false;
- }
- return true;
- }
- bool CSerialPort::SetCommunicationTimeouts(DWORD ReadIntervalTimeout,
- DWORD ReadTotalTimeoutMultiplier, DWORD ReadTotalTimeoutConstant,
- DWORD WriteTotalTimeoutMultiplier, DWORD WriteTotalTimeoutConstant)
- {
- if((m_bPortReady = GetCommTimeouts(m_hComm, &m_CommTimeouts)) == 0)
- return false;
- m_CommTimeouts.ReadIntervalTimeout = ReadIntervalTimeout;
- m_CommTimeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant;
- m_CommTimeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier;
- m_CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant;
- m_CommTimeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier;
- m_bPortReady = SetCommTimeouts(m_hComm, &m_CommTimeouts);
- if(m_bPortReady == 0)
- {
- MessageBox(L"StCommTimeouts function failed",L"Com Port Error",MB_OK+MB_ICONERROR);
- CloseHandle(m_hComm);
- return false;
- }
- return true;
- }
- bool CSerialPort::WriteByte(BYTE bybyte)
- {
- iBytesWritten=0;
- if(WriteFile(m_hComm, &bybyte, 1, &m_iBytesWritten, NULL) == 0)
- return false;
- else
- return true;
- }
- bool CSerialPort::ReadByte(BYTE &resp)
- {
- BYTE rx;
- resp=0;
- DWORD dwBytesTransferred=0;
- if(ReadFile(m_hComm, &rx, 1, &dwBytesTransferred, 0))
- {
- if(dwBytesTransferred == 1)
- {
- resp=rx;
- return true;
- }
- }
- return false;
- }
- bool CSerialPort::ReadByte(BYTE* &resp, UINT size)
- {
- DWORD dwBytesTransferred=0;
- if(ReadFile(m_hComm, resp, size, &dwBytesTransferred, 0))
- {
- if(dwBytesTransferred == size)
- return true;
- }
- return false;
- }
- void CSerialPort::ClosePort()
- {
- CloseHandle(m_hComm);
- return;
- }
생각보다 별거 없습니다. 파일 읽고 쓰는거랑 별반 차이 없고, 단지 실시간으로 Read/Write 하려면 Timer 혹은 Thread 를 통해 작업해주면 되겠습니다.
사용법은 아래와 같이 간단해요~
- // 이것저것 다 생략하고...
- CSerialPort _serial;
- if(_serial.OpenPort(L"COM4")) // 실제 사용될 COM Port 를 넣어야합니다.
- {
- // BaudRate, ByteSize, fParity, Parity, StopBit 정보를 설정해줍니다.
- _serial.ConfigurePort(CBR_9600, 8, FALSE, NOPARITY, ONESTOPBIT);
- // Timeout 설정입니다. 별다른거 없으면 전부 zero 설정해도 되구요.
- _serial.SetCommunicationTimeouts(0, 0, 0, 0, 0);
- // Buffer를 잡고
- BYTE* pByte = new BYTE[512];
- // 읽는데 성공하면 처리하고
- if(_serial.ReadByte(pByte, 512))
- {
- pByte[511] = '\0';
- _insertData(CString(reinterpret_cast<char*>(pByte)));
- }
- // 삭제해주면 되는 간편한 놈이죠... 클래스를 보시면 알겠지만
- // 1byte씩 읽거나 그 이상도 읽을 수 있습니다.
- // Write 해주는 부분도 비슷합니다. 응용해보세요 ~
- delete [] pByte;
- }
- // 다 썼으니 닫아주면 끝~
- _serial.ClosePort();
워낙 시리얼 통신에 대한 글이 많지만 여러모로 찾아다니는것도 골치고, 언제 또 사용할 지도 모르는 일이니 가볍게 포스팅 해봅니다.