차동 신호로 장거리·다중 노드 통신을 하는 전기 규격. 산업 현장의 사실상 표준이다.
RS-232와의 비교
| RS-232 | RS-485 | |
|---|---|---|
| 신호 방식 | 단극성(GND 기준) | 차동(A/B 두 선) |
| 노드 수 | 1:1 | 최대 32개(유닛 부하 기준) |
| 거리 | 15m | 1200m |
| 속도 | 20 kbps | 10 Mbps (거리에 반비례) |
| 노이즈 | 약함 | 매우 강함 |
| 통신 방향 | 전이중 | 반이중(2선) 또는 전이중(4선) |
왜 차동이 노이즈에 강한가
| A선: | 신호 + | 노이즈 |
|---|---|---|
| B선: -신호 + | 노이즈 | ← 두 선이 나란히 있어 같은 노이즈를 받는다 |
수신기는 A - B 를 계산한다 = (신호 + 노이즈) - (-신호 + 노이즈) = 2 × 신호 ← 노이즈가 상쇄되고 신호는 2배
커먼 모드 노이즈가 완전히 제거된다. 트위스티드 페어로 꼬면 두 선이 받는 노이즈가 더욱 같아져 효과가 커진다.
공장의 인버터·모터 옆을 지나는 케이블에서도 통신이 되는 이유다.
반이중 — 방향 전환이 핵심
- 2선식(A/B)은 송신과 수신이 같은 선을 쓴다
- 한 번에 한 노드만 송신할 수 있다
- 방향 전환 신호(DE/RE)로 제어
#define DE_TX() HAL_GPIO_WritePin(DE_PORT, DE_PIN, GPIO_PIN_SET)
#define DE_RX() HAL_GPIO_WritePin(DE_PORT, DE_PIN, GPIO_PIN_RESET)
void send(uint8_t *d, int n) {
DE_TX();
HAL_UART_Transmit(&huart, d, n, TIMEOUT);
while (!(huart.Instance->SR & USART_SR_TC)) { } // ★ 전송 완료 대기
DE_RX();
}
★ 여기가 가장 흔한 버그다. HAL_UART_Transmit이 반환돼도
마지막 바이트가 시프트 레지스터에 남아 있을 수 있다.
TC(Transmission Complete) 플래그를 기다리지 않고 DE를 내리면
마지막 바이트가 잘려 나간다.
증상: "데이터의 마지막 글자가 항상 깨진다" → TC 대기 누락이다.
하드웨어 지원 — 일부 MCU는 USART_CR3.DEM 비트로
DE 신호를 하드웨어가 자동 제어한다. 이것을 쓰면 문제가 사라진다.
프로토콜이 아니라 전기 규격이다
RS-485 는 "전압을 어떻게 표현하는가"만 정의한다 그 위에 어떤 프로토콜을 얹을지는 자유
Modbus RTU, PROFIBUS, DMX512, BACnet MS/TP …
충돌 방지는 상위 프로토콜의 책임이다. CAN처럼 아비트레이션이 없으므로, 두 노드가 동시에 송신하면 데이터가 깨진다. → 대부분 마스터-슬레이브 폴링 방식을 쓴다.
배선 규칙
✅ 데이지 체인 (일직선). 스타(별) 배선 금지 ✅ 양 끝에 120Ω 종단 ✅ 스터브(분기)는 최대한 짧게 ✅ 트위스티드 페어 사용 ✅ GND 도 함께 연결 (또는 절연) ★
★ GND 연결을 빠뜨리는 실수가 흔하다. 차동이라 필요 없어 보이지만, 커먼 모드 전압 범위(-7V ~ +12V) 를 벗어나면 수신기가 동작하지 않는다. 장비 간 접지 전위차가 크면 이 범위를 넘어간다.
접지 루프가 우려되면 절연형 트랜시버를 쓴다.
페일세이프 바이어싱
- 아무도 송신하지 않는 유휴 상태에서 A-B 전압이 0V 근처가 되면
- 수신기 출력이 불확정 → 노이즈를 데이터로 오인 → 프레이밍 에러 폭주
풀업(A선을 VCC로) + 풀다운(B선을 GND로) 저항으로 유휴 시 A > B 를 보장한다 (논리 1 = 유휴)
요즘 트랜시버는 내부 페일세이프를 내장한 것이 많지만, 없는 칩이라면 외부 저항(보통 560Ω~1kΩ)이 필요하다.
유닛 부하
표준 RS-485 수신기 = 1 유닛 부하 → 최대 32개 1/8 유닛 부하 트랜시버 → 최대 256개
노드를 많이 붙이려면 저부하 트랜시버를 골라야 한다.
진단
-
통신 안 됨 — → A/B 반전? 종단? GND? DE 제어? 마지막 바이트 깨짐 → TC 대기 누락
-
간헐적 오류 — → 종단, 페일세이프, 접지 전위차, 케이블 길이 전부 0xFF 또는 0x00 → 유휴 상태 오인 (바이어싱 문제)