RS-485 장비 통신 프로그래밍: Address·Command·CRC·Response 처리하기

RS-485 장비 통신 프로그래밍: Address·Command·CRC·Response 처리하기#

1장 RS-485 프로그래밍은 RS-232와 무엇이 다른가#

RS-232에서는 흔히 PC와 장비 하나가 직접 연결됩니다.

PC
│
│ RS-232
│
Device

반면 RS-485는 하나의 Bus에 여러 장비를 연결하는 구성이 가능합니다.

Controller
    │
────┼──────────────── RS-485 Bus
    │
    ├─ Device 01
    ├─ Device 02
    ├─ Device 03
    └─ Device 04

따라서 프로그램에서도 새로운 문제가 생깁니다.

어느 장비에 보낼 것인가?
→ Address

무슨 작업을 요청할 것인가?
→ Command

응답이 누구에게서 왔는가?
→ Response Address

데이터가 깨지지 않았는가?
→ CRC / Checksum

응답이 없으면 어떻게 할 것인가?
→ Timeout / Retry

즉 RS-485 프로그램은 단순히 byte를 보내고 받는 것을 넘어 여러 장비가 공유하는 통신 회선을 관리하는 프로그램이 됩니다.

2장 RS-485와 장비 Address는 별개의 개념이다#

중요한 점부터 짚어야 합니다.

RS-485 자체가 다음과 같은 Address를 정의하는 것은 아닙니다.

Device 01
Device 02
Device 03

RS-485는 기본적으로 전기적인 통신 방식입니다.

장비 Address와 Command 구조는 그 위에서 사용하는 Protocol이 결정합니다.

예를 들어 제조사 Protocol이:

[Address][Command][Data][CRC]

구조를 사용할 수도 있고,

Modbus RTU라면:

[Server Address][Function Code][Data][CRC]

같은 구조를 사용합니다.

따라서:

RS-485 = Address 기반 Protocol

이라고 이해하면 안 됩니다.

정확하게는:

RS-485 Bus 위에서 사용하는 상위 Protocol이 Address를 정의할 수 있다

가 맞습니다.

3장 가장 먼저 장비 Address를 확인한다#

RS-485 Bus에 다음 세 장비가 있다고 하겠습니다.

Device A
Address 0x01

Device B
Address 0x05

Device C
Address 0x09

Controller가 Address 0x05에 명령을 보내면 해당 Address를 사용하는 장비가 Response하도록 Protocol을 설계할 수 있습니다.

장비 Address 설정 방법은 제품마다 다릅니다.

DIP Switch 방식#

장비에 있는 DIP Switch를 조합해 Address를 지정할 수 있습니다.

예:

SW1  ON
SW2  OFF
SW3  ON
SW4  OFF

Rotary Switch 방식#

숫자 Dial을 돌려 Address를 지정하는 장비도 있습니다.

Software 설정#

전용 관리 프로그램이나 Serial Command를 통해 Address를 설정할 수도 있습니다.

EEPROM·Flash 저장#

설정한 Address를 내부 비휘발성 Memory에 저장하는 장비도 있습니다.

중요한 것은 같은 Bus 안에서 Protocol상 충돌하는 Address를 사용하지 않도록 관리하는 것입니다.

4장 Packet은 Address와 Command를 함께 전달한다#

가상의 장비 Protocol을 하나 만들어보겠습니다.

[Address]
[Command]
[Length]
[Payload]
[CRC]

예:

05 10 01 01 XX XX

의미를 가정하면:

05
→ Device Address

10
→ Command

01
→ Payload Length

01
→ Payload

XX XX
→ CRC

입니다.

프로그램에서는 이 구조를 그대로 byte 배열로 만들어야 합니다.

예를 들어 Java라면:

byte[] packet = {
    0x05,
    0x10,
    0x01,
    0x01,
    0x00,
    0x00
};

C#이라면:

byte[] packet =
{
    0x05,
    0x10,
    0x01,
    0x01,
    0x00,
    0x00
};

마지막 두 byte는 CRC가 들어갈 자리라고 가정합니다.

실제 Packet 구조와 Command 값은 반드시 사용하는 장비의 Protocol 문서를 따라야 합니다.

5장 CRC는 데이터가 깨졌는지 검사한다#

RS-485가 비교적 Noise에 강한 차동 신호 방식을 사용한다고 해서 데이터 오류가 절대로 발생하지 않는 것은 아닙니다.

그래서 상위 Protocol에서 CRC나 Checksum을 사용하는 경우가 많습니다.

예:

TX

05 10 01 01 A1 3C
            └──── CRC

수신 장비는:

수신 Packet
↓
자신이 CRC 계산
↓
Packet의 CRC와 비교

합니다.

일치하면:

Packet 정상

다르면:

Packet 손상 가능성

으로 판단할 수 있습니다.

CRC는 암호화나 인증 기능이 아닙니다.

전송 중 오류를 검출하기 위한 수단입니다.

CRC 알고리즘은 Protocol마다 다르다#

다음을 모두 확인해야 합니다.

Polynomial

Initial Value

Bit Reflection

Final XOR

CRC Byte Order

예를 들어 아래 코드는 흔히 볼 수 있는 CRC-16 계열의 한 형태일 뿐입니다.

public static int crc16(
        byte[] data,
        int offset,
        int length) {

    int crc = 0xFFFF;

    for (int i = offset;
         i < offset + length;
         i++) {

        crc ^= data[i] & 0xFF;

        for (int bit = 0;
             bit < 8;
             bit++) {

            if ((crc & 0x0001) != 0) {
                crc =
                    (crc >> 1) ^ 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }

    return crc & 0xFFFF;
}

이 방식이 자신의 장비 Protocol과 같다고 가정해서는 안 됩니다.

특히 Modbus RTU라면 정해진 CRC-16/Modbus 규칙을 사용하지만 제조사 전용 Protocol은 전혀 다른 방식일 수 있습니다.

6장 Command를 보냈으면 Response까지 연결해서 관리한다#

장비 통신 프로그램에서는 단순히:

Send 완료

를 성공으로 보면 안 됩니다.

올바른 흐름은 다음과 같습니다.

Command 생성
↓
TX
↓
장비 수신
↓
장비 처리
↓
Response 생성
↓
RX
↓
CRC 확인
↓
Address 확인
↓
Command·Status 확인
↓
업무 결과 처리

예를 들어:

TX
05 10 01 01 A1 3C

를 보냈다고 하겠습니다.

Response가:

RX
05 10 01 00 B2 4D

로 돌아왔다면 프로그램은 최소한 다음을 확인해야 합니다.

Address가 0x05인가?

기대한 Command Response인가?

Length가 정상인가?

CRC가 맞는가?

Status가 성공인가?

그 후에야 Application에서 성공 여부를 결정합니다.

7장 RS-485에서는 송신과 수신 방향도 중요하다#

2선식 RS-485는 흔히 Half Duplex로 사용됩니다.

즉 같은 Pair를 이용해 송신과 수신을 번갈아 수행합니다.

Controller
   │
   │ TX
   ▼
Device

Controller
   ▲
   │ RX
   │
Device

동시에 양방향으로 계속 송신하는 구조가 아닙니다.

USB-RS485 Adapter나 Serial Driver가 송수신 방향 전환을 자동으로 처리해주는 경우도 많지만, 일부 환경에서는 방향 제어가 별도로 필요할 수 있습니다.

따라서 프로그램에서 다음을 고려해야 합니다.

TX 시작

TX 완료

송신 Driver 해제

RX 전환

Response 대기

방향 전환 Timing이 잘못되면:

Command 마지막 byte 손실

Response 첫 byte 손실

응답 없음

불완전한 Frame

등이 발생할 수 있습니다.

8장 하나의 Bus에서 여러 장비를 순서대로 Polling할 수 있다#

다음 장비가 있다고 하겠습니다.

Address 01
Temperature Sensor

Address 02
Controller

Address 03
Meter

Address 04
Actuator

Controller는 일정한 순서로 상태를 조회할 수 있습니다.

Address 01 상태 요청
↓
Response

Address 02 상태 요청
↓
Response

Address 03 상태 요청
↓
Response

Address 04 상태 요청
↓
Response

이를 단순 Polling 구조로 만들 수 있습니다.

하지만 장비 수가 늘어나면 다음 문제가 생깁니다.

Polling Cycle 증가

Timeout 누적

느린 장비의 영향

Retry로 인한 전체 지연

Bus 점유 증가

예를 들어 Device 하나를 최대 500ms 기다리고 100대를 순차 조회한다면 최악의 경우 전체 주기가 크게 늘어날 수 있습니다.

따라서 RS-485 Multi-drop 프로그램에서는 개별 장비뿐 아니라 Bus 전체의 Polling Schedule까지 설계해야 합니다.

9장 Timeout과 Retry는 무조건 짧게 설정하는 것이 아니다#

장비에 Command를 보냈지만 Response가 오지 않는다고 하겠습니다.

TX
↓
...
↓
Response 없음

프로그램에는 Timeout이 필요합니다.

하지만 다음처럼:

100ms

를 모든 장비에 적용해서는 안 됩니다.

장비에 따라 정상 처리 시간이 다르기 때문입니다.

예:

상태 조회
50ms

설정 저장
300ms

Calibration
1초 이상

처럼 Command 종류에 따라서도 달라질 수 있습니다.

따라서 Timeout은:

Protocol 규격

Device 최대 처리 시간

Command 종류

Bus 장비 수

Retry 정책

을 기준으로 설정해야 합니다.

Retry도 주의해야 한다#

다음처럼 무조건 재전송하면 문제가 될 수 있습니다.

Command
↓
Timeout
↓
Command 재전송

첫 번째 Command를 장비가 실제로 실행했지만 Response만 유실된 경우라면 같은 동작이 두 번 실행될 수 있기 때문입니다.

특히 물리 동작이나 상태 변경 Command에서는:

Event ID

Sequence Number

Current State 확인

Idempotency

같은 상위 설계가 필요할 수 있습니다.

10장 Receive Buffer와 Packet Parser를 분리한다#

Serial Port에서:

read()

했다고 해서 Packet 하나가 정확히 들어온다는 보장은 없습니다.

예를 들어 Packet:

05 10 01 01 A1 3C

가 다음처럼 들어올 수 있습니다.

첫 번째 Read:

05 10

두 번째 Read:

01 01 A1

세 번째 Read:

3C

따라서 구조는 다음처럼 만드는 것이 좋습니다.

Serial Port
↓
Raw byte
↓
Receive Buffer
↓
Frame Extraction
↓
CRC Validation
↓
Packet Parser
↓
Device Response

Parser는 다음 정보를 확인할 수 있습니다.

Address

Command

Length

Payload

CRC

불완전한 Packet은 Buffer에 남겨두고 다음 수신 데이터를 기다립니다.

11장 Java와 C#에서는 Transport와 Protocol을 분리하자#

처음 프로그램을 만들 때는 다음 코드를 하나의 Class에 몰아넣기 쉽습니다.

Serial Open
Packet 생성
CRC 계산
Send
Read
Response 분석
Retry
업무 처리

하지만 장비가 늘어나면 유지보수가 어려워집니다.

다음처럼 분리하는 것이 좋습니다.

SerialTransport
│
├─ Open
├─ Close
├─ Send
└─ Receive

Rs485BusManager
│
├─ Device Address
├─ Polling
├─ Timeout
└─ Retry

ReceiveBuffer
│
└─ byte 누적

PacketParser
│
├─ Frame 검사
├─ Length 검사
└─ CRC 검사

DeviceProtocol
│
├─ Command 생성
└─ Response 해석

DeviceService
│
└─ 실제 업무 처리

이 구조를 사용하면 Transport가 나중에:

RS-485
↓
TCP Gateway

로 변경되더라도 Device Protocol을 재사용하기 쉬워집니다.

12장 RS-422를 함께 다룰 때는 물리 구조를 구분한다#

RS-422와 RS-485는 둘 다 Differential Signaling을 사용하지만 동일한 기술은 아닙니다.

특히 현장에서 흔히 접하는 구성에서는 RS-422가:

TX+
TX-

RX+
RX-

처럼 송수신 Pair를 분리한 Full Duplex 구조로 사용되는 경우가 많습니다.

반면 2선식 RS-485는:

A
B

Pair를 공유하는 Half Duplex 구성이 흔합니다.

따라서 프로그램에서는 같은 Serial API를 사용하더라도 실제 Adapter와 Driver가:

송수신 방향을 어떻게 제어하는가?

를 확인해야 합니다.

상위 Packet Protocol은 같을 수도 있지만 물리적인 Transport 동작은 다를 수 있습니다.

13장 종단저항·Bias·배선 문제는 코드로 해결할 수 없다#

RS-485 프로그램을 아무리 잘 만들어도 물리 Bus가 잘못되어 있으면 통신은 불안정합니다.

대표적으로 확인해야 할 항목입니다.

항목 확인할 내용
A/B 극성과 제조사 표기 확인
종단저항 Bus 양 끝 구성과 장비 권장값 확인
Bias Idle 상태 기준 전압 유지 방식 확인
Stub 불필요하게 긴 분기 최소화
Ground Common-mode 범위와 현장 접지 설계 확인
Cable 차동 통신에 적합한 Cable 사용
Topology 기본적으로 Bus 구조 중심으로 검토

흔히 120Ω Termination을 이야기하지만 모든 현장에서 무조건 120Ω 두 개라는 공식처럼 적용해서는 안 됩니다.

Cable 특성과 Transceiver, 제조사 권장 구성 등을 확인해야 합니다.

또한 A/B 표기는 제조사마다 반대로 사용되는 사례가 있으므로 이름만 보고 연결하지 말고 Manual을 확인하는 것이 안전합니다.

14장 장애는 TX·RX Hex Log를 기준으로 추적한다#

RS-485 장애 분석에서 가장 중요한 증거 중 하나가 Raw Packet Log입니다.

예:

2026-09-24 15:30:21.112
PORT=COM5
CONFIG=9600-8-N-1

TX
05 10 01 01 A1 3C

2026-09-24 15:30:21.168

RX
05 10 01 00 B2 4D

최소한 다음 정보를 기록하는 것이 좋습니다.

Timestamp

Port

Baud·Parity·Stop

TX / RX

Device Address

Command

Hex Dump

CRC Result

Timeout

Retry Count

Exception

이렇게 하면 다음 상황을 구분할 수 있습니다.

TX 자체가 안 됨

TX는 됐지만 Response 없음

Response가 다른 Address에서 옴

CRC 실패

잘못된 Command Response

Timeout 반복

15장 RS-485 통신 장애를 순서대로 확인한다#

장비 5대 중 Address 03만 응답하지 않는다고 하겠습니다.

1단계 장비 자체#

Power

Address 설정

Firmware

통신 설정

2단계 배선#

A / B

Connector

Cable

Ground

분기

3단계 Bus#

Termination

Bias

Topology

Noise

4단계 Serial 설정#

Baud Rate

Data Bits

Parity

Stop Bits

5단계 Protocol#

Address

Command

Length

CRC

6단계 Application#

Timeout

Retry

Parser

Device State

이 순서로 확인하면:

RS-485가 안 됩니다.

라는 막연한 문제를 구체적인 원인으로 좁힐 수 있습니다.

16장 실습은 물리 동작이 없는 Simulator부터 시작한다#

실제 Actuator나 설비를 움직이는 Command로 처음 테스트하는 것은 피하는 것이 좋습니다.

먼저 Simulator를 구성합니다.

예:

Virtual Bus

Address 01
Simulator

Address 05
Simulator

Address 09
Simulator

그리고 다음 정도부터 검증합니다.

Address 01
→ 상태 조회

Address 05
→ 상태 조회

Address 09
→ 상태 조회

확인 항목:

올바른 Address로 전송되는가?

Response Address가 일치하는가?

CRC가 검증되는가?

Timeout이 동작하는가?

없는 Address에서 Timeout이 발생하는가?

Retry 횟수가 제한되는가?

그 후 Hardware 시험 환경에서 실제 장비의 비위험 조회 Command를 검증하는 순서가 좋습니다.

17장 흔히 하는 잘못된 구현#

RS-485에 Address 기능이 있다고 생각한다#

Address는 RS-485 전기 규격이 아니라 상위 Protocol에서 정의합니다.

Address가 다르면 동시에 송신해도 된다고 생각한다#

같은 Half Duplex Bus에서는 여러 장비가 동시에 송신하면 충돌할 수 있습니다.

Protocol 차원에서 송신 Timing을 관리해야 합니다.

CRC가 맞으면 장비 동작도 성공했다고 생각한다#

CRC는 Packet이 손상되지 않았는지를 검사하는 것입니다.

실제 Command 처리 성공 여부는 Response Status 등을 별도로 확인해야 합니다.

Timeout이 나면 무조건 같은 Command를 재전송한다#

상태 변경 Command는 첫 번째 요청이 실제 실행됐을 가능성이 있으므로 중복 실행을 고려해야 합니다.

A/B 이름만 보고 연결한다#

제조사마다 표기 관례가 다를 수 있으므로 Manual과 실제 Signal 정의를 확인해야 합니다.

종단저항만 추가하면 모든 Noise 문제가 해결된다#

배선 구조, Ground, Cable, Stub, Bias, 주변 Noise Source 등을 함께 확인해야 합니다.

18장 자기 점검#

RS-485의 Address는 누가 정의하는가#

RS-485 자체가 아니라 그 위에서 사용하는 제조사 Protocol이나 Modbus 같은 상위 Protocol이 정의합니다.

하나의 Bus에서 여러 장비를 구분하는 방법은 무엇인가#

상위 Protocol이 제공하는 Device Address나 Identifier를 이용할 수 있습니다.

CRC가 정상이라는 것은 무엇을 의미하는가#

정해진 CRC 규칙 기준으로 수신 데이터에 오류가 발견되지 않았다는 의미이며 실제 장비 동작 성공이나 보안을 보장하는 것은 아닙니다.

Timeout 후 Command를 바로 재전송해도 되는가#

항상 그렇지는 않습니다. 상태 변경 Command라면 첫 요청이 처리됐지만 Response만 유실됐을 가능성을 고려해야 합니다.

RS-485 2선식에서 프로그램이 고려해야 할 추가 요소는 무엇인가#

Half Duplex 송수신 Timing과 Adapter의 Driver 방향 전환 방식 등을 확인해야 할 수 있습니다.

19장 이 글을 마치며#

RS-485 장비 통신 프로그램의 기본 흐름은 다음과 같습니다.

Serial Port Open
↓
Device Address 선택
↓
Command 생성
↓
Payload 구성
↓
CRC 계산
↓
TX
↓
송수신 방향 전환
↓
Response 대기
↓
Receive Buffer
↓
Packet Parser
↓
Address 확인
↓
CRC 검증
↓
Status 확인
↓
업무 처리

특히 다음 다섯 가지를 기억하면 됩니다.

RS-485는 전기적 통신 규격이며 Device Address·Command·Packet 구조는 그 위에서 사용하는 Protocol이 정의합니다.

Multi-drop 환경에서는 어떤 Address에 어떤 Command를 보냈는지 명확하게 관리하고 Response의 Address와 Command도 함께 검증해야 합니다.

CRC는 전송 오류를 검출하는 수단이지 인증이나 실제 장비 동작 성공을 보장하는 기능은 아닙니다.

Half Duplex RS-485에서는 송신과 수신이 같은 Bus를 공유할 수 있으므로 송수신 방향과 Timing을 고려해야 합니다.

Timeout·Retry·CRC·Packet Parser를 아무리 잘 구현해도 A/B 배선·Termination·Bias·Ground·Topology가 잘못되어 있으면 안정적인 통신을 만들 수 없습니다.

결국 RS-485 프로그래밍의 핵심은 단순히 Serial Port에 byte를 보내는 것이 아닙니다.

여러 장비가 하나의 Bus를 공유하는 환경에서 Address·Command·Response를 정확하게 연결하고, 불완전한 byte Stream을 Packet으로 복원하며, Timeout·CRC·Retry와 물리 Bus 상태까지 함께 관리하는 것이 핵심입니다.

이 페이지의 목차