Intro
안녕하세요. 이번에는 시리얼 통신에 관한 설명과 간단한 샘플 코드 소개 하겠습니다. 시리얼 통신은 컴퓨터나 다른 장치들 사이에서 데이터를 주고받는 데에 사용되는 일련의 통신 방법입니다. 주로 마이크로컨트롤러, 아두이노, 센서, 모터 등과 같은 장치들을 컴퓨터와 연결하여 데이터를 교환하고 제어하는 데에 많이 사용됩니다.
시리얼 통신 설명
1. 시리얼 통신의 기본 개념
- 시리얼 통신은 비트들이 연속적으로 전송되는 방식으로, 병렬 통신과는 달리 하나의 비트씩 순차적으로 전송됩니다. 데이터를 주고받을 때는 두 장치 간에 공통된 데이터 송수신 (TX/RX) 핀을 사용하며, 주로 UART(Universal Asynchronous Receiver/Transmitter) 프로토콜을 기반으로 합니다.
2. UART 프로토콜
- UART는 가장 일반적으로 사용되는 시리얼 통신 프로토콜 중 하나로, 비동기적으로 데이터를 전송합니다. 비동기적이라는 의미는 클록 신호가 없이 데이터 비트를 전송한다는 것을 의미합니다. UART는 데이터 비트, 정지 비트, 패리티 비트로 구성됩니다.
3. 시리얼 통신의 속도
- 시리얼 통신에서는 속도를 보드레이트(baud rate)라고 부릅니다. 보드레이트는 초당 전송되는 비트의 수를 나타내며, 일반적으로 흔히 사용되는 보드레이트는 9600, 19200, 38400, 115200 등이 있습니다. 속도는 통신하는 장치들 사이에서 동일해야 정상적으로 데이터를 주고받을 수 있습니다.
4. 시리얼 통신의 연결
- 시리얼 통신을 위해 두 장치를 연결할 때는 보통 UART 케이블이나 USB 시리얼 어댑터를 사용합니다. 컴퓨터의 경우 UART를 지원하는 시리얼 포트나 USB를 통해 시리얼 통신을 할 수 있습니다.
5. 시리얼 통신의 사용 예
- 시리얼 통신은 다양한 분야에서 사용됩니다. 예를 들어, 아두이노와 컴퓨터를 연결하여 센서 데이터를 읽거나 제어 신호를 보낼 수 있습니다. 또한, 마이크로컨트롤러를 이용한 로봇 제어, 센서 네트워크 구축, 원격 감시 시스템 등에도 적용될 수 있습니다.
소스 코드(C++)
헤더
#define PORT_COMMUNICATIONSIZE 512
#include<string>
class SerialPort
{
private:
HANDLE m_hComm;
DCB m_dcb;
COMMTIMEOUTS m_CommTimeouts;
bool m_bPortReady;
bool m_bWriteRC;
bool m_bReadRC;
unsigned long m_iBytesWritten;
unsigned long m_iBytesRead;
unsigned long m_dwBytesRead;
public:
SerialPort();
~SerialPort();
bool OpenPort(std::string portname);
bool ClosePort();
bool PortConfigure(unsigned long BaudRate, unsigned char ByteSize, unsigned long fParity, unsigned char Parity, unsigned char StopBits);
bool SetCommunicationTimeouts(unsigned long ReadIntervalTimeout, unsigned long ReadTotalTimeoutMultiplier,
unsigned long ReadTotalTimeoutConstant, unsigned long WriteTotalTimeoutMultiplier,
unsigned long WriteTotalTimeoutConstant);
bool ReadPortRegister(unsigned char* Register);
bool WritePortRegister(unsigned char* Register, int length);
};
본문
#include "SerialPort.h"
SerialPort::SerialPort()
{
m_hComm = NULL;
m_dcb = { 0 };
m_CommTimeouts.ReadIntervalTimeout = 0;
m_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
m_CommTimeouts.ReadTotalTimeoutConstant = 0;
m_CommTimeouts.WriteTotalTimeoutConstant = 0;
m_CommTimeouts.WriteTotalTimeoutConstant = 0;
m_bPortReady = false;
m_bWriteRC = false;
m_bReadRC = false;
m_iBytesWritten = -1;
m_iBytesRead = -1;
m_dwBytesRead = -1;
}
SerialPort::~SerialPort()
{
CloseHandle(m_hComm);
}
bool SerialPort::OpenPort(std::string portname)
{
m_hComm = CreateFileA(portname.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (m_hComm == INVALID_HANDLE_VALUE)
{
//OutputLog::LOG("Simulator - Serial Port Open Fail\n", OutputLog::LogLevel::System);
return false;
}
else
{
//OutputLog::LOG("Simulator - Serial Port Open Sucess\n", OutputLog::LogLevel::System);
return true;
}
}
bool SerialPort::ClosePort()
{
CloseHandle(m_hComm);
m_hComm = NULL;
if (m_hComm == NULL)
{
//OutputLog::LOG("Simulator - Serial Port Close Sucess\n", OutputLog::LogLevel::System);
return true;
}
else
{
//OutputLog::LOG("Simulator - Serial Port Close Fail\n", OutputLog::LogLevel::System);
return false;
}
}
bool SerialPort::PortConfigure(unsigned long BaudRate, unsigned char ByteSize, unsigned long fParity, unsigned char Parity, unsigned char StopBits)
{
if ((m_bPortReady = GetCommState(m_hComm, &m_dcb)) == 0)
return false;
else
{
m_dcb.BaudRate = BaudRate;
m_dcb.ByteSize = ByteSize;
m_dcb.Parity = (unsigned char)fParity;
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_bPortReady = SetCommState(m_hComm, &m_dcb);
if (m_bPortReady == 0)
{
CloseHandle(m_hComm);
return false;
}
}
return true;
}
bool SerialPort::SetCommunicationTimeouts(unsigned long ReadIntervalTimeout, unsigned long ReadTotalTimeoutMultiplier,
unsigned long ReadTotalTimeoutConstant, unsigned long WriteTotalTimeoutMultiplier,
unsigned long WriteTotalTimeoutConstant)
{
if ((m_bPortReady = GetCommTimeouts(m_hComm, &m_CommTimeouts)) == 0)
return false;
else
{
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)
{
CloseHandle(m_hComm);
return false;
}
else
return true;
}
}
bool SerialPort::WritePortRegister(unsigned char* Register, int length)
{
bool bStatus = false;
unsigned long dwBytesWritten = 0;
bStatus = WriteFile(m_hComm, &Register[0], length, &dwBytesWritten, NULL);
return bStatus;
}
bool SerialPort::ReadPortRegister(unsigned char* Register)
{
bool bStatus = false;
unsigned long dwBytesRead;
bStatus = ReadFile(m_hComm, &Register[0], PORT_COMMUNICATIONSIZE, &dwBytesRead, NULL);
return bStatus;
}
위에 코드는 간단한 시리얼 포트 open/close와 read/write를 구현한 부분입니다.
테스트해보려면 main 함수에서 객체 선언해서 사용하시면 됩니다.
마무리
시리얼 통신은 하드웨어와 소프트웨어 측면에서 간단하면서도 다양한 응용 분야에서 활용되는 중요한 통신 방법입니다. 컴퓨터와 다양한 장치들 간의 데이터 교환과 제어에 필수적인 기술이니, 시리얼 통신에 대해 더 알아보고 활용해 보시면 좋을 것 같습니다.
'[C/C++/MFC]' 카테고리의 다른 글
[C++ Visual studio 2019 & Google Test 연동 방법(Unit test)] (2) | 2021.07.17 |
---|---|
[C++ 캡슐화] (0) | 2021.07.04 |
[C++ 다형성, 오버로드 vs 오버라이드] (0) | 2021.05.23 |
[C++ 객체 지향 프로그래밍 특징(상속, 캡슐화, 다형성] (0) | 2021.05.09 |
[C++ 절차지향 프로그래밍 vs 객체지향 프로그래밍] (0) | 2021.05.08 |