반응형
1. Modbus
# "Modbus"라는 이름의 유래
Modbus는 “Modicon Bus”의 줄임말
- Modicon = 1970년대 초 Modicon사(현재 슈나이더 일렉트릭) 가 만든 PLC(Programmable Logic Controller) 브랜드
- Bus = 여러 장치가 데이터를 주고받는 통신선
Modbus = Modicon이 만든 산업용 통신 버스 프로토콜으로 탄생함.
1979년에 공개되어 지금까지도 전 세계 산업 현장에서 가장 널리 쓰이는 오픈 프로토콜 중 하나임.
# Modbus 구성
Modbus는 “CRC 다항식” 하나로 구분되지않음.
대신 다음 3가지 구성 요소로 정의.
구성 요소설명
| 통신 구조 (프레임 포맷) | [Slave Address][Function Code][Data][CRC16] 같은 구조 |
| 기능 코드(Function Code) | 0x03: Holding Register 읽기, 0x06: Write Single Register 등 |
| 오류 검출 방식 (CRC16) | CRC 다항식 0xA001 사용 (MSB일 경우, 0x8005) |
즉, Modbus는 단순히 CRC만의 이름이 아니라,
“데이터 구조 + 명령 규칙 + CRC 검증 방식”을 모두 포함한 프로토콜 전체 이름.
# 왜 CRC도 “Modbus CRC”라고 부를까?
- Modbus 프로토콜에서 사용하는 CRC16 알고리즘의 다항식(0xA001) 이
다른 표준(CRC-CCITT, CRC-USB 등)과 다르기 때문
| CRC 이름 | 다항식 | 용도 |
| CRC16-CCITT | 0x1021 | 통신 규약, XMODEM, PPP 등 |
| CRC16-IBM / ANSI / MODBUS | 0x8005 / 0xA001 | Modbus 통신 |
| CRC32 (Ethernet) | 0x04C11DB7 | 이더넷, ZIP 등 |
즉, “Modbus CRC”는
“Modbus 프로토콜에서 사용하는 CRC16의 변형”
→ 다항식 0xA001 사용
→ 비트 순서 LSB-first
2. CRC16과 CRC32
# CRC란?
CRC는 “순환 중복 검사(Cyclic Redundancy Check)”의 약자, 데이터 유효성 검사
데이터를 다항식(polynomial) 형태로 보고, 특정 생성 다항식으로 나눈 나머지(remainder) 를 체크값으로 사용하는 방식
- 말은 어렵지만 간단하게 한 비트씩 시프트하면서 1이면 이면 XOR 0이면 시프트 연산만 처리, 반복해서 CRC 값을 구함.
XOR보다 훨씬 오류 검출 능력이 좋음.
# CRC-16 예시 (C++)
가장 흔히 쓰이는 CRC-16-IBM (CRC-16-ANSI) 방식 예시
- 다항식: 0xA001 (LSB), 0x8005 (MSB)
- 초기값: 0xFFFF
#include <iostream>
#include <vector>
uint16_t crc16(const std::vector<uint8_t>& data) {
uint16_t crc = 0xFFFF;
for (uint8_t byte : data) {
crc ^= byte;
for (int i = 0; i < 8; i++) {
if (crc & 1)
crc = (crc >> 1) ^ 0xA001; // 다항식 XOR
else
crc >>= 1;
}
}
return crc;
}
int main() {
std::vector<uint8_t> data = {0x12, 0x34, 0x56};
uint16_t crc = crc16(data);
std::cout << "CRC16: 0x" << std::hex << crc << std::endl;
return 0;
}
출력 예시
CRC16: 0x4b37
# CRC-32 예시 (C++)
CRC-32는 이더넷, ZIP, PNG, gzip 등에서 가장 흔히 쓰이는 방식
- 다항식: 0xEDB88320 (LSB), 0x04C11DB7 (MSB)
- 초기값: 0xFFFFFFFF
#include <iostream>
#include <vector>
uint32_t crc32(const std::vector<uint8_t>& data) {
uint32_t crc = 0xFFFFFFFF;
for (uint8_t byte : data) {
crc ^= byte;
for (int i = 0; i < 8; i++) {
if (crc & 1)
crc = (crc >> 1) ^ 0xEDB88320;
else
crc >>= 1;
}
}
return ~crc; // 보통 마지막에 보수(~) 처리
}
int main() {
std::vector<uint8_t> data = {0x12, 0x34, 0x56};
uint32_t crc = crc32(data);
std::cout << "CRC32: 0x" << std::hex << crc << std::endl;
return 0;
}
출력 예시
CRC32: 0x8f7c1cb0
# CRC vs XOR 체크섬 비교
| 항목 | XOR 체크썸 | CRC16 | CRC32 |
| 연산 속도 | 빠름 | 보통 | 약간 느림 |
| 검출 능력 | 약함 (2비트 오류 검출 불가) | 좋음 (1~2비트, 버스트 오류 검출) | 매우 좋음 |
| 코드 복잡도 | 매우 단순 | 보통 | 조금 복잡 |
| 사용 예 | 간단한 센서, UART | 산업용 프로토콜(Modbus) | 네트워크, 파일 포맷 |
# 참고
- UART, RS485 같은 통신에서는 CRC16 (Modbus 방식)
- 파일 검증, 네트워크에서는 CRC32
- MCU나 센서용 가벼운 체크에는 XOR
* 송신측에서 보내는 데이터 crc 값과 수신측에서 계산된 crc 값이 동일해야 데이터 유효성이 검증됨.
반응형
'프로그래밍 > 작은 메모' 카테고리의 다른 글
| 유선 이더넷(Ethernet) IP 변경 배치 스크립트 파일(.bat) (0) | 2025.10.23 |
|---|---|
| C, C++ 터미널 출력 색상 변경 (0) | 2025.10.20 |
| XOR 데이터 무결성 확인(XOR 체크썸) (0) | 2025.10.17 |
| Ubuntu 터미널 명령어 반복 (0) | 2025.10.17 |
| Ubuntu USB 장치 연결 고정 (ex. 카메라 2대) (0) | 2025.10.13 |