Technical Document

기술문서

산업 기술 문서 백과

Modbus 주소 체계 (Coil / Holding Register / Input Register)

요약
Modbus는 데이터를 Coils, Discrete Inputs, Input Registers, Holding Registers의 4가지 기본 데이터 영역으로 구분합니다. 이 중 Coil은 1비트 읽기/쓰기, Input Register는 16비트 읽기 전용, Holding Register는 16비트 읽기/쓰기에 사용됩니다. 현장에서 가장 많이 헷갈리는 부분은 주소 표기 방식입니다. 문서에 적힌 40001, 30001 같은 숫자를 그대로 패킷에 넣는 것이 아니라, 실제 Modbus PDU에서는 기능코드와 0-base 시작 주소를 사용합니다. 즉, 문서의 “40001”은 사람이 보기 위한 참조 표기이고, 실제 통신에서는 보통 시작 주소 0으로 처리됩니다. :contentReference[oaicite:0]{index=0}

산업 현장에서 Modbus 장비를 연동하다 보면 “주소 40001 읽어주세요”, “1번 Coil 제어합니다”, “30005에서 값을 읽습니다” 같은 표현을 자주 보게 됩니다. 그런데 이 숫자들이 모두 같은 의미로 쓰이는 것은 아닙니다. 어떤 숫자는 메모리 영역을 구분하는 참조 번호이고, 어떤 숫자는 실제 프로토콜 프레임에 들어가는 시작 주소입니다. 이 차이를 헷갈리면 통신은 멀쩡한데도 값이 안 읽히는, 아주 얄미운 상황이 생깁니다. :contentReference[oaicite:1]{index=1}


1. Modbus 데이터 영역의 기본 구조

Modbus 애플리케이션 프로토콜은 데이터 모델을 4개의 기본 테이블로 정의합니다. 각 테이블은 데이터 크기와 접근 권한이 다르며, 기능코드도 서로 다르게 연결됩니다. 공식 사양 기준으로 Coils와 Discrete Inputs는 1비트 데이터, Input Registers와 Holding Registers는 16비트 워드 데이터입니다. :contentReference[oaicite:2]{index=2}

영역 데이터 크기 접근 권한 대표 기능코드 일반적 용도
Coil 1 bit Read / Write 01, 05, 15 출력 ON/OFF, 릴레이, 알람 제어
Discrete Input 1 bit Read Only 02 접점 입력, 상태 입력
Input Register 16 bit Read Only 04 센서 측정값, 실시간 아날로그 값
Holding Register 16 bit Read / Write 03, 06, 16 설정값, 파라미터, 제어값

질문 주신 주제 기준으로 보면 핵심은 세 가지입니다. Coil은 디지털 출력 쪽, Input Register는 읽기 전용 측정값 쪽, Holding Register는 설정과 제어 쪽이라고 이해하면 실무에서 가장 빠릅니다. 다만 제조사마다 실제 매핑 방식은 다를 수 있으므로, “온도는 무조건 Input Register”처럼 단정하면 안 되고 반드시 장비 맵 문서를 확인해야 합니다. :contentReference[oaicite:3]{index=3}


2. Coil 이란 무엇인가

Coil은 Modbus 데이터 모델에서 1비트 읽기/쓰기 가능한 영역입니다. 공식 사양에서는 “single bit”이면서 읽기와 쓰기가 가능한 대상으로 정의되며, 일반적으로 디지털 출력 또는 원격 제어용 비트에 매핑됩니다. :contentReference[oaicite:4]{index=4}

예를 들면 다음과 같은 항목이 Coil에 매핑될 수 있습니다.

  • 부저 ON/OFF
  • 릴레이 출력 제어
  • 경광등 작동
  • 알람 리셋 비트
  • 팬 강제 운전

Coil 읽기는 일반적으로 기능코드 01, 단일 Coil 쓰기는 05, 여러 Coil 쓰기는 15를 사용합니다. 즉 “값을 보는 것”과 “값을 바꾸는 것”이 모두 가능하다는 점이 핵심입니다. 현장에서는 이 영역을 디지털 출력 제어 메모리처럼 사용하는 경우가 많습니다. :contentReference[oaicite:5]{index=5}


3. Input Register 란 무엇인가

Input Register는 16비트 읽기 전용 영역입니다. 보통 센서 측정값, 내부 계산값, 현재 상태값처럼 장비가 제공하는 값을 읽는 데 사용합니다. 공식 사양에서는 read-only word 데이터로 정의되며, 대표 기능코드는 04입니다. :contentReference[oaicite:6]{index=6}

실무에서는 다음과 같은 데이터가 Input Register에 자주 들어갑니다.

  • 현재 온도
  • 현재 습도
  • 압력 측정값
  • 전류, 전압, 전력 값
  • 가스 농도 측정값

예를 들어 장비 매뉴얼에 “30001 = Temperature”라고 적혀 있다면, 보통 사람에게 보여주는 참조 표기로는 30001이지만, 실제 Modbus 요청 프레임에서는 기능코드 04와 함께 시작 주소 0을 넣어 읽는 식입니다. 여기서 30001을 그대로 주소 필드에 넣으면 주소가 엇나가 통신이 틀어질 수 있습니다. 이 지점이 Modbus 입문자들의 대표 함정입니다. :contentReference[oaicite:7]{index=7}


4. Holding Register 란 무엇인가

Holding Register는 16비트 읽기/쓰기 가능한 영역입니다. 설정값, 제어값, 목표값, 보정값, 장비 파라미터 같은 항목이 주로 여기에 배치됩니다. 대표 기능코드는 읽기용 03, 단일 쓰기 06, 다중 쓰기 16입니다. :contentReference[oaicite:8]{index=8}

Holding Register에 자주 배치되는 예시는 다음과 같습니다.

  • 온도 알람 상한값
  • 통신 설정값
  • 동작 모드 선택값
  • 보정 계수
  • 제어 목표치(Setpoint)

실무에서는 “현재 측정 온도는 Input Register에서 읽고, 경보 상한 설정은 Holding Register에 쓴다” 같은 구조가 자주 나옵니다. 즉, 하나는 현재 상태를 읽는 창문이고, 다른 하나는 장비 동작을 조정하는 손잡이 같은 느낌입니다. 같은 16비트 데이터라도 읽기 전용인지, 읽기/쓰기인지에 따라 영역이 나뉘는 셈입니다. :contentReference[oaicite:9]{index=9}


5. 주소 표기 방식이 왜 헷갈리는가

Modbus 주소 체계가 어려운 이유는 문서에서 흔히 보이는 0xxxx, 1xxxx, 3xxxx, 4xxxx 표기가 실제 프로토콜 주소 필드와 동일하지 않기 때문입니다. 공식 사양의 데이터 모델은 객체 타입과 주소를 분리해서 설명하며, 실제 PDU에서는 기능코드와 함께 0부터 시작하는 주소(offset)를 사용합니다. :contentReference[oaicite:10]{index=10}

현장에서 흔히 보는 참조 표기 방식은 보통 아래처럼 이해합니다.

참조 표기 의미 실제 시작 주소 예 대표 기능코드
00001 Coil 1번 0 01 / 05 / 15
10001 Discrete Input 1번 0 02
30001 Input Register 1번 0 04
40001 Holding Register 1번 0 03 / 06 / 16

즉 “40001”의 앞자리 4는 메모리 영역이 Holding Register라는 뜻을 사람이 보기 쉽게 붙여놓은 것이지, 주소 필드에 숫자 40001을 그대로 넣으라는 뜻이 아닙니다. 패킷에서는 기능코드 03과 시작 주소 0 조합으로 처리하는 것이 일반적입니다. :contentReference[oaicite:11]{index=11}


6. 0-base 와 1-base 차이

실제 실무에서 가장 많이 터지는 문제는 0-base 주소 체계와 1-base 문서 표기의 충돌입니다. 공식 프로토콜 프레임은 0-base offset을 사용하지만, 제조사 매뉴얼이나 HMI 소프트웨어는 1-base 참조 번호로 표기하는 경우가 많습니다. :contentReference[oaicite:12]{index=12}

예를 들어 아래 두 표현은 실질적으로 같은 위치를 가리킬 수 있습니다.

  • 문서 표기: Holding Register 40001
  • 실제 요청 주소: Function 03, Address 0

그리고 아래도 같은 패턴입니다.

  • 문서 표기: Input Register 30010
  • 실제 요청 주소: Function 04, Address 9

이 때문에 어떤 프로그램에서는 주소 입력란에 “40001”을 넣어야 하고, 어떤 프로그램에서는 “0” 또는 “9”처럼 순수 offset만 넣어야 합니다. 같은 Modbus라도 소프트웨어 UI 철학이 제각각이라, 여기가 참으로 산업현장의 작은 미로입니다. 문서만 믿고 돌진하면 1칸씩 밀려서 데이터가 죄다 다른 방에서 튀어나옵니다. :contentReference[oaicite:13]{index=13}


7. Coil / Input Register / Holding Register 실무 예시

예를 들어 온습도 모니터링 장비가 아래처럼 맵을 제공한다고 가정해보겠습니다.

항목 문서 표기 영역 설명
부저 제어 00001 Coil 1 = ON, 0 = OFF
현재 온도 30001 Input Register 현재 측정값 읽기
현재 습도 30002 Input Register 현재 측정값 읽기
온도 알람 상한 40001 Holding Register 설정값 읽기/쓰기
습도 알람 상한 40002 Holding Register 설정값 읽기/쓰기

이 경우 마스터 장비나 SCADA는 현재 온도와 습도는 기능코드 04로 읽고, 알람 기준은 기능코드 03으로 읽거나 06/16으로 씁니다. 부저를 울리거나 끌 때는 Coil에 쓰기 기능을 사용합니다. 즉, 같은 장비 안에서도 읽기 전용 측정값과 제어용 파라미터가 서로 다른 주소 공간에 나뉘어 존재하는 것입니다. :contentReference[oaicite:14]{index=14}


8. 자주 발생하는 실수

Modbus 연동에서 자주 나오는 실수는 생각보다 단순합니다. 하지만 이 단순한 함정이 디버깅 시간을 순식간에 잡아먹습니다.

  • 40001을 주소 필드에 그대로 입력하는 실수
  • Function 03과 04를 혼동하는 실수
  • 0-base / 1-base 차이를 놓치는 실수
  • 16비트 부호/스케일을 고려하지 않는 실수
  • 32비트 데이터의 워드 순서를 확인하지 않는 실수

특히 온도값이 253처럼 읽혔는데 실제 의미는 25.3℃일 수 있고, 두 개의 Holding Register를 합쳐서 32비트 부동소수점으로 해석해야 하는 경우도 많습니다. 즉 주소 체계를 맞췄다고 끝이 아니라, 데이터 형식과 스케일도 함께 확인해야 진짜 값이 보입니다. :contentReference[oaicite:15]{index=15}


9. 실무에서 기억하면 좋은 핵심 정리

Modbus 주소 체계를 빠르게 정리하면 아래처럼 기억하시면 됩니다.

  • Coil = 1비트, 읽기/쓰기, 디지털 출력 제어
  • Input Register = 16비트, 읽기 전용, 측정값
  • Holding Register = 16비트, 읽기/쓰기, 설정값
  • 30001 / 40001은 사람이 보기 위한 참조 표기일 가능성이 큼
  • 실제 통신 프레임은 기능코드 + 0-base 주소로 처리

한 줄로 압축하면 이렇습니다. Modbus에서 중요한 것은 “숫자 자체”보다도 그 숫자가 어느 영역을 의미하는지, 그리고 그 소프트웨어가 참조 번호를 받는지 offset 주소를 받는지 구분하는 것입니다. 이 감각만 잡히면 Modbus 주소 체계는 더 이상 암호문이 아니라, 꽤 질서정연한 사물함 번호표처럼 보이기 시작합니다. :contentReference[oaicite:16]{index=16}


태그 : Modbus, Modbus주소, Coil, HoldingRegister, InputRegister, DiscreteInput, ModbusRTU, ModbusTCP, 레지스터주소, 산업통신