CRC (Cyclic Redundancy Check) Verification is widely used. In the past, LRC (Longitudinal Redundancy Check) verification was used in most programs for simple processing. LRC verification is well understood and easy to implement. I studied the C language implementation of CRC in one day, and understood and mastered the basic principles and C language programming. Simply write it down based on your understanding.
1. CRC Overview
The basic idea of CRC test is to use linear coding theory to generate a test code r bit (that is, CRC code) based on certain rules on the sending end based on the k-bit binary code sequence to be transmitted ), after the information is attached, a new binary code sequence number (k + r) is formed and finally sent out. The acceptor verifies the data according to the same rules to determine whether an error occurs during transmission. There are two processing methods for the acceptor: 1. Calculate the CRC code of the k-bit sequence. If it is consistent with the received CRC, the receiving is correct. 2. Calculate the CRC code of the entire k + r bit. If it is 0, the received code is correct.
The CRC code has multiple check digits, including 8-bit, 16-bit, and 32-bit. The principle is the same. The 16-bit CRC code is generated by first shifting the number of binary sequences to be sent to the left 16 bits (that is, after multiplying the power of 16 2) by a polynomial, the remainder is the CRC code.
The CRC code is calculated using the formula 2, that is, the division of polynomials uses a subtraction operation without any bits. The operation is equivalent to an exclusive or operation. This must be understood carefully and is the foundation of programming.
CRC-16: (used in binary synchronous Systems) G (X) = X16 + X15 + X2 + 1
CRC-CCITT: (recommended by CCITT in Europe) G (X) = X16 + X12 + X5 + 1
CRC-32: G (X) = X32 + X26 + X23 + X22 + X16 + X12 + X11 + X10 + X8 + X7 + X5 + X4 + X2 + X1 + 1
2. calculate CRC by bit
The use of CRC-CCITT polynomials, polynomials 0x11021, C language programming, involved in the calculation of 0x1021, this place has to think deeply in order to understand the mysteries, share my ideas: when CRC is calculated by bit, for example, when the binary sequence is calculated as 1001 1010 1010 1111, the number of binary sequences is shifted to 16 places, that is, 1001 1010 1010 1111 (0000 0000 0000 0000 ), in fact, this binary sequence can be split into 1000 0000 0000 0000 0000 (0000 0000 0000) + 0000 0000 0000 0000 (0000 0000 0000 0000) + 00 0000 0000 0000 (0000 0000 0000) + 1 0000 0000 0000 (0000 0000 0000 0000) + ......
Now start the analysis operation:
<1> calculate the remainder of the first binary sub-sequence. The vertical division is 0x10000 ^ 0x11021, and the remaining 0 digits are retained;
<2> calculate the remainder of the second binary sequence, and then calculate the remainder of the first operation x 2 together with the second binary sequence, this step is understandable. If the split sequence is 0, no computation is required.
<3> the remainder of the remaining binary sequences is the same as the preceding two steps.
<4> when the last bit is calculated, it is the remainder of the binary sequence, that is, the CRC verification code.
This calculation method is equivalent to computing each bit. The calculation process is easy to understand and occupies less memory. The disadvantage is that one bit and one bit of computing is time-consuming.
The C language implementation method is provided below:
Copy codeThe Code is as follows: unsigned char test [16] = {0x00,0x11,0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
Unsigned char len = 16;
Void main (void)
{
Unsigned long temp = 0;
Unsigned int crc;
Unsigned char I;
Unsigned char * ptr = test;
While (len --){
For (I = 0x80; I! = 0; I = I> 1 ){
Temp = temp * 2;
If (temp & 0x10000 )! = 0)
Temp = temp ^ 0x11021;
If (* ptr & I )! = 0)
Temp = temp ^ (0x10000 ^ 0x11021 );
}
Ptr ++;
}
Crc = temp;
Printf ("0x % x", crc );
}
The above program is easy to understand based on computation analysis. To save memory space, we further simplify the program. The analysis shows that when the 15bit remainder calculated by the last bit in the binary sequence is 1 (the remainder calculated by the last bit & 0x8000 )! = 0. After the remainder of the last digit X 2, perform the remainder operation on 0x11021, and then add the remainder obtained by the base calculation. This is easy to understand. That is to say, let's take it for example as a simple division. After calculating the remainder of the last bit by 2, if it is large, it can be used as a divisor, then the division is removed. One thing is different from the normal division, because the polynomial Division uses a subtraction operation without the borrow digit, so 0x10000 can also be divided by 0x11021. The remainder is not 0x10000, but 0x1021. You just need to calculate it by yourself. The sum of the remainder is an addition operation that does not bring in bits, that is, an exclusive or. At last, we should also emphasize that the binary sequence is involved in the operation after 16 bits are shifted to the left, so the last bit of the sequence can also be divided. The simplified C language implementation is provided below.Copy codeThe Code is as follows: unsigned char test [16] = {0x00,0x11,0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
Unsigned char len = 16;
Void main (void)
{
Unsigned int crc = 0;
Unsigned char I;
Unsigned char * ptr = test;
While (len --){
For (I = 0x80; I! = 0; I = I> 1 ){
If (crc & 0x8000 )! = 0 ){
Crc = crc <1;
Crc = crc ^ 0x1021;
}
Else {
Crc = crc <1;
}
If (* ptr & I )! = 0 ){
Crc = crc ^ 0x1021;
}
}
Ptr ++;
}
Printf ("0x % x", crc );
}
The above program is more common on the Internet, but it must be explained in detail. Through the detailed analysis above, if it is still difficult to understand this section of the program, you can compare it with the previous program that has not been simplified. It is easier to understand it. If you still can't understand it, you can still look at it from the beginning. Is it easy for me to code so many words .....
The Calculation of CRC code by bit is relatively simple and occupies less memory, but it requires one bit and one bit to be calculated. Next we will introduce a method for Fast Calculation of CRC by byte lookup.
3. calculate CRC in bytes
With the knowledge of bitwise computing above, understanding this is a small case. For example, when the bytes calculate CRC, for example, when the binary sequence is 1001 1010 1010 1111, that is, 0x9a9f, the number of binary sequences is shifted to 16 places, it is 0x9a9f (0 0 0 0). In fact, the binary sequence can be split into 0x9a00 (0 0 0 0) + 0x009f (0 0 0 0 0). The analysis and calculation are the same as the preceding steps, the only difference is that the remainder CRC value in the previous calculation is multiplied by the power of two to participate in the next operation. This should be easy to understand. In order to simplify programming, the CRC in the calculation is split into a high eight-bit and a low eight-bit form. The high eight-bit value is directly added to the standard value to obtain the remainder, multiply the lower eight bits by the power of two to form the sum of the remainder and the calculated remainder. In order to increase the computing speed, we calculated all the CRC values of the 8-bit binary sequence numbers and placed them in a table. Using the look-up table method can greatly increase the computing speed.
How can we get a table? Of course, it is calculated. The following program provides a computing program with a polynomial of 0x11021.
Copy codeThe Code is as follows: void main (void)
{
Unsigned int crc = 0;
Unsigned char I;
Unsigned int j;
For (j = 0; j <256; j ++ ){
Crc = 0;
For (I = 0x80; I! = 0; I = I> 1 ){
If (crc & 0x8000 )! = 0 ){
Crc = crc <1;
Crc = crc ^ 0x1021;
}
Else {
Crc = crc <1;
}
If (j & I )! = 0 ){
Crc = crc ^ 0x1021;
}
}
Printf ("0x ");
If (crc <0x10 ){
Printf ("000 ");
}
Else if (crc <0 x100 ){
Printf ("00 ");
}
Else if (crc <0 x1000 ){
Printf ("0 ");
}
Printf ("% x,", crc );
}
}
If you are not using the 0x11021 polynomial, you only need to replace 0x1021 in the program with another one. The following printf statements can be replaced by printf ("0x % x,", crc) directly to make the generated tables more neat for control. The generated table is as follows:
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, values, numbers, numbers, 0x2a12, 0 xdbfd, 0 xcbdc, 0 Numbers, 0xeb9e, 0x9b79, numbers, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, numeric, 0x0c0, 0x1c41, 0 xedae, 0xfd8f, 0 xcdec, 0 xddcd, 0xad2a, 0xbd0b, numbers, 0x4ef4, numbers, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0 xefbe, 0 xdfdd, 0 xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, expires, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, expires, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, expires, 0xfb1e, 0x8bf9, 0x9bd8, 0 xabbb, 0xbb9a, 0x4a75, expires, 0x1ad0, 0x2ab3, 0x3a92, expires, 0xdd6c, 0xcd4d, 0 primary, 0xad8b, 0x9de8, 0x8dc9, primary, 0x6c07, primary, primary, 0x3ca, primary, primary, 0x0c0, primary, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0 xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
Well, let's write the source program for byte computing:Copy codeThe Code is as follows: unsigned char test [16] = {0x00,0x11,0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
Unsigned char len = 16;
Unsigned int crc_table [1, 256] = {
X0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, large, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, large, 0x3a33, 0x2a12, 0 xdbfd, 0 xcbdc, 0 primary, 0xeb9e, 0x9b79, primary, 0xbb3b, 0xab1a, primary, 0x5cc5, primary, 0x3c03, 0x0c0, 0x1c41, 0 xedae, 0xfd8f, 0 xcdec, 0 xddcd, 0xad2a, primary, 0x8d68, 0x9d49, 0x7e97, primary, 0x1e51, 0x0e70, 0xff9f, 0 xefbe, 0 xdfdd, 0 xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, primary, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0xb5ea, 0xa5cb, 0x95a8, 0x7256, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0 xabbb, 0xbb9a, 0x4a75, primary, 0x6a37, 0x7a16, primary, 0xdd6c, 0xcd4d, 0 primary, 0xad8b, primary, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, primary, 0x3ca, primary, primary, 0x0c0, primary, 0xff3e, 0xcf5d, 0xdf7c, primary, 0 xbfba, primary, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 };
Void main (void)
{
Unsigned int crc = 0;
Unsigned char crc_H8;
Unsigned char * ptr = test;
While (len --){
Crc_H8 = (unsigned char) (crc> 8 );
Crc = crc <8;
Crc = crc ^ crc_table [crc_H8 ^ * ptr];
Ptr ++;
}
Printf ("0x % x", crc );
}
4. calculate CRC in half bytes
Do you think the table above is too big or not so nice? Let's make some improvements. We will not go into details about the principles of the semi-byte calculation. The procedure is as follows:
Copy codeThe Code is as follows: unsigned char test [16] = {0x00,0x11,0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
Unsigned char len = 16;
Unsigned int crc_table [16] =
{0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef
};
Void main (void)
{
Unsigned int crc = 0;
Unsigned char crc_H4;
Unsigned char * ptr = test;
While (len --)
{
Crc_H4 = (unsigned char) (crc> 12 );
Crc = crc <4;
Crc = crc ^ crc_table [crc_H4 ^ (* ptr> 4)];
Crc_H4 = (unsigned char) (crc> 12 );
Crc = crc <4;
Crc = crc ^ crc_table [crc_H4 ^ (* ptr & 0x0f)];
Ptr ++;
}
Printf ("0x % x", crc );
}