MODBUS-RTU 프로토콜 쉽게 이해하기

2021. 6. 2. 06:07 컴퓨터/프로그래밍

MODBUS 프로토콜

이 글은 시리얼 통신을 잘 알고 있지만, MODBUS-RTU를 처음 접하는 분을 위해 저의 경험을 바탕으로 작성했습니다. 시리얼 통신을 꽤 오랫동안 다루었지만, MODBUS-RTU를 처음 접했을 때는 지금껏 사용해 오던 프로토콜하고는 느낌이 달라서 왜 이렇게 생겨 먹은 것인 지부터 이해해야 했습니다.

보통 시리얼 통신은 장비에 맞추어 작성합니다. 장비에 어떤 입출력이 있고 무엇을 제어해야 하는지와 구해야 할 정보에 따라서 프로토콜을 설계합니다. 즉, 장비와 프로젝트에 따라서 프로토콜이 바뀌고 그때마다 프로그램을 수정하거나 새로 작성합니다.

MODBUS Memory Map Table

그러나 MODBUS는 장비가 바뀌어도 프로토콜은 바뀌지 않습니다. 생소한 제품도 MODBUS를 지원한다면 프로토콜 수정 없이 통신이 가능한데, 이유는 사전에 정한 것이 있기 때문입니다. 바로 MODBUS Memory Map입니다.

▲ 장비가 MODBUS를 지원한다면 반드시 위와 같은 형식의 메모리 맵을 갖추어야 합니다. 이전까지의 시리얼 통신은 장비와 직접 통신하는 느낌이라면 MODBUS 통신은 장비 사이에 메모리 맵이 가로막고 있는 것 같습니다. 장비는 자기 상태가 바뀌면 메모리 맵에 미리 지정된 주소의 값을 변경합니다. 외부 프로그램은 장비의 메모리 맵을 읽어서 상태를 확인하고 제어하고 싶다면 기능에 해당하는 주소의 값을 변경합니다. 장비는 계속해서 그 주소 값을 확인해서 시스템에 반영합니다.

▲ MODBUS 통신을 지원하는 장비는 외부에 위와 같은 모드버스 메모리 맵 테이블을 제공합니다. Slot #1번 입력 값이 필요하다면 40001번 레지스터 값을 읽으면 됩니다. 스위치 SW #1이 켜진 것을 알고 싶다면 40006번 레지스터를 읽고 Off하고 싶다면 같은 40006번 레지스터에 제어 값을 쓰기 하면 됩니다.

이와 같이 장비의 기능에 따라서 메모리 맵을 구성 합니다. MODBUS 프로토콜은 단지 장비의 메모리 맵에서 특정 주소의 값을 읽거나 쓰기를 하는 것뿐입니다. 이런 이유로 장비에 따라서 메모리 맵 구성이 다를 뿐 MODBUS 프로토콜은 바뀌지 않습니다.

용도에 따른 코일과 레지스터 영역

▲ MODBUS 메모리 맵을 다시 보면 번호 구역에 따라 코일과 레지스터로 나뉘어 있는데, 이는 MODBUS가 PLC를 대상으로 만들어졌기 때문입니다. 코일은 1 bit의 값과 같고 레지스터는 2byte의 word 값으로 생각할 수 있습니다. 즉, 코일은 On/Off하는 스위치를, 레지스터는 16bit의 입출력 값입니다.

코일과 레지스터에는 각각 읽기·쓰기가 가능한 영역과 읽을 수만있는 영역으로 나뉘며 해당 영역의 코일과 레지스터에 접근하려면 지정된 함수 코드를 사용해야 합니다.

MODBUS 프로토콜을 처음 접했을 때 구역별로 함수 번호가 따로 있는 이유가 의아했습니다. 어차피 읽고 쓰기 작업인데 레지스터 번호만 알면 되지 왜 읽기·쓰기 함수 번호를 코일과 레지스터 영역에 따라서 다르게 지정했을까 하는 것이었습니다. 즉, 읽기 하나·쓰기 하나 정해 놓고 주소를 지정하면 간단하지 않나 하는 것이죠.

그러나 MODBUS는 구역을 확실히 나누고 구역별로 특성을 지키기 위함인지 별도로 함수 번호를 만들었습니다. 그리고 4번 함수에 주소 값을 0을 지정하면 30001번 레지스터 값을 반환합니다. 즉, MODBUS는 레지스터 번호와는 별도로 주소 값을 같습니다.

조금 헷갈리죠? 간단히 말씀드리면 3번·6번·16번 함수는 레지스터 40001번부터 4999번까지 다룹니다. 이렇게 정해져 있기 때문에 40001번 레지스터 값을 읽는 다고 해서 3번 함수에 40001번 주소로 지정하지 않습니다. 3번 함수에 0번 주소로 지정합니다. 레지스터 30001번부터 39999번까지는 4번 함수를 사용하는데, 30001번 레지스터를 읽는다고 4번 함수 30001을 지정하는 것이 아니라 4번 함수 0번 주소로 지정합니다.

다시 말씀드려서 1~9999, 10001~19999, 30001~39999, 40001~49999 구역별로 함수가 지정되어 있어서 첫 번째 레지스터 번호의 주소는 모두 0번이 됩니다. 즉, 모든 함수는 주소의 시작이 0번부터 같아서 각 구역별로 지정한 함수는 다른 구역을 침범할 수 없습니다.

주의할 것은 코일과 레지스터 번호는 1번부터 시작하지만, 프로그래머는 0번부터 시작하는 습관이 있습니다. 그래서 번호는 1번부터 시작하지만, 주소는 0번부터 시작합니다. 그러나 주소도 1번부터 시작하는 장비가 있습니다. 그러므로 반드시 1번의 주소가 0이라고 판단하지 말고 장비에서 제공하는 모드버스 메모리 맵 테이블을 확인해야 합니다.

 

MODBUS 프로토콜 기본 구성

MODBUS 프로토콜의 기본 구성은 어떤 슬레이브와 통신하는지 정하는 국번, 함수 번호, 레지스터의 주소, 필요한 데이터로 구성되어 있습니다.

▲ 위의 패킷은 아래와 같이 요구하는 내용입니다.

  • 01: 슬레이브 1번에게
  • 04 : 4번 함수를 이용하여 30001~39999사이에 있는 레지스터 중
  • 00 0A : 10번 주소부터
  • 00 01 : 1개 레지스터(즉, 10번 주소 레지스터 값만) 값을 요구

마스터의 요구에 따라 응답하는 프로토콜도 결정되어 있습니다.

▲ 위는 마스터의 요구에 따라 아래와 같이 응답한 것입니다.

  • 01: 국번 1번 슬레이브이고
  • 04: 4번 함수에 대한 응답
  • 02: 전송할 데이터 길이는 2 byte(1개의 레지스터 값을 요구했으므로)
  • 12 34 : 데이터 값

이와 같이 MODBUS 통신은 장비에 따라 프로토콜이 바뀌는 것이 아니라 MODBUS 메모리 맵이 장비에 따라 구성되는 것입니다. 그러므로 MODBUS 장비에 대해 몰라도 메모리 맵을 알고 있다면 MODBUS 통신으로 제어할 수 있고 상태 값을 구할 수 있습니다.

▲ 어떻습니까? 이렇게 장비의 MODBUS 메모리 맵을 보니 어떻게 제어하고 상태를 읽을 수 있을지 감이 잡히시죠? 잘 만들어진 장비는 누구나 이해하기 쉽게 모드버스 메모리 맵 테이블을 제공합니다. 잘 정리된 메모리 맵 테이블이 있다면 구구하게 설명하는 수고를 줄일 수 있습니다.

MODBUS 프로토콜 메모리 맵과 함수 정리

이와 같이 MODBUS 프로토콜은 메모리 맵이 중요합니다. 장비 특성을 알고 메모리 맵에서 필요한 내용을 분석하면 이후로 통신 처리하기 편합니다.

▲ MODBUS의 블록별로 정리한 메모리 테이블입니다. 제일 많이 사용한 함수 번호는 3,4,6번이고 자주는 아니지만, 1, 5번을 사용했습니다.

libmodbus 추천

MODBUS-RTU 프로토콜은 단순해서 구현하기 어렵지 않지만, 그래도 주의할 내용이 많아서 직접 코딩하는 것보다는 libmodbus 라이브러리를 사용할 것을 권합니다. 매우 오랫동안 많은 개발자가 사용해서 신뢰할 수 있으며 온라인에 올라온 자료가 많아서 도움을 구하기 쉽습니다.

MODBUS-ASCII와 MODBUS-RTU 차이점

시리얼 통신에서 MODBUS는 두 가지 방식으로 구현할 수 있습니다. MODBUS-ASCII와 MODBUS-RTU인데요, MODBUS-ASCII는 이름에서 알 수 있듯이 개행 문자(0x0d 0x0a)를 섞은 아스키 통신입니다. 이에 비해 MODBUS-RTU는 바이너리 통신입니다.

MODBUS-ASCII는 타이핑만으로 제어할 수 있어서 만든 것 같은데, 단 한 번도 사용해 본 적이 없습니다. 구현해 달라는 요청을 받은 적도 없고요.

언급드린 내용 외에 MODBUS를 처음 접하면서 이해가 안 되었던 이상한 점을 정리해서 글을 올렸습니다. 아래 글 내용도 참고하세요.

 

아리송한 MODBUS-RTU 특이점

MODBUS-RTU 왜 이렇게 만들었을까? 통신으로 장비를 제어하는 시스템을 개발한다면 모드버스(MODBUS) 프로토콜이 편한데요, 다뤄야 할 장비가 모드버스를 지원한다면 반가울 정도입니다. 그런데 이

badayak.com

 

MODBUS-RTU 구현 시 주의 사항

MODBUS-RTU 경험담 MODBUS-RTU 프로그램을 작성하면서 겪었던 경험담을 올립니다. 좀 당황스러운 일인데, 경험에 따라 생각이 다를 수 있어서 반드시 이래야 한다는 것은 아니지만, rs485 라인에 MODBUS-RT

badayak.com

 

이 댓글을 비밀 댓글로