
Modbus 통신 가이드
Modbus 개요
주요 특징
- 단순성: 구현이 간단하고 이해하기 쉽습니다
- 오픈 표준: 로열티 없이 자유롭게 사용 가능합니다
- 안정성: 오류 검출 기능이 내장되어 있습니다
- 광범위한 지원: 다양한 장치와 소프트웨어에서 지원됩니다
Modbus 통신 방식
Master-Slave 구조
Modbus는 Master-Slave 구조를 기반으로 합니다:
| 역할 | 설명 | 동작 |
|---|---|---|
| Master | 통신을 주도하는 장치 | 질의 송신 |
| Slave | Master의 요청에 응답하는 장치 | 응답 송신 |
통신 매체별 분류
Modbus RTU (Remote Terminal Unit)
- 전송 매체: RS-232, RS-485
- 데이터 형식: 바이너리 (8비트)
- 오류 검출: CRC-16
- 특징: 컴팩트하고 효율적입니다
Modbus ASCII
- 전송 매체: RS-232, RS-485
- 데이터 형식: ASCII 문자 (7비트)
- 오류 검출: LRC (Longitudinal Redundancy Check)
- 특징: 사람이 읽기 쉬우나 비효율적입니다
Modbus TCP/IP
- 전송 매체: 이더넷
- 데이터 형식: 바이너리
- 오류 검출: TCP 자체 오류 검출 기능 사용
- 특징: 네트워크 환경에서 사용됩니다
Modbus 데이터 모델
Coils (코일)
| 속성 | 내용 |
|---|---|
| 주소 범위 | 00001 ~ 09999 (또는 0x0000 ~ 0x270E) |
| 데이터 타입 | 1비트 (ON/OFF) |
| 접근 권한 | 읽기/쓰기 가능 |
| 용도 | 디지털 출력 (릴레이, 디지털 출력 포트) |
| 함수 코드 | 01 (읽기), 05 (단일 쓰기), 15 (다중 쓰기) |
Discrete Inputs (이산 입력)
| 속성 | 내용 |
|---|---|
| 주소 범위 | 10001 ~ 19999 (또는 0x0000 ~ 0x270E) |
| 데이터 타입 | 1비트 (ON/OFF) |
| 접근 권한 | 읽기 전용 |
| 용도 | 디지털 입력 (스위치, 센서 상태) |
| 함수 코드 | 02 (읽기) |
Input Registers (입력 레지스터)
| 속성 | 내용 |
|---|---|
| 주소 범위 | 30001 ~ 39999 (또는 0x0000 ~ 0x270E) |
| 데이터 타입 | 16비트 워드 |
| 접근 권한 | 읽기 전용 |
| 용도 | 아날로그 입력 (센서 값, 측정값) |
| 함수 코드 | 04 (읽기) |
Holding Registers (홀딩 레지스터)
| 속성 | 내용 |
|---|---|
| 주소 범위 | 40001 ~ 49999 (또는 0x0000 ~ 0x270E) |
| 데이터 타입 | 16비트 워드 |
| 접근 권한 | 읽기/쓰기 가능 |
| 용도 | 설정값, 제어값 저장 |
| 함수 코드 | 03 (읽기), 06 (단일 쓰기), 16 (다중 쓰기) |
Modbus 프레임 구조
Modbus RTU 프레임
[Slave Address][Function Code][Data][CRC]
1 byte 1 byte N bytes 2 bytes
Modbus ASCII 프레임
[Start]:[Slave Address][Function Code][Data][LRC][End]
1 : 2 bytes 2 bytes N 2 2
Modbus TCP 프레임
[MBAP Header][Function Code][Data]
7 bytes 1 byte N bytes
MBAP Header:
[Transaction ID][Protocol ID][Length][Unit ID]
2 bytes 2 bytes 2 bytes 1 byte
주요 함수 코드
| 함수 코드 | 기능 | 대상 데이터 |
|---|---|---|
| 01 | Read Coils | Coils (읽기) |
| 02 | Read Discrete Inputs | Discrete Inputs (읽기) |
| 03 | Read Holding Registers | Holding Registers (읽기) |
| 04 | Read Input Registers | Input Registers (읽기) |
| 05 | Write Single Coil | Coils (단일 쓰기) |
| 06 | Write Single Register | Holding Registers (단일 쓰기) |
| 15 | Write Multiple Coils | Coils (다중 쓰기) |
| 16 | Write Multiple Registers | Holding Registers (다중 쓰기) |
통신 시퀀스 예시
레지스터 읽기 예시
Master → Slave: [01][03][00 00][00 02][C4 0B]
슬레이브1, 기능03, 주소0000, 개수2, CRC
Slave → Master: [01][03][04][00 0A][00 0B][79 84]
슬레이브1, 기능03, 바이트4, 데이터10, 데이터11, CRC
코일 쓰기 예시
Master → Slave: [01][05][00 00][FF 00][8C 3A]
슬레이브1, 기능05, 주소0000, 값FF00(ON), CRC
Slave → Master: [01][05][00 00][FF 00][8C 3A]
동일한 응답 (확인)
☀️ 태양광 RTU와 Inverter 통신 예시
시스템 구성
물리적 연결 구성
(Master)
(Gateway)
(Slave ID: 1)
(Slave ID: 2)
(Slave ID: 3)
상단: Ethernet/TCP (Modbus TCP)
하단: RS-485 (Modbus RTU)
통신 매체별 역할
| 구간 | 통신 방식 | 프로토콜 | 특징 |
|---|---|---|---|
| RTU ↔ Serial Converter | Ethernet | Modbus TCP | 높은 대역폭, 장거리 전송 |
| Serial Converter ↔ Inverter | RS-485 | Modbus RTU | 멀티드롭, 노이즈 내성 |
Serial Converter 역할
주요 기능
- 프로토콜 변환: Modbus TCP ↔ Modbus RTU
- 물리 계층 변환: Ethernet ↔ RS-485
- 버퍼링: 데이터 임시 저장 및 전송 순서 관리
- 오류 복구: 통신 오류 시 재전송 처리
- 타이밍 관리: RTU 프레임 간격 조정
설정 예시
Serial Converter 설정:
- IP Address: 192.168.1.100
- Port: 502 (Modbus TCP 기본 포트)
- Serial Settings: 9600, 8, N, 1
- Timeout: 1000ms
- Max Connections: 5
Solar-INV-200 데이터 맵 예시
Input Registers (30001~39999)
| 주소 | 설명 | 단위 | 데이터 타입 |
|---|---|---|---|
| 30001 | DC 전압 | V | 16-bit |
| 30002 | DC 전류 | A | 16-bit |
| 30003 | AC 전압 (R상) | V | 16-bit |
| 30004 | AC 전압 (S상) | V | 16-bit |
| 30005 | AC 전압 (T상) | V | 16-bit |
| 30006 | AC 전류 (R상) | A | 16-bit |
| 30007 | AC 전류 (S상) | A | 16-bit |
| 30008 | AC 전류 (T상) | A | 16-bit |
| 30009 | 순시 전력 | kW | 16-bit |
| 30010 | 누적 발전량 (상위) | kWh | 16-bit |
| 30011 | 누적 발전량 (하위) | kWh | 16-bit |
| 30012 | 온도 | °C | 16-bit |
| 30013 | 주파수 | Hz | 16-bit |
Holding Registers (40001~49999)
| 주소 | 설명 | 단위 | 데이터 타입 |
|---|---|---|---|
| 40001 | 출력 제한 설정 | % | 16-bit |
| 40002 | 전력 인자 설정 | - | 16-bit |
| 40003 | 시간 설정 (시) | - | 16-bit |
| 40004 | 시간 설정 (분) | - | 16-bit |
Coils (00001~09999)
| 주소 | 설명 | 동작 |
|---|---|---|
| 00001 | 인버터 시작/정지 | ON: 시작, OFF: 정지 |
| 00002 | 비상 정지 | ON: 비상 정지 활성 |
| 00003 | 리셋 | ON: 알람 리셋 |
Discrete Inputs (10001~19999)
| 주소 | 설명 | 상태 |
|---|---|---|
| 10001 | 인버터 운전 상태 | ON: 운전 중, OFF: 정지 |
| 10002 | 알람 상태 | ON: 알람 발생, OFF: 정상 |
| 10003 | DC 입력 상태 | ON: 정상, OFF: 이상 |
| 10004 | AC 출력 상태 | ON: 정상, OFF: 이상 |
실제 통신 시퀀스 (Solar-INV-200 기준)
PV 스트링 데이터 읽기
RTU → Serial Converter (Modbus TCP)
TCP Header: [Transaction ID: 0001][Protocol: 0000][Length: 0006][Unit ID: 01]
Data: [01][03][75 30][00 10]
└─ 슬레이브1, 기능03(Input Register 읽기), 주소30001, 개수16개
Serial Converter → Solar-INV-200 (Modbus RTU)
[01][03][75 30][00 10][A1 B7]
└─ 슬레이브1, 기능03, 주소30001(DC전압), 개수16개, CRC
Solar-INV-200 → Serial Converter (Modbus RTU)
[01][03][20][12 C0][05 DC][00 F0][00 12][00 F1][00 14][00 F2][00 13][00 00][00 00][00 00][00 00][00 00][00 00][00 00][00 00][B2 A1]
└─ 슬레이브1, 기능03, 32바이트
DC전압: 4800(480.0V), DC전류: 1500(15.0A)
AC전압(R): 240(240V), AC전류(R): 18(1.8A)
AC전압(S): 241(241V), AC전류(S): 20(2.0A)
AC전압(T): 242(242V), AC전류(T): 19(1.9A)
인버터 상태 및 알람 정보 읽기
RTU → Serial Converter (Modbus TCP)
TCP Header: [Transaction ID: 0002][Protocol: 0000][Length: 0006][Unit ID: 01]
Data: [01][02][27 10][00 04]
└─ 슬레이브1, 기능02(Discrete Input 읽기), 주소10001, 개수4개
Solar-INV-200 → Serial Converter (Modbus RTU)
[01][02][01][0D][A1 F8]
└─ 슬레이브1, 기능02, 1바이트
비트맵: 1101 (운전중, 알람발생, DC정상, AC이상)
출력 제한 설정
RTU → Serial Converter (Modbus TCP)
TCP Header: [Transaction ID: 0003][Protocol: 0000][Length: 0006][Unit ID: 01]
Data: [01][06][9C 40][00 50]
└─ 슬레이브1, 기능06(Single Register 쓰기), 주소40001, 값80(%)
Serial Converter → Solar-INV-200 (Modbus RTU)
[01][06][9C 40][00 50][88 B4]
└─ 슬레이브1, 기능06, 주소40001, 값80, CRC
Solar-INV-200 → Serial Converter (Modbus RTU)
[01][06][9C 40][00 50][88 B4]
└─ 동일한 응답 (설정 완료 확인)
비상 정지 명령 (브로드캐스트)
RTU → Serial Converter (Modbus TCP)
TCP Header: [Transaction ID: 0004][Protocol: 0000][Length: 0006][Unit ID: 00]
Data: [00][05][00 02][FF 00]
└─ 브로드캐스트, 기능05(Coil 쓰기), 주소00002, 값ON
Serial Converter → 모든 Solar-INV-200 (Modbus RTU)
[00][05][00 02][FF 00][2C 3A]
└─ 브로드캐스트는 응답 없음
Serial Converter 내부 처리
데이터 스케일링 처리
전압 데이터 (게인 10)
// 수신된 값: 0x12 0xC0 = 4800
실제전압 = 4800 / 10 = 480.0V (DC 전압)
전류 데이터 (게인 100)
// 수신된 값: 0x05 0xDC = 1500
실제전류 = 1500 / 100 = 15.0A (DC 전류)
전력 데이터 (게인 1000)
// 수신된 값: 0x13 0x88 = 5000
실제전력 = 5000 / 1000 = 5.0kW (순시 전력)
비트 필드 해석
상태 비트 해석
// 수신된 값: 0x0D = 1101b
비트0(운전상태): 1 - 운전 중
비트1(알람상태): 0 - 정상
비트2(DC입력상태): 1 - 정상
비트3(AC출력상태): 1 - 정상
실제 운영 시나리오
RTU가 1분마다 PV 스트링 데이터를 수집하고, 10초마다 AC 출력 데이터를 수집합니다. 5초마다 알람 상태를 확인하여 이상 감지 시 즉시 상세 정보를 요청합니다.
계통 요청으로 출력을 80%로 제한이 필요할 때, RTU가 40001번 레지스터에 80을 설정하고 인버터의 설정 확인 응답 후 실제 출력 전력을 모니터링합니다.
심각한 알람 감지 시 RTU가 즉시 비상 정지 명령을 브로드캐스트하여 모든 인버터를 안전 정지시키고, 상태 확인 및 로그를 기록합니다.
오류 처리
예외 응답
오류 발생 시 슬레이브는 예외 응답을 보냅니다:
[Slave Address][Function Code + 0x80][Exception Code][CRC]
주요 예외 코드
| 코드 | 설명 |
|---|---|
| 01 | 불법 기능 코드 |
| 02 | 불법 데이터 주소 |
| 03 | 불법 데이터 값 |
| 04 | 슬레이브 장치 오류 |
| 06 | 슬레이브 장치 사용 중 |
구현 시 고려사항
타이밍
- RTU: 문자 간 타임아웃 (1.5문자 시간)
- RTU: 프레임 간 타임아웃 (3.5문자 시간)
- ASCII: 문자 간 타임아웃 (1초)
주소 체계
- PDU 주소: 0부터 시작 (프로토콜 내부)
- 데이터 모델 주소: 1부터 시작 (사용자 참조)
- 실제 구현 시 주소 변환이 필요합니다
바이트 순서
- Modbus는 Big-Endian 순서를 사용합니다
- 16비트 데이터: 상위 바이트 먼저 전송
- 32비트 데이터: 구현에 따라 다름 (표준 미정의)
활용 사례
산업 자동화
- PLC와 HMI 간 통신
- 센서 데이터 수집
- 액추에이터 제어
건물 자동화
- HVAC 시스템 제어
- 조명 제어
- 보안 시스템 연동
에너지 관리
- 전력 미터 데이터 수집
- 태양광 인버터 모니터링
- 배터리 관리 시스템
장단점
- 구현이 간단하고 비용 효율적입니다
- 광범위한 하드웨어 지원을 받습니다
- 안정적이고 신뢰할 수 있습니다
- 오픈 표준으로 호환성이 우수합니다
- 상대적으로 낮은 데이터 전송 속도를 가집니다
- 제한된 보안 기능을 제공합니다
- Master-Slave 구조의 한계가 있습니다
- 실시간 통신에는 부적합합니다
결론
Modbus는 단순하면서도 강력한 통신 프로토콜로, 산업 자동화 분야에서 널리 사용되고 있습니다. 코일과 레지스터를 통한 명확한 데이터 모델과 다양한 통신 매체 지원으로 인해 다양한 애플리케이션에 적용할 수 있습니다. 특히 태양광 시스템에서는 RTU와 Inverter 간의 안정적인 데이터 수집과 제어를 위한 핵심 기술로 활용되고 있습니다.
새로운 기술들이 등장하고 있지만, Modbus의 단순성과 안정성은 여전히 많은 산업 현장에서 선택받는 이유입니다.
'je개발 복습 > ETC' 카테고리의 다른 글
| [ html2canvas, jsPdf ] 웹 화면을 PDF 로 다운받는 작업 후기와 숙제 (0) | 2025.11.25 |
|---|---|
| [ 네트워크 관리사 ] CIDR 표기법 (0) | 2025.08.03 |
| [ Tanstack Query ] staleTime / gcTime 설정 방식 (1) | 2025.07.29 |
| [ Linux ] Shell 날짜 조회하기 (0) | 2023.01.15 |
| [ Linux ] 크론탭(Crontab), Shell 로 정기적인 명령어 (0) | 2023.01.15 |