본 문서는
1. 바이너리(Binary) 데이터 타입과 텍스트(Text) 데이터 타입의 차이
2. 데이터 전송을 위한 변환 과정
3. 485통신 모드버스 예제 소스 코드
4. Encoding과 Decoding 구현 예제(SmartSerialPort 사용)
순서로 진행합니다.
다양한 통신 환경에서 데이터 송신 시 데이터를 전송하기 전에 데이터의 인코딩(원데이터→바이트 배열)이 필요하며 데이터 수신 시 수신한 데이터를 원본 데이터로 되돌리는 처리인 디코딩(바이트 배열→원데이터)이 필요합니다. 데이터 인코딩/디코딩 방식에 따라 데이터 타입이 Binary 데이터 타입 또는 Text 데이터 타입으로 나뉩니다.
바이너리(Binary) 데이터 타입 | 텍스트(Text) 데이터 타입 |
---|---|
Binary 데이터 타입은 데이터를 이진화하여 전송하며 Text 타입에 비해 훨씬 적은 공간을 차지하고, 인코딩/디코딩 속도가 빠릅니다. 하지만 이진 데이터이므로 가독성이 떨어지고 관리 및 디버깅이 어렵습니다. | Text 데이터 타입은 데이터를 ASCII, Unicode 등의 Text로 처리하여 전송하는 방식으로 인간이 이해할 수 있는 언어를 사용하기 때문에 가독성이 높고 관리 및 디버깅이 쉽습니다. 하지만 Binary 타입에 비해 많은 공간을 요구하고 인코딩/디코딩 속도가 느립니다. |
예를 들어 32비트 부동 소수점값 IEEE754 형식의 데이터 0x40490FDB를 전송하려면, Binary 데이터 타입의 경우 4바이트의 크기지만 Text 데이터 타입의 경우 3.1415927를 전송해야 하므로 ASCII의 경우 9바이트 크기가 됩니다.(Unicode의 경우 18Byte)
2. 데이터 전송을 위한 변환 과정
일반적으로 데이터를 전송하기 위해 Binary화하여 처리하게 됩니다. 아래는 Binary Data의 인코딩 및 디코딩 처리에 관한 설명입니다.
[표] 송/수신 데이터의 프레임 구조 예시
Encoding | Decoding | |
---|---|---|
수치 데이터 |
수치 데이터를 Encoding하기 위해서 BitConverter 클래스를 이용하여 데이터 포맷에 따라 쉽게 변환할 수 있습니다. | 수치 데이터를 Decoding하기 위해서 BitConverter 클래스를 이용하여 데이터 포맷에 따라 쉽게 변환할 수 있습니다. |
// 수치 데이터 fValue에 float(부동 소수점) 데이터 입력 float fValue = 3.1415927f; // Binary 데이터로 변환 byte[] retBinaryData = BitConverter.GetBytes(fValue); |
// 바이트 배열의 지정된 위치로 반환 후 // float형으로 변환 float fValue1 = BitConverter.ToSingle(retBinaryData, 0); |
|
문자 데이터 |
문자 데이터를 Encoding하기 위해서는 Encoding 클래스를 이용해 문자 인코딩 방식을 선택하여 쉽게 변환할 수 있습니다. | 문자 데이터를 Decoding하기 위해서는 Encoding 클래스를 이용해 문자 인코딩 방식을 선택하여 쉽게 변환할 수 있습니다. |
// String strValue 선언 string strValue; // fValue에 float(부동 소수점) 데이터 입력 fValue = 3.1415927f; // fValue를 String(소수점 포맷)으로 strValue에 저장 strValue = fValue.ToString("0.000000000000000"); // Binary 데이터로 변환 byte[] retTextData = Encoding.Unicode.GetBytes(strValue); |
// 바이트 배열의 지정된 위치로 반환 후 string형으로 변환 string strValue1 = Encoding.Unicode.GetString(retTextData, 0, retTextData.Length); |
|
구조체 데이터 |
구조체 데이터를 Encoding하기 위해서는 BitConverter 클래스(string 이외)와 Encoding 클래스(string)를 이용하면 됩니다. | 구조체 데이터를 Decoding하기 위해서는 BinaryReader reader를 이용하면 됩니다. |
private struct StructureData { public int iA;
}public float fB; public byte byLength; public string sC; private void Form1_Load(object sender, EventArgs e) {
StructureData sd1 = new StructureData();
} sd1.iA = 50; sd1.fB = 77.77777f; sd1.sC = "ABCDE"; // Unicode라서 *2해줌 sd1.byLength = (byte)( sd1.sC.Length * 2); // 전송 데이터(구조체 타입) // "ABCDE"가 Unicode라서 10 더해줌 byte[] byteRAW = new byte[4 + 4 + 1 + 10]; // 디코딩(BYTE[] → 원데이터 변환) // Buffer.BlockCopy는 특정 오프셋에서 시작하는 소스 배열에서 특정 오프셋에서 시작하는 대상 배열로 지정된 바이트 수를 복사 System.Buffer.BlockCopy(BitConverter.GetBytes(sd1.iA), 0, byteRAW, 0, sizeof(int)); System.Buffer.BlockCopy(BitConverter.GetBytes(sd1.fB), 0, byteRAW, sizeof(int), sizeof(float)); // C나 C++의 경우 문자열의 끝을 NULL문자를 확인하여 구분하지만 C#의 경우 문자열의 앞부분에 문자열의 길이를 명시해야 함 // Unicode라서 *2해줌 System.Buffer.BlockCopy(Encoding.Unicode.GetBytes(sd1.sC), 0, byteRAW, sizeof(int) + sizeof(float) + sizeof(byte), (sd1.sC.Length * 2)); |
private struct StructureData { public int iA;
}public float fB; public byte byLength; public string sC; // 인코딩(원데이터 → 바이트 배열 변환). 리턴 타입이 TEST static StructureData ByteToStructure (byte[] data) { StructureData BinaryReader1 = new StructureData ();
}// 기본 데이터 형식을 특정 인코딩의 이진값으로 읽음 using (BinaryReader reader = new BinaryReader (new MemoryStream(data, false), Encoding.Unicode)) { BinaryReader1.iA = reader.ReadInt32();
}// 현재 스트림에서 부호있는 4바이트 정수를 읽기 BinaryReader1.fB = reader.ReadSingle(); // 현재 스트림에서 4바이트 부동 소수점값을 읽기 BinaryReader1.sC = reader.ReadString(); return BinaryReader1; StructureData sd1; sd1= ReadUsingBinaryReader(byteRAW); |
※ 일반 데이터(수치, 문자)와 구조체 데이터는 코딩은 달라도 바이너리 데이터는 동일합니다.
3. 485통신 모드버스 예제 소스 코드(C#)
private void ReadData()
{
if (smartModbus1.IsOpen == true)
{
SmartX. SmartModbus.EXCEPTIONCODE retStatus = SmartX.SmartModbus.EXCEPTIONCODE.SLAVEADDRESS_ERROR;
// 값을 읽어서 저장할 바이트 배열
byte[] ReadData = new byte[4];
// IEEE754로 변환하여 저장할 변수
float retData1= new float();
// SlaveAddress : 01, FunctionCode : 03, StartAddress : 00 2A, DataLength : 00 02
retStatus = smartModbus1.ReadHoldingRegister(100, 2, out ReadData);
// 정상 수신 할때만 변환 실행
if (retStatus == SmartX.SmartModbus.EXCEPTIONCODE.SUCCESS)
{
retData1 = BitConverter.ToSingle(ReadData, 0);
// 라벨에 값 표시
SmartLabel1.Text = retData1.ToString();
else
{
return;
4. Encoding 과 Decoding 구현 예제(SmartSerialPort 사용)
[STEP-1] IEC-Series내의 사용할 포트의 TX와 RX를 결선합니다.
[STEP-2] PortNo(포트 넘버)와 BaudRate(통신 속도), ReadTimeOut과 BufferSize를 지정합니다.
[STEP-3] Open 버튼을 클릭하여 통신 포트를 오픈합니다.
[STEP-4] 전송 데이터를 일반 데이터의 조합 또는 구조체 데이터로 보낼지를 지정합니다.
[STEP-5] 송신 데이터의 수정을 위해 각 Value값을 클릭하면 SmartKeyboard가 Open되고 데이터를 수정 후 X버튼을 클릭합니다.
[STEP-6] Send 버튼을 클릭하여 STEP-5에서 입력한 데이터가 수신 측(하단 SmartListBox)에 정상 표시되는지 확인합니다.
※ 연속으로 10개의 데이터를 전송하려는 경우 Send(Auto)버튼을 클릭합니다.