rs485 시리얼 통신 구성 방법 및 주의 사항

2021. 5. 14. 07:20 컴퓨터/프로그래밍

rs485 시리얼 통신 구현 방법 비교

요즘처럼 인터넷 시대에도 산업 현장에서는 rs232와 rs485 시리얼 통신을 많이 사용합니다. 거리가 멀거나 1:N 통신이 필요한 경우 rs485 통신을 사용하는데요, 한 개의 통신 라인에 여러 장치와 통신을 해야 하다 보니 다양한 아이디어가 나오고 구현 방식도 여러 가지입니다. rs485 시리얼 통신에서 프로토콜을 어떻게 구현하며 어떤 점을 주의해야 하는지 알아보겠습니다.

마스터·슬레이브 통신

▲ rs485는 두 가닥의 라인에 여러 개의 장치를 연결하고 통신합니다. 그러므로 규칙을 정하지 않으면 장치 두 대를 연결해도 통신이 안 됩니다. 이를 해결하기 위해서는 누가 먼저 통신 라인에 패킷을 올려놓을지 규칙을 정해야 하는데, 가장 쉬운 방법은 어느 한 장치에 주도권을 주는 것입니다.

rs485에 두 대의 장치를 연결하든, 수십 대를 연결하든 어느 하나의 장치에게만 통신 라인의 사용 권한을 주고, 다른 장치는 권한을 가지고 있는 장치의 요구에 따라 통신 라인을 사용합니다. 구분을 쉽게 하기 위해서 rs485에서는 통신 라인의 사용 권한을 가지고 있는 장치를 마스터(Master)라고 하고 나머지 장치는 마스터에 순종하는 슬레이브(Slave)라고 합니다.

▲ 마스터와 슬레이브가 결정되면 위 그림처럼 통신이 가능합니다. 마스터만 슬레이브로 명령을 전송하는 간단한 방식이지만, 실제로 현장에 사용되며 단순한 스위칭이나 안내 표시 등에 유용합니다. 통신 환경에 따라서 명령이 전달되지 않을 수 있으므로 마스터는 주기적으로 계속해서 전송합니다.

이 방식의 장점은 필요한 곳이 생기면 선을 연결하고 장치를 설치해 주기만 하면 됩니다. 슬레이브에 어떤 설정 없이 같은 통신 라인에 물리기만 하면 작동합니다.

슬레이브 ID의 필요

▲ 마스터·슬레이브 결정 만으로 통신이 가능하지만, 특정 슬레이브를 지정해서 제어할 수 없습니다. 그래서 슬레이브를 구별할 수 있도록 슬레이브 장치마다 고유의(unique) 숫자 번호 ID를 지정하고 이를 슬레이브 ID(Slave ID)라고 합니다.

▲ 또한 서로 약속을 해서 0xffff번처럼 특정 숫자의 ID가 오면 모두가 처리하는 브로드캐스트(BroadCast)를 구현할 수 있습니다. 즉, 특정 슬레이브를 지정해서 명령을 처리하는 유티캐스트(UniCast)와 브로드캐스트를 함께 운영할 수 있습니다.

이 통신 방식도 모든 슬레이브에 명령이 전달되었는지 확신할 수 없으므로 마스터는 같은 명령이라도 주기적으로 계속해서 전송해 주어야 합니다.

슬레이브 상태 확인을 위한 응답

마스터에서 슬레이브 쪽으로 명령을 전송하는 것만으로 처리할 수 있다면 참 좋겠는데, 슬레이브가 제대로 수행했는지 확인이 안 됩니다. 시리얼 통신 특성상 전송 중에 패킷 손상이 발생할 수 있고 지정한 슬레이브 장치가 꺼져 있을 수도 있습니다.

▲ 슬레이브의 작동 결과를 알고 싶다면, 또는 슬레이브에 에러가 발생했는지의 여부를 모니터링해야 한다면 마스터는 슬레이브에게 요청(Request)하고 응답(Response)을 받아야 합니다. 이렇게 묻고 답하는 방식을 폴링(Polling)이라고 하는데 여기서부터 rs485 통신 프로토콜은 어려워지고 복잡해집니다. 폴링 방식에 대해서는 아래에 좀 더 자세히 알아보겠습니다.

응답 후 수행? 수행 후 응답?

▲ 제일 먼저 생각해야 할 것은 마스터의 명령 수신 후 슬레이브의 응답 시기입니다. 슬레이브는 언제 응답하는 것이 좋을까요? 마스터의 명령을 수신하면 바로 응답하고 작업하는 것이 좋을까요? 아니면 마스터가 지시한 내용을 수행한 후에 응답하는 것이 좋을까요? 확실한 것은 마스터의 명령을 수행하고 응답하는 것입니다. 수행 결과를 알려 줄 수 있고요.

▲ 마스터의 명령을 받자마자 응답하는 경우 수행 후에 결과를 마스터에게 독단적으로 보낼 수 없습니다. 장치에 문제가 발생했다고 하더라도 함부로 마스터에게 패킷을 전송하면 다른 장치의 통신을 방해하게 됩니다. 통신 충돌 없이 보냈다고 해도 마스터는 요청한 적이 없으므로 무시할 것입니다. 이런 이유로 마스터는 슬레이브로부터 응답을 받으면 명령이 수행이 되었다고 판단하거나 일정 시간 후에 진행 상태를 요청하여 확인합니다.

▲ 수행 후에 응답하는 것이 확실하고 결과까지 알려 줄 수 있어서 좋습니다만, 슬레이브는 빠르게 처리하고 응답해야 합니다. 수행할 명령이 시간을 끄는 작업이라면 응답을 먼저 하고 수행합니다. 마스터가 통신 패킷 오류로 생각되어 여러 번 다시 요청하는 동안에도 답변하지 못했다면 마스터는 다른 슬레이브와 통신을 시도할 것입니다. 이때 슬레이브가 보낸 패킷은 통신 충돌을 발생할 수 있으며, 충돌 없이 마스터에게 전송되었다고 해도 앞서와 같이 무시될 것입니다.

▲ 응답하려는 찰나에 마스터가 명령을 재전송할 수 있습니다. 그러므로 슬레이브는 작업 수행 후에 응답하기로 했다면 반드시 마스터의 대기 시간(timeout) 내에 작업을 처리하고 응답해야 합니다. 아울러 마스터는 적당한 시간 동안 대기해야 하는데, 이를 위해서는 마스터 개발자와 슬레이브 개발자 간에 정보 교환을 많이 해야 합니다.

이 내용은 매우 중요합니다. 슬레이브가 응답을 소홀히 하면 마스터의 모니터링 화면에는 가끔 에러가 표시되는데 슬레이브 쪽을 확인해 보면 전혀 이상이 없습니다. 마스터가 응답을 제대로 받지 못했을 뿐이지 슬레이브는 처리를 했거든요. 그래서 응답 후에 수행과 수행 후에 응답은 명령에 따라 적절히 선택해야 합니다.

적절한 대기 시간(timeout)은?

▲ 마스터가 슬레이브에 명령을 전송하면 일정 시간을 대기해야 합니다. 또한, 슬레이브는 대기 시간 내에 응답해야 합니다.

▲ 만일 마스터의 응답 대기 시간이 너무 짧거나, 충분히 기다렸는데도 슬레이브가 너무 늦게 응답한다면 정상적으로 처리해도 마스터는 모두 통신 에러로 판단하게 됩니다.

그렇다면 마스터의 적당한 대기시간(timeout)은 어떻게 될까요?

슬레이브가 명령 수신 후 바로 응답하기로 했다면, 마스터가 전송하는 최대 데이터 길이로 적당한 대기 시간(timeout)을 계산할 수 있습니다. 시리얼 포트로 출력을 직접 제어해서 데이터를 하나하나 보낸다면 전송 완료 시점을 알 수 있습니다. 그러나 윈도우나 리눅스 시스템에서 커널에 출력을 맡긴다면 프로그램은 시리얼 포트로 마지막 바이트가 전송된 시간을 정확히 모릅니다. write() 함수가 시리얼 포트로 모두 출력하고 복귀하는 것이 아니라 커널의 버퍼에 넘기고 반환하기 때문이죠.

그러므로 마스터는 wite() 함수를 호출하고 시간을 체크하기 시작할 것입니다. 그렇다면 마스터는 슬레이브가 통신 패킷을 모두 받을 때까지 기다려야 합니다. 마스터의 슬레이브로 전송하는 데이터의 최대 크기가 100바이트라고 한다면, 통신 설정의 bps, data bit size, parity, stop bit 등으로 전송 시간을 계산할 수 있습니다.

예를 들어,

  • 9600bps
  • 8 data bit
  • not parity
  • 1 stop bit

로 설정했다면

100byte의 전송 비트 개수= (2 start bit + 8 data bit + 1 stop bit) * 100byte = 1100bit

시리얼 통신에서는 한 개의 data bit 전송 완료를 알려 주는 stop bit와 함께 전송 시작을 알려주는 start bit가 있습니다. 그리고 이 start bit는 2 bit 고정입니다. 한 개 바이트의 비트 개수로 100byte에 필요한 비트 개수는 1100bit입니다.

9600bps 통신에서 1100bit를 전송하는데 걸리는 시간은?

100byte 전송 시간= 1100 bit / 9600 bps = 0.1145833333 sec = 115msec

100byte 전송에 약 115msec 정도 걸리네요. 그러므로 마스터는 이 시간보다는 좀 더 여유 있게 대기해야 합니다.

만약에 최대 데이터 길이가 1000바이트라면 전송하는데만 1초가 넘게 걸립니다. 이런 계산 없이 대충 500msec로 코딩하면 통신이 널뛰기합니다. 평소에는 이상 없다가도 가끔 에러가 발생하는 것이죠. 디버깅을 위해 여러 가지 명령을 전송해 보았는데, 짧은 길이로만 테스트했다면 절대 버그를 찾지 못합니다.

이런 이유로 최대 전송 길이도 정해야 합니다.

만일 슬레이브가 명령을 처리 후에 응답한다면, 전송에 소요되는 시간에 슬레이브가 처리하는 명령 중 가장 오래 걸리는 시간을 더합니다. 대기 시간이 너무 길면 다음 명령 전송이 늦어질 수 있으므로 처리 시간이 너무 오래 걸리는 명령은 응답을 먼저 하는 것이 좋습니다.

적당한 재시도 횟수는?

이번에는 재시도 횟수입니다. 만일 슬레이브로부터 응답을 받지 못했다면 몇 번을 반복해서 요청하는 것이 효율적일까요? 딱히 몇 번이 좋다고 결정된 횟수는 없습니다. 보통 3회에서 5회를 많이 사용한다고 해도 시스템에 따라서, 현장 상황에 따라서 적당하고 효율적인 숫자를 찾아야 합니다.

▲ 통신 불량에 의한 재요청은 성공할 때까지 하는 것이 좋습니다만, 특정 장치와의 통신이 매우 불량하다면 다음 슬레이브와의 통신이 심하게 지연될 수 있습니다. 특정 장치가 고장 날 수 있고 꺼져 있을 수도 있습니다. 그렇다면 몇 번 재요청하는 것이 좋을까요?

개인적인 생각입니다만, 재요청 횟수는 슬레이브 개수에 따라 정하는 것이 효율적입니다. 마스터 대기시간을 500msec로 결정했습니다. 슬레이브 개수는 10개입니다. 만일 재 시도 횟수를 3회로 했다면, 그리고 모든 슬레이브가 고장이라고 한다면 모든 슬레이브를 확인하는데 걸리는 시간은,

500 msec * 3 loop * 10 slave = 1500 msec = 1.5 초

최악의 상태에서 모든 슬레이브 상태를 확인하는데 1.5초입니다. 만일 고객이 1초 이내를 요구한다면 재 시도 횟수는 2회로 줄입니다. 또는 시스템이 그렇게 빠른 것을 요구하지 않는다면 5회로 늘릴 수 있습니다.

또는 마스터가 모든 슬레이브와 주기적으로 통신하고 같은 데이터라도 계속해서 전송한다면 재요청하지 않는 것이 더 효율적일 수 있습니다. 다음 통신에서 전송하면 되니까요. 재요청이 없으면 다른 슬레이브로 넘어가는 시간이 짧습니다.

rs485 폴링(Polling) 시 주의사항

통신은 폴링(Polling)과 이벤트(Event) 두 가지 방식이 있습니다. 폴링은 요청(Request)을 받으면 응답(Response)하는 방식이라면 이벤트(Event)는 사건이 발생하면 능동적으로 전송합니다. 마스터·슬레이브로 구성한 rs485 통신은 묻고 답하는 폴링 방식을 사용해야 합니다.

필요할 때 전송하는 이벤트 방식이 효율적이겠습니다만, 구현이 매우 까다롭습니다. 이에 비해 폴링 방식은 구현이 쉽지만, 슬레이브가 많아지면 많아질수록 상택 확인과 명령 처리가 늦어지는 단점이 있습니다.

마스터가 슬레이브 ID를 바꾸어 가며 상태를 계속 확인 중에도 특정 슬레이브에 명령을 전송해야 하는데, 언제 전송할까요? 여기에는 두 가지 방법이 있습니다. 하나는 폴링하는 순서에 맞추어서 전달할 명령이 있으면 전송합니다. 두 번째 방법은 전달할 명령을 모두 전송한 후에 상태를 확인하는 폴링으로 돌아갈 수 있습니다.

▲ 폴링 순서에 맞추어 명령을 전송한다면 처리가 늦어질 수 있습니다. 차례를 기다려야 하기 때문인데요, 슬레이브 개수가 많으면서 명령 처리를 빠르게 요구하는 시스템에는 사용하기 어렵습니다.

▲ 반대로 명령 전송에 무조건 우선순위를 둔다면 빠르게 실행할 수 있겠지만, 제어할 일이 계속해서 발생해서 명령을 계속 전송해야 한다면 상태 확인을 못할 수 있습니다. 그러므로 명령 전송 몇 회 후에는 반드시 상태 확인을 하도록 코딩해야 합니다.

두 가지 방식 모두 고심해야 하는 문제가 있습니다. 이벤트 발생으로 마스터가 슬레이브로 전송할 명령이 계속해서 발생하는데 아직 슬레이브로 전송하지 못한 명령이 있다면 버퍼를 만들어서 잘 쌓아 두어야 합니다. 이를 명령 버퍼라고 하겠습니다. 명령 버퍼에 전송할 명령은 계속 쌓이는데 슬레이브와 통신이 원활하지 않다면 결국 넘치고 말 것입니다. 이런 일이 발생하면 아우~ 골치 아픕니다.

슬레이브도 마찬가지입니다. 마스터로부터 명령이 계속 오는데 아직 이전 명령을 처리하지 못하고 있다면 명령 버퍼를 만들고 수신된 명령을 잘 기억해 두어야 합니다. 처리가 너무 더디면 새로 받은 명령을 버리거나 예전 명령을 건너뛰어야 합니다.

심한 경우 명령 버퍼를 크게 잡는 다고 해서 해결되지 않을 수 있습니다. 이런 경우를 대비해서 미리 계획을 세워야 하며 명령 버퍼가 넘치는 것을 막기 위해서 같은 명령이 있는지 찾아서 삭제하거나 대신하는 등의 코딩이 필요합니다.

예를 들어서 습도 제어 명령을 수신했는데, 이전에 받은 습도 제어가 아직 처리 전이라 명령 버퍼에 들어 있다면 그 버퍼 내용을 지우거나 이번에 수신한 습도 값으로 바꾸어 주는 것입니다.

슬레이브 ID? 장치 ID? 디바이스 ID?

때로 슬레이브 ID를 장치 ID·디바이스 ID라고도 하는데, 슬레이브가 장치이니 틀린 말은 아니지만, 장치 ID나 디바이스 ID보다는 슬레이브 ID라고 하는 것이 좋습니다. rs485 통신에서 마스터와 대비하여 슬레이브라고 언급하는 것이 혼란을 줄일 수 있고, 책과 인터넷에 올라온 문서 대부분이 슬레이브 ID로 언급하는 경우가 많습니다.

rs485 통신에서 많이 사용하는 MODBUS 기술 문서에서도 Slave ID라고 언급되어 있는데, MODBUS의 Slave ID를 우리나라 말로는 장치 ID나 디바이스 ID가 아니라 "국번"이라고 합니다. 또한, 슬레이브 중에는 그 밑으로 여러 장치가 물려 있는 각 장치를 제어하는 경우가 있습니다. 이 장치들과 혼돈을 줄이기 위해서도 Slave ID라고 하고, 슬레이브에 물려 있는 장치는 장치 ID 또는 디바이스 ID로 구분한다면 혼란을 주일 수 있습니다.

통신은 다른 개발자와 의견을 많이 나누어야 하는 분야라서 혼자 익숙한 단어보다는 많은 사람이 사용하는 단어를 사용하는 것이 좋습니다.

rs485가 아니더라도 통신에서는 로그는 매우 중요합니다. 로그에 대해서는 자세한 언급을 하지 않겠습니다만, 로그는 넣어도 안 넣어도 기능에 이상이 없으므로 크게 신경을 쓰지 않게 되는데, 데이터를 잘 남겨야 디버깅을 하는데 큰 도움을 받을 수 있습니다.

이상으로 rs485 통신에 대해 알아보았는데요, 어떻습니까? rs485 통신, 쉬울 것 같으면서도 생각할 것이 많지요?

이 댓글을 비밀 댓글로

티스토리 로그인이 풀리면 여기를 클릭하세요.

error: Content is protected !!