3-1) CRC16 논리적 흐름을 그대로 구현
3-2) 최대한 간략화하여 구현
3-3) 사전 연산 테이블 활용하여 구현
매크로로 CRC16 구현을 위한 단계 정리
1) 사용할 배열 및 변환 Table 선언
2) HEX값을 2진수 수로 변환
2-1) 2진수로 변환한 길이 (lenData)를 저장
2-2) 값 뒤에 16비트 추가 : 0x1021 연산한 결과값(나머지) 표시를 위한 위치
3) 앞에서부터 1021을 lenData 길이만큼 XOR 반복 연산
3-1) 앞자리가 1이면 XOR 연산
3-2) 앞자리가 0이면 다음 값으로
4) 연산결과 나머지를 HEX값으로 변환
1) 사용할 변수 및 변환 Table 선언
Dim crcValue
crcValue = Array("0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "1")
Dim hexArray
hexArray = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
Dim binArray
binArray = Array("0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111")
① crcValue : 0x1021을 2진수 형태의 배열로 정리
② hexArray : 16진수 변환을 위한 16진수 숫자 순서 배열
③ binArray : 16진수를 2진수로 변환했을 때의 값 배열
2) 입력된 HEX값을 2진수 수로 변환
For i = 1 To lenData
binAssy = binAssy & binArray(Val("&H" & Mid(crcData, i, 1)))
Next i
lenData = Len(binAssy)
binAssy = binAssy & "0000000000000000"
① 입력값 (crcData)을 앞자리부터 하나씩 2진수 값으로 변환하고 변환한 결과를 binAssy에 누적 저장
ex) crcData = 0x1A3B → binAssy = 0001101000111011
② 2진수로 변환한 데이터 길이값 저장
ex) binAssy = 0001101000111011 → lenData = 16
③ 변환결과 뒤에 16비트 추가
ex) binAssy = 0001101000111011 → binAssy = 00011010001110110000000000000000
3) 앞에서부터 1021을 lenData 길이만큼 XOR 반복 연산
For i = 1 To lenData
If Left(binAssy, 1) = 1 Then
binAssy = Mid(binAssy, 2)
For j = 1 To 16
binCalAssy = binCalAssy & (Mid(binAssy, j, 1) Xor crcValue(j - 1))
Next j
binAssy = binCalAssy & Mid(binAssy, 17)
binCalAssy = ""
Else
binAssy = Mid(binAssy, 2)
End If
Next i
① 데이터 길이만큼 반복 연산
② 앞자리가 1이면 앞자리 삭제하고 0x1021과 XOR 연산
③ 앞자리가 0이면 앞자리 삭제
④ 연산결과 최종적으로 16비트 길이의 나머지값이 남게 된다.
4) 연산결과를 HEX값으로 변환
For i = 1 To 4
binTemp = Mid(binAssy, i * 4 - 3, 4)
For j = 0 To 15
If binTemp = binArray(j) Then
crcResult = crcResult & hexArray(j)
End If
Next j
Next i
① 4비트 단위로 나눠서 HEX값으로 변환
전체 수식
'이진수 변환 후 비트 시프트
Function crcBin(crcData As String, Optional crcIntValue As String = "FFFF") 'CRC16-CITT 계산 함수
Dim crcValue
crcValue = Array("0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "1") 'CRC 다항식 0x1021
Dim hexArray
hexArray = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") '16진수 배열
Dim binArray
binArray = Array("0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111") '2진수 배열
Dim i As Integer, j As Integer '반복 구문용 변수
Dim lenData As Integer 'data 길이 변수
Dim binData As String '2진수 변환값
Dim crcIntBin As String '초기값 2진수 변환
Dim binAssy As String '2진수 출력값 누적 저장
Dim binCalAssy As String 'XOR 연산 중간값
Dim crcResult As String '16진수 변환값
'입력 Data 정리
crcData = Replace(crcData, " ", "") '공백이 있으면 공백 제거
crcData = UCase(crcData) '입력값의 알파벳이 소문자면 대문자로 변경
lenData = Len(crcData) 'data 길이 확인
'초기값 및 입력값을 이진수로 변경
For i = 1 To 4
crcIntBin = crcIntBin & binArray(Val("&H" & Mid(crcIntValue, i, 1))) '추출값을 16진수 숫자로 변환하여 해당 위치 Array값 추출하고 결과 누적
Next i
For i = 1 To lenData
binAssy = binAssy & binArray(Val("&H" & Mid(crcData, i, 1))) '추출값을 16진수 숫자로 변환하여 해당 위치 Array값 추출하고 결과 누적
Next i
binAssy = binAssy & "0000000000000000" '뒤에 16비트 추가
'XOR 연산
'초기값 연산 : 0xffff
For j = 1 To 16
binCalAssy = binCalAssy & (Mid(binAssy, j, 1) Xor Mid(crcIntBin, j, 1))
Next j
binAssy = binCalAssy & Mid(binAssy, 17)
binCalAssy = ""
'정규 연산 : 0x1021
lenData = Len(binAssy) - 16 '연산 반복할 횟수
For i = 1 To lenData
If Left(binAssy, 1) = 1 Then '앞자리가 1일 경우 xor 연산
binAssy = Mid(binAssy, 2) '앞자리 삭제
For j = 1 To 16
binCalAssy = binCalAssy & (Mid(binAssy, j, 1) Xor crcValue(j - 1))
Next j
binAssy = binCalAssy & Mid(binAssy, 17)
binCalAssy = ""
Else
binAssy = Mid(binAssy, 2)
End If
Next i
'연산값을 16진수로 변경
For i = 1 To 4
binTemp = Mid(binAssy, i * 4 - 3, 4)
For j = 0 To 15
If binTemp = binArray(j) Then
crcResult = crcResult & hexArray(j)
End If
Next j
Next i
crcBin = crcResult
End Function
* 위의 전체 수식에는 초기값 0xFFFF를 적용한 후 계산하도록 설정되어 있고,
임의의 초기값을 입력할 수도 있도록 되어 있다.
필요없다면 해당 부분 수식을 삭제하거나 Function의 FFFF를 0000으로 변환하면 된다.
결과적으로 특정한 HEX 데이터를 입력할 경우 체크섬 데이터가 나오게 되고,
만약 이미 동일한 CRC16 방식을 이용하여 계산한 체크섬이 뒤에 붙어 있는 데이터라면 결과는 0x0000이 나오게 된다.
실행한 예시
* 나는 해당 함수를 personal의 모듈에 넣어두고 사용하기에 함수를 사용할때 personal.xlsb!를 입력하였다.
0xF2 0xA5 0x9A 0x1F라는 임의의 데이터에 CRC16 함수를 적용한 결과값이 0xB4 0x77이고,
이를 원본 데이터 뒤에 붙여서 CRC16 함수를 적용하면 0x00 0x00으로
데이터 및 CRC16 함수에 문제가 없다는 것을 확인할 수 있다.
사실 짧은 데이터 하나 두개 정도를 체크섬에 문제가 없는지 확인하는 정도라면 현재의 수식으로도 충분하다.
연산 시간이 쓸데없이 길어지기는 하지만 짧은 주기로 시리얼 통신을 하는 것도 아니니까.
하지만 처음에 봤던 c언어로 된 간결한 코드를 흉내라도 내고 싶다는 생각에
좀더 간결하게 작성할 수 있는 방안을 찾아보기로 하였다.
'엑셀 매크로' 카테고리의 다른 글
체크섬 (CRC16-CCITT) 엑셀 매크로로 구현하기_3-2) 간략하게 구현 (0) | 2024.03.07 |
---|---|
체크섬 (CRC16-CCITT) 엑셀 매크로로 구현하기_2) 구현 계획 (0) | 2024.01.17 |
체크섬 (CRC16-CITT) 엑셀 매크로로 구현하기_1) CRC16의 정의 (1) | 2024.01.10 |