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언어로 된 간결한 코드를 흉내라도 내고 싶다는 생각에

좀더 간결하게 작성할 수 있는 방안을 찾아보기로 하였다.

 

Posted by 지마군
,

rss