MODBUS

MODBUS Protocol

기하 2021. 8. 17. 16:29

프로토콜 설명

MODBUS© 프로토콜은

지능형 장치 간의 마스터-슬레이브 통신을 설정하는 데 널리 사용되는 메시징 구조입니다. 

 

마스터에서 슬레이브로 전송되는 MODBUS 메시지에는

① 슬레이브의 주소,

② 명령'(예: '레지스터 읽기' 또는 '레지스터 쓰기'),

③ 데이터

④ 체크섬(LRC 또는 CRC)이 포함됩니다.


Modbus 프로토콜은 메시징 구조일 뿐이므로 기본 물리 계층과 독립적입니다. 

전통적으로 RS232, RS422 또는 RS485를 사용하여 구현됩니다.

 

The Request 요청 요청
리퀘스트안에 있는 기능 코드(Function Code)
주소가 지정된 슬레이브 장치에 수행할 작업의 종류를 알려줍니다. 

데이터 바이트에는 슬레이브가 기능을 수행하는 데 필요한 추가 정보가 포함됩니다. 

예를 들어, 기능 코드 03은 슬레이브가 홀딩 레지스터를 읽고 내용으로 응답하도록 요청합니다. 

데이터 필드는 슬레이브가 시작할 레지스터와 읽을 레지스터 수를 알려주는 정보를 포함해야 합니다. 

오류 검사 필드는 슬레이브가 메시지 내용의 무결성을 검증하는 방법을 제공합니다.

 

The Response 응답
슬레이브가 정상적인 응답을 하면 응답의 기능 코드는 요청의 기능 코드의 에코입니다. 

데이터 바이트는 레지스터 값이나 상태와 같이 슬레이브가 수집한 데이터를 포함합니다. 

오류가 발생하면 응답이 오류 응답임을 나타내도록 기능 코드가 수정되고

데이터 바이트에는 오류를 설명하는 코드가 포함됩니다. 

오류 검사 필드를 통해 마스터는 메시지 내용이 유효한지 확인할 수 있습니다.

 

컨트롤러는 ASCII 또는 RTU의 두 가지 전송 모드 중 하나를 사용하여 표준

Modbus 네트워크에서 통신하도록 설정할 수 있습니다.

 

ASCII 모드
컨트롤러가 ASCII(American Standard Code for Information Interchange) 모드를 사용하여

Modbus 네트워크에서 통신하도록 설정되면

메시지의 각 8비트 바이트가 2개의 ASCII 문자로 전송됩니다. 

이 모드의 주요 이점은 오류를 일으키지 않고

문자 사이에 최대 1초의 시간 간격이 발생할 수 있다는 것입니다.

 

Coding System
    Hexadecimal ASCII printable characters 0 ... 9, A ... F
Bits per Byte
    1 start bit
    7 data bits, least significant bit sent first
    1 bit for even / odd parity-no bit for no parity
    1 stop bit if parity is used-2 bits if no parity
Error Checking
    Longitudinal Redundancy Check (LRC)

 

RTU 모드
컨트롤러가 RTU(Remote Terminal Unit) 모드를 사용하여

Modbus 네트워크에서 통신하도록 설정되면

메시지의 각 8비트 바이트에는 2개의 4비트 16진수 문자가 포함됩니다. 

이 모드의 주요 이점은 더 큰 문자 밀도가 동일한 전송 속도에 대해

ASCII보다 더 나은 데이터 처리량을 허용한다는 것입니다. 

각 메시지는 연속 스트림으로 전송되어야 합니다.

 

Coding System
Eight-bit binary, hexadecimal 0 ... 9, A ... F
Two hexadecimal characters contained in each eight-bit field of the message
Bits per Byte
1 start bit
8 data bits, least significant bit sent first
1 bit for even / odd parity-no bit for no parity
1 stop bit if parity is used-2 bits if no parity
Error Check Field
Cyclical Redundancy Check (CRC)

 

 

ASCII 모드에서 메시지는 콜론( : ) 문자(ASCII 3A 16진수)로 시작하고

캐리지 리턴 줄 바꿈(CRLF) 쌍(ASCII 0D 및 0A 16진수)으로 끝납니다.


다른 모든 필드에 대해 전송되는 허용되는 문자는 16진수 0 ... 9, A ... F입니다.

네트워크 장치는 네트워크 버스에서 콜론 문자를 지속적으로 모니터링합니다. 

하나가 수신되면 각 장치는 다음 필드(주소 필드)를 디코딩하여 주소가 지정된 장치인지 확인합니다.


메시지 내에서 문자 사이에 최대 1초의 간격이 경과할 수 있습니다. 

더 큰 간격이 발생하면 수신 장치는 오류가 발생한 것으로 간주합니다. 

일반적인 메시지 프레임은 다음과 같습니다.

Start Address Function Data LRC End
: 2 Chars 2 Chars N Chars 2 Chars CR LF


RTU 프레이밍
RTU 모드에서 메시지는

최소 3.5자 배의 무음 간격으로 시작됩니다. 

이것은 네트워크에서 사용되는 전송 속도에서 문자 시간의 배수로 가장 쉽게 구현됩니다

(아래 그림에서 T1-T2-T3-T4로 표시). 

그런 다음 전송되는 첫 번째 필드는 장치 주소입니다.
모든 필드에 대해 전송되는 허용되는 문자는 16진수 0 ... 9, A ... F입니다.

네트워크 장치는 무음 간격을 포함하여 네트워크 버스를 지속적으로 모니터링합니다. 

첫 번째 필드(주소 필드)가 수신되면 각 장치는 이를 디코딩하여 주소가 지정된 장치인지 확인합니다.
마지막으로 전송된 문자 다음에 최소 3.5자 배의 유사한 간격이 메시지의 끝을 표시합니다. 

이 간격 후에 새 메시지를 시작할 수 있습니다.


전체 메시지 프레임은 연속 스트림으로 전송되어야 합니다. 

프레임이 완료되기 전에 1.5 문자 시간 이상의 무음 간격이 발생하면

수신 장치는 불완전한 메시지를 플러시하고 다음 바이트가 새 메시지의 주소 필드라고 가정합니다.
마찬가지로, 새 메시지가 이전 메시지 다음에 오는 3.5자보다 일찍 시작되면

수신 장치는 이를 이전 메시지의 연속으로 간주합니다. 

이것은 최종 CRC 필드의 값이 결합된 메시지에 대해 유효하지 않기 때문에 오류를 설정합니다. 

일반적인 메시지 프레임은 다음과 같습니다.

Stsrt Address Function Data CRC End
3.5 Char time 8 Bit 8 Bit N * 8Bit 16Bit 3.5 Char time

 

Address Field 주소 필드
메시지 프레임의 주소 필드는

2자(ASCII) 또는 8비트(RTU)를 포함합니다. 

개별 슬레이브 장치에는 1 ... 247 범위의 주소가 할당됩니다.

 

Function Field 기능 필드

기능 코드 필드는 주소가 지정된 슬레이브에 수행할 기능을 알려줍니다.
Modbus poll에서 지원하는 기능은 다음과 같습니다.

 

01 READ COIL STATUS
02 READ INPUT STATUS
03 READ HOLDING REGISTERS
04 READ INPUT REGISTERS
05 WRITE SINGLE COIL
06 WRITE SINGLE REGISTER
15 WRITE MULTIPLE COILS
16 WRITE MULTIPLE REGISTERS

 

데이터 필드에는 요청 또는 전송 데이터가 포함됩니다.

 

오류 검사 필드 내용


표준 Modbus 네트워크에는 두 가지 종류의 오류 검사 방법이 사용됩니다. 

류 검사 필드 내용은 사용 중인 방법에 따라 다릅니다.

 

ASCII
ASCII 모드가 문자 프레임에 사용되는 경우 오류 검사 필드에는 두 개의 ASCII 문자가 포함됩니다. 

오류 검사 문자는 시작 콜론과 종료 CRLF 문자를 제외하고

메시지 내용에 대해 수행되는 LRC(Longitudinal Redundancy Check) 계산의 결과입니다.
LRC 문자는 CRLF 문자 앞에 오는 마지막 필드로 메시지에 추가됩니다.
LRC 예제 코드

 

RTU
RTU 모드가 문자 프레이밍에 사용될 때 오류 검사 필드에는

2개의 8비트 바이트로 구현된 16비트 값이 포함됩니다. 

오류 검사 값은 메시지 내용에 대해 수행된 순환 중복 검사 계산의 결과입니다.

 

CRC 필드는 메시지의 마지막 필드로 메시지에 추가됩니다. 이 작업이 완료되면 필드의 하위 바이트가 먼저 추가되고 상위 바이트가 뒤따릅니다. CRC 상위 바이트는 메시지에서 보낼 마지막 바이트입니다.
CRC 예제 코드


기능 01(01hex) 코일 읽기

슬레이브에 있는 개별 코일의 ON/OFF 상태를 읽습니다.

요청
요청 메시지는 시작 코일과 읽을 코일의 수량을 지정합니다.

슬레이브 장치 주소 4에서 10...22(코일 11~23) 읽기 요청의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 04 0 4
함수 01 0 1
시작 주소 안녕하세요 00 0 0
시작 주소 Lo 0A 0A
코일 수량 안녕하세요 00 0 0
코일 수량 Lo 0D 0D
오류 확인 Lo DD LRC (E 4)
오류 확인 안녕하세요 98  
트레일러 없음 CR LF
총 바이트 8 17

 

응답
코일 상태 응답 메시지는 데이터 필드의 비트당 하나의 코일로 압축됩니다. 상태는 다음과 같이 표시됩니다. 1은 ON 값이고 0은 OFF 값입니다. 첫 번째 데이터 바이트의 LSB는 요청에 지정된 코일을 포함합니다. 다른 코일은 이 바이트의 상위 끝을 향하고 후속 바이트에서 하위에서 상위로 따릅니다. 반환된 코일 수량이 8의 배수가 아닌 경우 최종 데이터 바이트의 나머지 비트는 0으로 채워집니다(바이트의 상위 끝쪽으로). 바이트 수 필드는 데이터의 전체 바이트 수를 지정합니다.

요청에 대한 응답의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 04 0 4
함수 01 0 1
바이트 수 02 0 2
데이터(코일 7...10) 0A 0A
데이터(코일 27...20) 11 1 1
오류 확인 Lo B3 LRC(독일)
오류 확인 안녕하세요 50 없음
트레일러 없음 CR LF
총 바이트 7 15

 


기능 02(02hex) 개별 입력 읽기

슬레이브에 있는 이산 입력의 ON/OFF 상태를 읽습니다.

요청
요청 메시지는 시작 입력과 읽을 입력의 수량을 지정합니다.

슬레이브 장치 주소 4에서 10...22(입력 10011~10023) 읽기 요청의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 04 0 4
함수 02 0 2
시작 주소 안녕하세요 00 0 0
시작 주소 Lo 0A 0A
입력 수량 Hi 00 0 0
수량 입력 소호의 0D 0D
오류 확인 Lo 99 LRC (E 3)
오류 확인 안녕하세요 98  
트레일러 없음 CR LF
총 바이트 8 17

 

응답
입력 상태 응답 메시지는 데이터 필드의 비트당 하나의 입력으로 압축됩니다. 상태는 다음과 같이 표시됩니다. 1은 ON 값이고 0은 OFF 값입니다. 첫 번째 데이터 바이트의 LSB는 요청에 지정된 입력을 포함합니다. 다른 입력은 이 바이트의 상위 끝을 향하고 후속 바이트의 하위에서 상위로 이어집니다. 반환된 입력 양이 8의 배수가 아닌 경우 최종 데이터 바이트의 나머지 비트는 0으로 채워집니다(바이트의 상위 끝쪽으로). 바이트 수 필드는 데이터의 전체 바이트 수를 지정합니다.

요청에 대한 응답의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 04 0 4
함수 02 0 2
바이트 수 02 0 2
데이터(입력 17...10) 0A 0A
데이터(입력 27...20) 11 1 1
오류 확인 Lo B3 LRC(DD)
오류 확인 안녕하세요 14 없음
트레일러 없음 CR LF
총 바이트 7 15

 


기능 03(03hex) 보유 레지스터 읽기

슬레이브에 있는 홀딩 레지스터의 바이너리 내용을 읽습니다.

요청
요청 메시지는 시작 레지스터와 읽을 레지스터의 수량을 지정합니다.

슬레이브 장치 1에서 0...1(레지스터 40001~40002) 읽기 요청의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 01 0 1
함수 03 0 3
시작 주소 안녕하세요 00 0 0
시작 주소 Lo 00 0 0
레지스터 수량 안녕하세요 00 0 0
수량 레지스터 소호의 02 0 2
오류 확인 Lo C4 LRC(FA)
오류 확인 안녕하세요 0B  
트레일러 없음 CR LF
총 바이트 8 17

 

응답
응답 메시지의 레지스터 데이터는 레지스터당 2바이트로 압축되며 바이너리 내용은 각 바이트 내에서 오른쪽으로 정렬됩니다. 각 레지스터에 대해 첫 번째 바이트는 상위 비트를 포함하고 두 번째 바이트는 하위 비트를 포함합니다.

요청에 대한 응답의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 01 0 1
함수 03 0 3
바이트 수 04 0 4
데이터 하이 00 0 0
데이터 로우 06 0 6
데이터 하이 00 0 0
데이터 로우 05 0 5
오류 확인 Lo LRC(ED)
오류 확인 안녕하세요 31 없음
트레일러 없음 CR LF
총 바이트 8 19

기능 04(04hex) 입력 레지스터 읽기

슬레이브에 있는 입력 레지스터의 바이너리 내용을 읽습니다.

요청
요청 메시지는 시작 레지스터와 읽을 레지스터의 수량을 지정합니다.

슬레이브 장치 1에서 0...1(레지스터 30001~30002) 읽기 요청의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 01 0 1
함수 04 0
시작 주소 안녕하세요 00 0 0
시작 주소 Lo 00 0 0
레지스터 수량 안녕하세요 00 0 0
수량 레지스터 소호의 02 0 2
오류 확인 Lo 71 LRC(여9)
오류 확인 안녕하세요 CB  
트레일러 없음 CR LF
총 바이트 8 17

 

응답
응답 메시지의 레지스터 데이터는 레지스터당 2바이트로 압축되며 바이너리 내용은 각 바이트 내에서 오른쪽으로 정렬됩니다. 각 레지스터에 대해 첫 번째 바이트는 상위 비트를 포함하고 두 번째 바이트는 하위 비트를 포함합니다.

요청에 대한 응답의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 01 0 1
함수 04 0 4
바이트 수 04 0 4
데이터 하이 00 0 0
데이터 로우 06 0 6
데이터 하이 00 0 0
데이터 로우 05 0 5
오류 확인 Lo DB LRC(EC)
오류 확인 안녕하세요 86 없음
트레일러 없음 CR LF
총 바이트 9 19

 


기능 05(05hex) 단일 코일 쓰기

단일 코일을 ON 또는 OFF에 씁니다.

요청
요청 메시지는 기록할 코일 참조를 지정합니다. 코일은 0에서 시작하여 주소가 지정됩니다. 코일 1은 0으로 지정됩니다.

요청된 ON/OFF 상태는 요청 데이터 필드의 상수로 지정됩니다. FF 00 hex 값은 코일이 ON이 되도록 요청합니다. 값이 00 00이면 OFF가 되도록 요청합니다. 다른 모든 값은 불법이며 코일에 영향을 미치지 않습니다.

다음은 슬레이브 장치 17에서 코일 173을 ON으로 쓰기 위한 요청의 예입니다.

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 05 0 5
코일 주소 안녕하세요 00 0 0
코일 주소 Lo 교류 교류
쓰기 데이터 안녕 FF 0 0
쓰기 데이터 Lo 00 FF
오류 확인 Lo 4E LRC(3층)
오류 확인 안녕하세요 8B  
트레일러 없음 CR LF
총 바이트 8 17

 

응답
정상적인 응답은 요청의 반향이며 코일 상태가 작성된 후 반환됩니다.
요청에 대한 응답의 예:

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 05 0 5
코일 주소 안녕하세요 00 0 0
코일 주소 Lo 교류 교류
쓰기 데이터 안녕 FF 0 0
쓰기 데이터 Lo 00 FF
오류 확인 Lo 4E LRC(3층)
오류 확인 안녕하세요 8B  
트레일러 없음 CR LF
총 바이트 8 17

 


기능 06(06hex) 단일 레지스터 쓰기

단일 홀딩 레지스터에 값을 씁니다.

요청
요청 메시지는 기록될 레지스터 참조를 지정합니다. 레지스터는 0부터 시작하여 주소가 지정됩니다. 레지스터 1은 0으로 주소가 지정됩니다.

요청된 쓰기 값은 요청 데이터 필드에 지정됩니다. 다음은 슬레이브 장치 17의 00 03 16진수에 레지스터 40002를 쓰라는 요청의 예입니다.

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 06 0 6
주소 등록 안녕하세요 00 0 0
주소 등록 01 0 1
쓰기 데이터 안녕 00 0 0
쓰기 데이터 Lo 03 0 3
오류 확인 Lo 9A LRC (E 5)
오류 확인 안녕하세요 9B  
트레일러 없음 CR LF
총 바이트 8 17

 

응답
정상적인 응답은 레지스터 내용이 기록된 후 반환된 요청의 반향입니다.

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 06 0 6
코일 주소 안녕하세요 00 0 0
코일 주소 Lo 01 0 1
쓰기 데이터 안녕 00 0 0
쓰기 데이터 Lo 03 0 3
오류 확인 Lo 9A LRC (E 5)
오류 확인 안녕하세요 9B  
트레일러 없음 CR LF
총 바이트 8 17

 


기능 15(0Fhex) 다중 코일 쓰기

코일 시퀀스의 각 코일을 ON 또는 OFF로 씁니다.

요청
요청 메시지는 기록할 코일 참조를 지정합니다. 코일은 0에서 시작하여 주소가 지정됩니다. 코일 1은 0으로 지정됩니다.

요청된 ON/OFF 상태는 요청 데이터 필드의 내용에 의해 지정됩니다. 필드의 비트 위치에 있는 논리 1은 해당 코일이 ON이 되도록 요청합니다. 논리적 0은 OFF를 요청합니다.

아래는 슬레이브 장치 17에서 코일 20(19 또는 13 16진수로 주소 지정)에서 시작하는 일련의 10개 코일을 작성하라는 요청의 예입니다.

요청 데이터 내용은 2바이트입니다: CD 01 16진수(1100 1101 0000 0001 바이너리). 바이너리 비트는 다음과 같은 방식으로 코일에 해당합니다.

비트: 1 1 0 0 1 1 0 1 0 0 0 0 0 0 0 1

코일: 27 26 25 24 23 22 21 20 - - - - - - 29 28

전송된 첫 번째 바이트(CD hex)는 코일 27 ... 20의 주소를 지정하며, 최하위 비트는 이 세트에서 가장 낮은 코일(20)의 주소를 지정합니다.

전송된 다음 바이트(01 hex)는 코일 29 및 28을 지정하고 최하위 비트는 이 세트에서 가장 낮은 코일(28)을 지정합니다. 마지막 데이터 바이트에서 사용되지 않은 비트는 0으로 채워져야 합니다.

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 0F 0F
코일 주소 안녕하세요 00 0 0
코일 주소 Lo 13 1 3
코일 수량 안녕하세요 00 0 0
코일 수량 Lo 0A 0A
바이트 수 02 0 2
쓰기 데이터 안녕 CD CD
쓰기 데이터 Lo 01 0 1
오류 확인 Lo BF LRC(여3)
오류 확인 안녕하세요 0B  
트레일러 없음 CR LF
총 바이트 11 23

 

응답
일반 응답은 슬레이브 주소, 기능 코드, 시작 주소 및 작성된 코일 수를 반환합니다. 다음은 위에 표시된 요청에 대한 응답의 예입니다.

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 0F 0F
코일 주소 안녕하세요 00 0 0
코일 주소 Lo 13 1 3
코일 수량 안녕하세요 00 0 0
코일 수량 Lo 0A 0A
오류 확인 Lo 26 LRC (C 3)
오류 확인 안녕하세요 99  
트레일러 없음 CR LF
총 바이트 8 17

 

 


기능 16(10hex) 여러 레지스터 쓰기

일련의 홀딩 레지스터에 값을 씁니다.

요청
요청 메시지는 기록할 레지스터 참조를 지정합니다. 레지스터는 0부터 시작하여 주소가 지정됩니다. 레지스터 1은 0으로 주소가 지정됩니다.

요청된 쓰기 값은 요청 데이터 필드에 지정됩니다. 데이터는 레지스터당 2바이트로 압축됩니다.

다음은 슬레이브 장치 17에서 40002에서 00 0A 및 01 02 16진수로 시작하는 두 개의 레지스터를 쓰라는 요청의 예입니다.

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 10 1 0
시작 주소 안녕하세요 00 0 0
시작 주소 Lo 01 0 1
레지스터 수량 안녕하세요 00 0 0
수량 레지스터 소호의 02 0 2
바이트 수 04 0 4
데이터 하이 00 0 0
데이터 로우 0A 0A
데이터 하이 01 0 1
데이터 로우 02 0 2
오류 확인 Lo C6 LRC(CB)
오류 확인 안녕하세요 F0  
트레일러 없음 CR LF
총 바이트 13 23

 

응답
일반 응답은 슬레이브 주소, 기능 코드, 시작 주소 및 기록된 레지스터 수를 반환합니다. 다음은 위에 표시된 요청에 대한 응답의 예입니다.

분야 명 RTU(16진수) ASCII 문자
헤더 없음 : (콜론)
슬레이브 주소 11 1 1
함수 10 1 0
시작 주소 안녕하세요 00 0 0
시작 주소 Lo 01 0 1
레지스터 수량 안녕하세요 00 0 0
수량 레지스터 소호의 02 0 2
오류 확인 Lo 12 LRC(DC)
오류 확인 안녕하세요 98  
트레일러 없음 CR LF
총 바이트 8 17

 


LRC 예제 코드

이 함수는 C 언어를 사용하여 LRC BYTE를 계산하는 예제입니다.

BYTE LRC (BYTE *nData, WORD wLength)
{
BYTE nLRC = 0 ; // LRC char initialized

for (int i = 0; i < wLength; i++)
nLRC += *nData++;

return (BYTE)(-nLRC);

} // End: LRC


CRC 예제 코드

이 함수는 C 언어를 사용하여 CRC 단어를 계산하는 방법의 예입니다.

WORD CRC16 (const BYTE *nData, WORD wLength) { static const WORD wCRCTable[] = { 0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241, 0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440, 0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40, 0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841, 0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40, 0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41, 0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641, 0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040, 0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240, 0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441, 0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41, 0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840, 0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41, 0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40, 0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640, 0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041, 0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240, 0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441, 0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41, 0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840, 0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41, 0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40, 0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640, 0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041, 0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241, 0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440, 0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40, 0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841, 0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40, 0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41, 0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641, 0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 }; BYTE nTemp; WORD wCRCWord = 0xFFFF; while (wLength--) { nTemp = *nData++ ^ wCRCWord; wCRCWord >>= 8; wCRCWord ^= wCRCTable[nTemp]; } return wCRCWord;

} // 끝: CRC16