본문 바로가기
PLC 전기제어 기술자료/PLC를 함수화 해보자!

[MELSEC] PLC 프로그램을 함수화 해보자 -6- (CRC-16/MODBUS 코드 생성)

by 위치결정 2023. 3. 1.
반응형

< XCALL 을 활용한 CRC-16/MODBUS 코드 생성 함수 예제 >

 

PLC는 손쉽게 그림 그리듯 래더라는 도식화된 독특한 언어체계와 PLC 메이커에서 제공하는 펑션, 명령어들을 이용하여 프로그램 할수 있는 뛰어난 자동화 제어장치입니다.

하지만 단점이 있으니 설비의 규모가 커질수록 같은 동작의 프로세스라고 할지라도 프로그램을 여러 유니트에 맞추어 일일이 어드레스를 변경하거나 복사해가며 번거롭게 코딩을 해주어야 한다는 점입니다.

 

PLC에서도 간단한 기능들은 CALL이나 XCALL 문을 이용하여 반복적으로 사용할수 있는 프로그램을 함수화 할수 있으니 이를 활용하면 보다 프로그램이 간단해 질것입니다.

 

 

이번에는 모드버스RTU 시리얼통신을 할때면 무조건 등장하여 많은 사람들의 골머리를 썩게 만들었던 CRC-16 체크코드를 생성하는 함수를 다뤄봅니다.

 

사실 이미 미츠비시 PLC에서는 Q UDV 타입부터 CRC-16/MODBUS 명령어(CRC)가 신규 추가되어 명령어 펑션을 사용하거나

사전정의프로토콜(Predefined Protocol) 기능에서 제공하는 모드버스 라이브러리를 활용하여도 충분하긴했지만

CRC-16 코드를 꼭 모드버스에서만 사용할수 있는것은 아니기에 XOR 코드가 모드버스전용이아닌 커스텀 할수 있도록 함수화 하였습니다. 모드버스 말고 쓸일이 있을지는 잘 모르겠지만요 :)

 

crc_modbus_230509.gxw
0.96MB

 

< CRC-16 의 이해를 돕는 위키 >

https://ko.wikipedia.org/wiki/%EC%88%9C%ED%99%98_%EC%A4%91%EB%B3%B5_%EA%B2%80%EC%82%AC

 

순환 중복 검사 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 순환 중복 검사(巡環重復檢査), CRC(cyclic redundancy check)는 네트워크 등을 통하여 데이터를 전송할 때 전송된 데이터에 오류가 있는지를 확인하기 위한 체크값을

ko.wikipedia.org

 

 

< 함수 기능 설명 >

이전에 다뤘던 체크섬 코드 생성과 마찮가지로 송수신 데이터 프레임을 다루는 기능이다보니 데이터 레지스터 영역의 소모량이 꽤 많습니다.

따라서 XCALL 에서 기본 사용가능한 인수 (FX, FY, FD) 를 제한적으로 사용할 수 밖에 없습니다.

이를 극복하기 위하여 프로그램의 일부영역을 함수용 영역으로 설정하였습니다.

[ 본 예제 프로그램에서는 통신영역을 D0200번대로 설정하였으며, 함수용 영역을 D0900, ZR0900번대로 사용합니다 ]

함수의 첫번째 파라미터 FD0 : CRC-16 코드 생성시 문자열 참조 시작포인트

함수의 두번째 파라미터 FD1 : CRC-16 코드 생성시 문자열 참조 종료포인트

함수의 세번째 파라미터 FD2 : CRC-16 코드 생성 결과 리턴값

 

ZR0900 : 원본 문자열 (입력값)

D0910 : 문자열을 바이트 캐릭터 단위로 분리 저장영역 (WTOB 버퍼)

D0990 : CRC-16 코드 생성 결과값

 

 

< 사용 예제#1 LS 인버터 G100 모델 RS-485 MODBUS RTU 를 통해 지령주파수 60.00hz 를 쓰는 경우 >

LS 인버터를 예시로 들어봅니다.

1번국 인버터에 1속 주파수(주소 : 0x1D05) 를 60.00hz 로 설정하는 예시입니다.

 

송신해야할 전체 프레임은 "0x01 06 1D04 1770 <CRC-16>" 이 됩니다.

1번국에 쓰기펑션(06) 으로 0x1D05 어드레스 주소값에 0x1770 (60.00hz) 를 쓰겠다는 의미가 되겠죠.

주소값을 써줄때는 항상 -1 를 해주어야 하기때문에 0x1D05 를 바로 쓰지않고 1를 뺀 0x1D04 를 쓰는것 입니다.

 

또 위의 샘플 래더를 보면 하위바이트부터 상위로 프레임을 작성한것을 확인할수 있을겁니다.

여기에 PLC에서 [MOV H1D04 D5201] 부분을 주목하면

PLC 시리얼 통신을 바이트 단위로 설정하였기 때문일것이라 생각되는데

저렇게 데이터를 송신하게되면 원래 송신하고자 했던 0x1D04 가 아니라 0x041D 가 되어 송신이 되어버립니다.

이를 보정하기위한 스왑을 해준것 입니다.

 

그래서 다음과 같은 프레임이 되었습니다.  "0x01 06 1D04 1770 <CRC-16>" 

이 송신 프레임을 소스로 CRC-16 코드만 생성하여 실제로 송신하면 인버터의 1속값이 60.00hz 로 설정될것으로 기대됩니다.

이 데이터를 ZR0900 으로 옮겨주어 XCALL을 이용하여 펑션을 불러와 실행하면 CRC-16 코드가 생성될것입니다.

XCALL 펑션을 활용하여 1번 문자부터 6번 문자까지 참조하여 모드버스용 다항식 XOR 코드인 "0xA001"을 이용하여 CRC-16 코드를 생성하여 D0203에 저장합니다.

결과는 리턴값 D0203 에 CRC-16 이 생성되어 0xC073 저장되는것이 확인됩니다.

 

이 결과값을 한번 CRC-16 계산기를 통해 검증해보면 되겠네요.

https://crccalc.com/

 

Online CRC-8 CRC-16 CRC-32 Calculator

Input: ASCII HEX

crccalc.com

 

잘 된것 같습니다.

모드버스의 경우 상대 기기에 따라 CRC-16 생성코드를 그냥 송신해야 교신이 되는 경우가 있고, 스왑을 해야 교신이 되는 경우가 더러 있습니다.

 

그리고 통신 프로토콜에 따라 CRC코드의 생성 알고리즘이 달라 다항식 코드를 0x8005 를 그대로 사용하는 경우(LSB우선)와, 뒤집은 0xA001 을 사용하는 경우(MSB우선) 도 있습니다.

통신 전 프로토콜이 사용하는 CRC 알고리즘을 확인하고 그에 맞는 알고리즘을 사용하여 CRC를 생성해야합니다.

반응형

댓글