理解和运用MAXIM IBUTTON产品中的循环冗余校验(CRC)


摘要 : 全部1-Wire器件,包括iButton器件,都具有唯一的8字节注册码,储存在只读存储器(ROM)中。该注册码在1-Wire总线上用作唯一的网络地址。为确保数据通信的完整性,每个注册码的一个字节是一个DOW CRC字节。本篇应用笔记说明了8位DOW CRC的计算方法以及用于验证器件存储器记录的16位CRC的计算。DOW CRC和CRC-16还会在选择1-Wire器件验证数据的硬件中产生。
 

引言

Maxim的iButton系列产品是通过单线按照1-Wire协议传送特定命令序列,进行数据通信。该系列产品都有个很重要的特性,就是在出厂前每个器件都被写入了唯一的8字节ROM码。其ROM码组成如图1所示,最低有效字节为家族代码,代表iButton器件的类型,如:DS1990A的家族码为01,DS1991的家族码为02。由于在同一条1-Wire总线上可同时挂接多个相同系列或不同系列的1-Wire器件,因此主机必须能够决定如何正确地访问位于1-Wire总线上的各个器件,这一点尤为重要。家族码提供器件的类型,随后的6个字节是器件的唯一序列号,用以区分同一个系列的不同器件。该序列号可作为1-Wire总线上器件的“地址”,这样1-Wire总线上的所有器件连同主机就构成了一个微型局域网(MicroLAN),它们之间通过一条公共线来进行通信。1-Wire器件ROM码的最高有效字节是循环冗余校验(CRC)码,该值基于前面的7个字节数据。当系统主机开始与某个器件进行通信时,可以读取8个ROM字节,低位在前。如果主机计算出的CRC码与ROM数据本身所含的CRC码相同,则通信有效;反之,则表明有错误发生,需重新读取器件的ROM码。


图1. 采用DOW CRC的iButton系统配置

有些iButton器件除了8字节ROM外,还具有高达8kB的RAM,主机可以通过适当的命令进行访问。即使iButton器件本身不带CRC硬件电路,如果主机具有为ROM码计算CRC值的能力,就可以采用CRC技术,开发一个访问器件RAM部分的子程序。数据按正常模式写入器件,主机将计算出的CRC结果附在数据后面,与数据一起保存。当从iButton器件读入数据时,则执行相反的过程。主机将计算出的CRC值与存储器中存储的CRC进行比较,如果相同,则认为从iButton接收的数据有效。为了充分利用CRC来验证1-Wire总线上进行的串行通信的有效性,用户有必要了解一下CRC的概念和工作原理。此外,无论是基于硬件实现还是软件实现,还需要掌握通过主机计算CRC的实用计算方法。

背景知识

有多种串行数据的检错方法,一种常用的方法是在被检测的数据包中包含一个附加位,用于指示是否出错。如:对于8位ASCII字符来说,可在其ASCII字符串后添加一位用于检错。假设数据为11010001,可以附加第9位,使数据中"1"的位数为奇数个。这样,应该附加1,数据包就变为:111010001,其中带下划线的字符为所要求的奇偶校验位,使全部9位数据中1的位数为奇数。如果收到的数据为:111010001,则认为接收到的信息有效;但是,若收到的数据为:111010101,即左边第七位接收错误,此时数据中"1"的个数就不再是奇数,则表明发生了错误,进而采取相应的措施,这种校验方法称作奇校验。与之类似,如果要求数据中1的个数总为偶数,则称为偶检验。但是这种检验方式有其局限性,它只能检查出数据中的奇数个错误。在上例中,如果收到的数据为:111011101,其中从左边数第6位和第7位都是错的,但此时奇偶检测结果却是正确的。对于这类错误,因此无论采用奇校验还是偶校验,都不能够检测出来。

详述

Maxim 1-Wire器件的CRC

在串行数据流中发现错误的最有效检错方案是循环冗余校验(CRC),并且所要求的硬件最少。这里主要介绍Maxim器件的CRC校验的工作及特性,暂不涉及详细的数学定义和描述。包含在CRC特性之后的数学概念在参考资料中进行了详细介绍。由于CRC实际上是由硬件实现,因此很容易理解CRC功能,通常CRC表示为带反馈的移位寄存器,如图2所示。另一种方式,也可将CRC看成是变量X的多项式,每一项的系数为二进制数,这些系数与移位寄存器的反馈通道直接对应。硬件方案中的移位寄存器的阶数,或多项式中的最高幂次就是将要计算CRC的位数。通常数字通信中使用的CRC编码方式有CRC-16和CRC-CCITT,它们产生的CRC码都为16位。Maxim的1-Wire CRC (DOW CRC)的位数是8位,用于1-Wire器件的64位ROM码的检错,该ROM码包括:最低有效字部分的8位家族码、与最低有效字节紧挨着的6字节48位唯一序列号、位于最高有效字节是前56位ROM码所计算出的CRC校验码。图2中,异或门构成的反馈路径(多项式的系数)决定了CRC检错性能和错误定位性能。DOW CRC可检测到以下几种错误:

  1. 任意64位数据中的奇数个错误。
  2. 所有64位数据中的双位错误。
  3. 包含在8位"window" (1至8位错误)中的任何字符串的错误。
  4. 绝大多数长字符串的错误。

如图2所示,输入数据是与移位寄存器的第8阶输出进行异或,移位寄存器在数学上可被视为除法电路,其中输入数据为被除数,反馈移位寄存器为除数,计算所得的商数在这里没有价值,计算后的余数就是指定数据流的CRC码。当最后一位数据移入之后,移位寄存器的值就是最后的余数。通过用移位寄存器来实现CRC的方案不难看出,最后得到的结果(CRC码)是根据要发送的所有数据,通过一种非常复杂的过程获得的,故此,这种校验算法基本上可以检测出数据中大多数的错误,只有极少数特别极端情况的差错无法检测到。


图2. Maxim 1-Wire 8位CRC

例2所示是当所有数据都移入之后计算出的CRC码。在计算开始时移位寄存器全置为‘0’,计算由64位ROM的LSB位开始,本例中家族码为02。当56位数据(序列号加上家族码)都移入后,移位寄存器的的值变为A2,这就是输入数据流的DOW CRC码。如果把计算得到的CRC码(A2)的8个位接在数据流的后面继续移入移位寄存器,那么当64位数据全部输入后,移位寄存器的值就全部为0。在DOW CRC算法中,就是利用这样一个特性来检查是否发生了错误的。把任意的8位数据移入移位寄存器到得到的8位数字接在移入的数据的后面继续移入移位寄存器,那么第8位数据位移入后的移位寄存器的结果总为00,通过观察不难注意到,移位寄存器的第8阶的值总是和输入的数据位相等,这样就使得用来控制反馈的异或门的输出和移位寄存器第一阶的下一个状态总为逻辑0,这样一来,当数据移入时,从左到右移入的每一位都是0,直到第8位后移位寄存器的每一位都被置0为止。Maxim 1-Wire 64位ROM就是利用上述特性来简化64位ROM的硬件设计的。主机端的移位寄存器首先被清0,然后读取包括CRC码在内的64位ROM。如果读取正确,则移位寄存器为零,易于检测。如果移位寄存器的值不是全部为0,则(表示发生了错误)必须重新读取数据。

到现在为止,我们一直围绕CRC硬件实现方法进行讨论,当然,与硬件方法等价的软件解决方案,则是另一种计算DOW CRC码的实现方法。如何编写程序代码如例1示例所示。需注意的是,寄存器A与常量18的异或运算是为了实现DOW CRC中第4、5阶之后的的异或反馈门,如图2所示。另一种软件实现方案就是简单地构建一个查询表,可以根据CRC寄存器中的8位值和新的8位数据直接读取。对于CRC寄存器为00的这种简单情况,可以推出输入数据的256种不同的组合,并将它们保存距阵中,该距阵索引值等于输入数据(即索引值为:I = 0至255)。很明显,如果CRC寄存器的当前值不是00,那么对于任一个当前CRC码和输入字来说,其查询表的值与CRC寄存器为0的简单情况相同,但表的索引值计算方式应改为:

新CRC = 表[I],I = 0至255 ;
这里,I = (当前CRC) EXOR (输入字)。

当CRC寄存器的当前值为00时,该等式就和上述简单情况一样。由于第二种方案是以字节为基础进行操作,而不是上例中面向位的操作,因此可以节省计算时间。但该方法会占用存储器的空间,因为查询表是存储在存储器中的,占用256字节,而在第一种方案中除了程序代码外,不再需要占用任何存储空间。例3为第二种方案的程序代码示例,表1给出了上例中查询表实现方法。在生成CRC码时,DOW CRC的两个特性有助于其代码的调试,其中的第一个特性在硬件实现时已介绍过,即:如果下一个输入数据等于当前CRC寄存器值,则计算后的CRC码肯定为00 (见前面的说明)。其第二个特性也能够用于确认代码是否正确,出现在输入数据等于当前CRC寄存器的反码时。对于DOW CRC算法来说,计算出的CRC码将为35H,即十进制的53 。当输入数据为CRC寄存器反码时,通过观察CRC寄存器工作方式,就可以解释这种特性,如表2所示。

例1. 汇编语言程序

DO_CRC:	PUSH ACC	;save accumulator
PUSH B ;save the B register
PUSH ACC ;save bits to be shifted
MOV B,#8 ;set shift = 8 bits ; CRC_LOOP: XRL A,CRC ;calculate CRC
RRC A ;move it to the carry
MOV A,CRC ;get the last CRC value
JNC ZERO ;skip if data = 0
XRL A,#18H ;update the CRC value
;
ZERO: RRC A ;position the new CRC
MOV CRC,A ;store the new CRC
POP ACC ;get the remaining bits
RR A ;position the next bit
PUSH ACC ;save the remaining bits
DJNZ B,CRC_LOOP ;repeat for eight bits
POP ACC ;clean up the stack
POP B ;restore the B register
POP ACC ;restore the accumulator
RET

例2. DOW CRC算法举例

CRC Value Input Value
00000000 0
00000000 1
10001100 0       2
01000110 0       
00100011 0
10011101 0
11000010 0       0
01100001 0       
10111100 0
01011110 0
00101111 1       C
00010111 1       
00001011 1
00000101 0
10001110 0       1
01000111 0       
10101111 0
11011011 0
11100001 0       8
11111100 1       
11110010 1
11110101 1
01111010 0       B
00111101 1       
00011110 1
10000011 0
11001101 0       1
11101010 0       
01110101 0
10110110 0
01011011 0       0
10100001 0       
11011100 0
01101110 0
00110111 0       0
10010111 0       
11000111 0
11101111 0
11111011 0       0
11110001 0       
11110100 0
01111010 0
00111101 0       0
10010010 0       
01001001 0
10101000 0
01010100 0       0
00101010 0       
00010101 0
10000110 0
01000111 0       0
10101101 0       
11011010 0
01101101 0
10111010 0       0
01011101 0       
10100010 = A2 Hex = CRC Value for [00000001B81C (Serial Number) + 02 (Family Code)]
10100010 0
01010001 1
00101000 0       2
00010100 0       
00001010 0
00000101 1
00000010 0       A
00000001 1       
00000000 = 00 Hex = CRC Value for A2 [(CRC) + 00000001B81C (Serial Number) + 02 (Family Code)]

例3. DOW CRC查询函数

Var
CRC : Byte;
Procedure Do_CRC(X: Byte);
{
This procedure calculates the cumulative Maxim 1-Wire CRC of all bytes passed to it.
The result accumulates in the global variable CRC.
}
Const
Table : Array[0..255] of Byte = ( 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53); Begin
CRC := Table[CRC xor X];
End;

表1. 查表方式计算DOW CRC

Current CRC Value (= Current Table Index) Input Data New Index (= Current CRC xor Input Data) Table (New Index) (= New CRC Value)
0000 0000 = 00 Hex 0000 0010 = 02 Hex (00 H xor 02 H) = 02 Hex = 2 Dec Table[2]= 1011 1100 = BC Hex = 188 Dec
1011 1100 = BC Hex 0001 1100 = 1C Hex (BC H xor 1C H) = A0 Hex = 160 Dec Table[160]= 1010 1111 = AF Hex = 175 Dec
1010 1111 = AF Hex 1011 1000 = B8 Hex (AF H xor B8 H) = 17 Hex = 23 Dec Table[23]= 0001 1110 = 1E Hex = 30 Dec
0001 1110 = 1E Hex 0000 0001 = 01 Hex (1E H xor 01 H) = 1 F Hex = 31 Dec Table[31]= 1101 110 = DC Hex = 220 Dec
1101 1100 = DC Hex 0000 0000 = 00 Hex (DC H xor 00 H) = DC Hex = 220 Dec Table[220]= 1111 0100 = F4 Hex = 244 Dec
11110100 = F4 Hex 0000 0000 = 00 Hex (F4 H xor 00 H) = F4 Hex = 244 Dec Table [244]= 0001 0101 = 15 Hex = 21 Dec
0001 0101 = 15 Hex 0000 0000 = 00 Hex (15 H xor 00 H) = 15 Hex = 21 Dec Table[21]= 1010 0010 = A2 Hex = 162 Dec
1010 0010 = A2 Hex 10100010 = A2 Hex (A2 H xor A2 H) = Hex = 0 Dec Table[0]=0000 0000 = 00 Hex = 0 Dec

带有CRC寄存器1的补码CRC寄存器

表2. CRC寄存器值输入

X0 X1 X2 X3 X4 X5 X6 X7 X7*
1 X0 X1 X2 X3* X4* X5 X6 X6*
1 1 X0 X1 X2* X3 X4* X5 X5*
1 1 1 X0 X1* X2* X3 X4* X4*
0 1 1 1 X0 X1* X2 X3 X3*
1 0 1 1 0 X0* X1* X2 X2*
1 1 0 1 0 1 X0* X1* X1*
0 1 1 0 1 0 1 X0* X0*
0 0 1 1 0 1 0 1 Final CRC Value = 35 Hex, 53 Decimal

注释:Xi* = Xi的反码

iButton RAM中CRC-16的算法

如前所述,一些iButton器件除了内部唯一的8字节ROM码,还有RAM存储器。与内部的8字节ROM码相比,RAM中存储的数据量要大得多,因此Maxim推荐使用16位CRC码而不是ROM所使用的8位DOW CRC,以确保数据的完整性。这种特殊的16位CRC通常称为CRC-16。图3给出了这种16位CRC的移位寄存器的硬件实现图和相应的多项表达式,图中的移位寄存器有16阶,其表达式也有16次幂项。如前所述,iButton器件自身并不产生CRC码,而是由主机生成16位CRC码并将其附加在实际数据之后。由于iButton的“通信通道”,如两个金属接触面,存在不确定性,数据传输可能会出现一些错误,分为三类:第一,短暂的连接中断引起的数据传输中小部分数据位出错,CRC-16可检测出这类错误;第二类错误是完全脱离接触引起的,如:当iButton器件快速移离读写头时。

将导致后续部分的读入数据为逻辑1,这是因为未连接iButton器件时,主机将解释所有的接收数据为1。 CRC-16在大多数情况下可以检测出这类错误。第三类错误是由读写头短路引起的,这可能因为iButton器件没有正确插入或iButton器件在阅读器内大幅度翘起导致的。读写头短路会使主机把数据全读为0,此时采用CRC进行校验时,就会出现问题。由于确认数据是否有效的方法是判断主机在读取数据和附加的CRC之后,计算出的CRC码是否全为0000H (采用16位CRC)。当阅读器短路时,读到的数据和CRC值全部为0,此时读操作已经出错,但由主机计算出的CRC值将错误地指示该读操作是有效的。为了避免这种情况的发生,Maxim推荐将CRC-16反码(CRC-16*)随同数据一起写入RAM。当采用无补码的CRC-16时,iButton的数据验证过程与DOW CRC相似,即,主机把CRC寄存器初始化成0000H,然后从iButton读取全部数据和存储的CRC-16,则最终计算出来的结果应为0000H。如果采用CRC-16*,在iButton中保存的就是CRC-16的反码和数据。进行CRC校验时,主机同样把CRC寄存器初始化成0H,然后从iButton读取数据和CRC-16*,如果操作没有错误的话,最后的结果应该是B001H。这样大大地提高了系统可靠性,读写头短路造成的错误就不会被漏检。至于为什么CRC-16具有这些特性,可通过与之相似的DOW CRC的分析(见图3和图5)来解释。在理论上16位CRC的操作与此前介绍的8位CRC完全相同,只是由于采用的是16的CRC,性能有所改善。对于CRC-16函数,可以检测到以下几类错误:

  1. 任何数据记录中的奇数个错误。
  2. 任何数据记录中的双位错误。
  3. 包含在16位"window" (1至16错误)中的任何字符串的错误。
  4. 绝大多数长字符串的错误。


图3. CRC-16硬件实现及其多项式表示

图3给出了CRC-16函数的硬件实现图,例4则列出了与其硬件相对应的软件实现方案,采用位操作计算CRC-16值。之前很少有高效的查询表软件解决方案,8位DOW CRC查询表的基础概念也同样适用于CRC-16,只需对8位的程序稍加改动即可。但是,如果仍然采用DOW CRC实现方法的话,要把CRC-16全部16位结果全部放进一个查询表,则表中就会有216也就是65536个记录(占用的空间将会很大)。与DOW CRC不同的实现方法如例5所示,图中采用两个256位表来计算和存储16位CRC值,其中一个表包含CRC的高8位,另一个存放低8位。任何一个16位CRC都可以分为代表高8位的Current_CRC16_Hi和代表低8位的Current_CRC16_Lo两部分。对于任何一个输入字节,在高阶字节表中决定新的CRC值高阶字节(New_CRC16_Hi)的索引计算公式如下:

New_CRC16_Hi = CRC16_Tabhi[I], I = 0至255; 这里:I = (Current_CRC16_Lo) EXOR (输入字)

在低阶字节表中决定新的CRC值低阶字节(New_CRC16_Lo)的索引计算公式如下: 

New_CRC16_Lo = (CRC16_Tablo[I]) EXOR (Current_ CRC16_Hi) I = 0至255;
这里:I = (Current_CRC16_Lo) EXOR (输入字)

图4所示为如何实现该方法的一个实例。

例4. 计算CRC-16的汇编语言程序

crc_lo data 20h ; lo byte of crc calculation (bit addressable)
crc_hi data 21h ; hi part of crc calculation ;---------------------------------------------------------------------------
; CRC16 subroutine.
; - accumulator is assumed to have byte to be crc'ed
; - two direct variables are used crc_hi and crc_lo
; - crc_hi and crc_lo contain the CRC16 result
;---------------------------------------------------------------------------
crc16: ; calculate crc with accumulator
push b ; save value of b
mov b, #08h ; number of bits to crc.
crc_get_bit:
rrc a ; get low order bit into carry
push acc ; save a for later use
jc crc_in_1 ;got a 1 input to crc
mov c, crc_lo.0 ;xor with a 0 input bit is bit
sjmp crc_cont ;continue
crc_in_1:
mov c, crc_lo.0 ;xor with a 1 input bit
cpl c ;is not bit.
crc_cont:
jnc crc_shift ; if carry set, just shift
cpl crc_hi.6 ;complement bit 15 of crc
cpl crc_lo.1 ;complement bit 2 of crc
crc_shift
mov a, crc_hi ; carry is in appropriate setting
rrc a ; rotate it
mov crc_hi, a ; and save it
mov a, crc_lo ; again, carry is okay
rrc a ; rotate it
mov crc_lo, a ; and save it
pop acc ; get acc back
djnz b, crc_get_bit ; go get the next bit
pop b ; restore b
ret
end

例5. 利用查找表进行CRC-16计算的汇编程序

crc_lo data 40h	; any direct address is okay
crc_hi data 41h
tmp data 42h ;---------------------------------------------------------------------------
; CRC16 subroutine.
; - accumulator is assumed to have byte to be crc'ed
; - three direct variables are used, tmp, crc_hi and crc_lo
; - crc_hi and crc_lo contain the CRC16 result
; - this CRC16 algorithm uses a table lookup
;---------------------------------------------------------------------------
crc16:
xrl a, crc_lo ; create index into tables
mov tmp, a ; save index
push dph ; save dptr
push dpl ;
mov dptr, #crc16_tablo ; low part of table address
movc a, @a+dptr ; get low byte
xrl a, crc_hi ;
mov crc_lo, a ; save of low result
mov dptr, #crc16_tabhi ; high part of table address
mov a, tmp ; index
movc a, @a+dptr ;
mov crc_hi, a ; save high result
pop dpl ; restore pointer
pop dph ;
ret ; all done with calculation
crc16_tablo:
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 000h, 0c1h, 081h, 040h, 001h, 0c0h, 080h, 041h
db 001h, 0c0h, 080h, 041h, 000h, 0c1h, 081h, 040h
crc16_tabhi:
db 000h, 0c0h, 0c1h, 001h, 0c3h, 003h, 002h, 0c2h
db 0c6h, 006h, 007h, 0c7h, 005h, 0c5h, 0c4h, 004h
db 0cch, 00ch, 00dh, 0cdh, 00fh, 0cfh, 0ceh, 00eh
db 00ah, 0cah, 0cbh, 00bh, 0c9h, 009h, 008h, 0c8h
db 0d8h, 018h, 019h, 0d9h, 01bh, 0dbh, 0dah, 01ah
db 01eh, 0deh, 0dfh, 01fh, 0ddh, 01dh, 01ch, 0dch
db 014h, 0d4h, 0d5h, 015h, 0d7h, 017h, 016h, 0d6h
db 0d2h, 012h, 013h, 0d3h, 011h, 0d1h, 0d0h, 010h
db 0f0h, 030h, 031h, 0f1h, 033h, 0f3h, 0f2h, 032h
db 036h, 0f6h, 0f7h, 037h, 0f5h, 035h, 034h, 0f4h
db 03ch, 0fch, 0fdh, 03dh, 0ffh, 03fh, 03eh, 0feh
db 0fah, 03ah, 03bh, 0fbh, 039h, 0f9h, 0f8h, 038h
db 028h, 0e8h, 0e9h, 029h, 0ebh, 02bh, 02ah, 0eah
db 0eeh, 02eh, 02fh, 0efh, 02dh, 0edh, 0ech, 02ch
db 0e4h, 024h, 025h, 0e5h, 027h, 0e7h, 0e6h, 026h
db 022h, 0e2h, 0e3h, 023h, 0e1h, 021h, 020h, 0e0h
db 0a0h, 060h, 061h, 0a1h, 063h, 0a3h, 0a2h, 062h
db 066h, 0a6h, 0a7h, 067h, 0a5h, 065h, 064h, 0a4h
db 06ch, 0ach, 0adh, 06dh, 0afh, 06fh, 06eh, 0aeh
db 0aah, 06ah, 06bh, 0abh, 069h, 0a9h, 0a8h, 068h
db 078h, 0b8h, 0b9h, 079h, 0bbh, 07bh, 07ah, 0bah
db 0beh, 07eh, 07fh, 0bfh, 07dh, 0bdh, 0bch, 07ch
db 0b4h, 074h, 075h, 0b5h, 077h, 0b7h, 0b6h, 076h
db 072h, 0b2h, 0b3h, 073h, 0b1h, 071h, 070h, 0b0h
db 050h, 090h, 091h, 051h, 093h, 053h, 052h, 092h
db 096h, 056h, 057h, 097h, 055h, 095h, 094h, 054h
db 09ch, 05ch, 05dh, 09dh, 05fh, 09fh, 09eh, 05eh
db 05ah, 09ah, 09bh, 05bh, 099h, 059h, 058h, 098h
db 088h, 048h, 049h, 089h, 04bh, 08bh, 08ah, 04ah
db 04eh, 08eh, 08fh, 04fh, 08dh, 04dh, 04ch, 08ch
db 044h, 084h, 085h, 045h, 087h, 047h, 046h, 086h
db 082h, 042h, 043h, 083h, 041h, 081h, 080h, 040h


图4. CRC-16计算和查表方法的比较

例6描述了一种令人感兴趣的的中间方案。该程序利用图5所示的公式,通过对当前整个CRC的值和输入字节进行运算来生成CRC-16。同时在图中还给出了该等式的推导过程,用字母字符表示当前16位CRC值,用数字字符表示输入字节的位。8次移位后就得到了所示的等式,这些等式随后可以预计算出大部分的新CRC值。注意:例如ABCDEFGH01234567 (定义为所有位异或的结果)数字量等于输入数据和当前CRC低字节的奇偶性。与前面的按位计算或查表方法相比较,这种方法可以减少计算时间,或减少存储空间。最后,应说明的是,前面介绍的CRC-16函数的两种特性在这里也用作调试准则。其第一个特性与DOW CRC的情况完全相同,即如果当前CRC寄存器的16位内容作为后续的16位输入数据,则得到的CRC也总为0000H。CRC功能的第二个特性与DOW CRC相似,如果把当前CRC寄存器的16位反码也作为后续的16位输入数据,则CRC结果总为B0 01H。这两个CRC-16特性的证明方法也与DOW CRC相似。

例6. 高速CRC-16算法的汇编语言程序

lo equ 40h ; low byte of CRC
hi equ 41h ; high byte of CRC crc16:
push acc ; save the accumulator.
xrl a, lo
mov lo, hi ; move the high byte of the CRC.
mov hi, a ; save data xor low(crc) for later
mov c, p
jnc crc0
xrl lo, #01h ; add the parity to CRC bit 0
crc0:
rrc a ; get the low bit in c
jnc crc1
xrl lo, #40h ; need to fix bit 6 of the result
crc1:
mov c, acc.7
xrl a, hi ; compute the results for other bits.
rrc a ; shift them into place
mov hi, a ; and save them
jnc crc2
xrl lo, #80h ; now clean up bit 7
crc2:
pop acc ; restore everything and return
ret


详细图片
(GIF)
图5. 高速CRC-16的计算方法

18B20的CRC官方讲解的更多相关文章

  1. 让 http 2来得更猛烈些吧

    今早在公交车上,把http2的官方讲解文档(还在草案之中)看了一圈,发现相对http 1.1确实改进了不少,完整的文档可通过:://www.gitbook.com/book/ye11ow/http2- ...

  2. 移动h5开发资源整理

    这2年来,移动h5开发逐渐成为一种主流,也不断趋向于成熟.硬件和浏览器的不断更新,曾经的浏览器兼容也不再是开发者的噩梦. 接触h5开发一年多,从最初的新手到现在,陆陆续续遇到过很多坑.这里把想到的一些 ...

  3. WCF学习资料汇总

    微软官方讲解教程: 跟我一起从零开始学WCF系列课程 http://msdnwebcast.net/webcast/1/2692/ 构建WCF面向服务的应用程序系列课程 http://msdnwebc ...

  4. 开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发

    [原][开源框架]Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位... 时间 2015-01-05 10:08:18 我是程序猿,我为自己代言 原文  http: ...

  5. RHEL 集群(RHCS)配置小记 -- 文档记录

    1.RHEL 6 集群配置官方管理手册 https://access.redhat.com/site/documentation/zh-CN/Red_Hat_Enterprise_Linux/6/pd ...

  6. Android 第三方开源库收集整理(转)

    原文地址:http://blog.csdn.net/caoyouxing/article/details/42418591 Android开源库 自己一直很喜欢Android开发,就如博客签名一样,  ...

  7. Android精品开源整理

    一.兼容类库 ActionBarSherlock : Action Bar是Android 3.0后才开始支持的,ActionBarSherlock是让Action Bar功能支持2.X后的所有平台, ...

  8. jQuery常用技巧-使用的总结

    1.关于页面元素的引用 通过jquery的$()引用元素包括通过id.class.元素名以及元素的层级关系及dom或者xpath条件等方法,且返回的对象为jquery对象(集合对象),不能直接调用do ...

  9. 最火的Android开源项目整理

    一.代码库   1.from  代码家 整理比较好的源码连接   ******************************************************************* ...

  10. 【转】android的一些开源项目

    自己一直很喜欢Android开发,就如博客副标题一样,我想做个好的App. 在摸索过程中,GitHub上搜集了很多很棒的Android第三方库,推荐给在苦苦寻找的开发者,而且我会不定期的更新这篇文章. ...

随机推荐

  1. 华为云大咖说:开发者应用AI大模型的“道、法、术”

    本文分享自华为云社区<华为大咖说 | 企业应用AI大模型的"道.法.术" --道:认知篇>,作者:华为云PaaS服务小智. 本期核心观点 上车:AGI是未来5-10年内 ...

  2. (JAVA)设计模式-适配器模式

    模式的定义和特点: 适配器模式(Adapter)是一种将一个类的接口转换成客户希望的另外一个接口的设计模式,可以提高代码的复用性和灵活性. 结构与实现: 定义一个适配器类来实现业务接口,再继承现有组件 ...

  3. itest(爱测试) 开源接口测试,敏捷测试管理平台10.1.0发布

    一:itest work 简介 itest work 开源敏捷测试管理,包含极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock,还有压测 ,又有丰富的统计分析,8合1工作站.可按 ...

  4. vue3 elementui plus Select 选择器不选择下拉框里面的数据得到的value值

    我们先来看 我点击弹框出现什么都不做 直接点击确定 看传参 tableId,timeColumnId,userColumnId直接是名称而没有获取value值 看下下拉框里面的数据 而我想直接点击获取 ...

  5. react兄弟之间通信

    写入组件 import React, { Component } from 'react'//下面二个就是兄弟关系的组件 import Cmp1 from '../Child/Cmp1' import ...

  6. C#.NET 国密 SM2 公钥证书从文本转换

    先前的 Util 是直接从文件中转换的 https://www.cnblogs.com/runliuv/p/15079404.html public static AsymmetricKeyParam ...

  7. Scrapy框架(十)--增量式爬虫

    增量式爬虫 - 概念:监测网站数据更新的情况,只会爬取网站最新更新出来的数据. - 分析: - 指定一个起始url - 基于CrawlSpider获取其他页码链接 - 基于Rule将其他页码链接进行请 ...

  8. JavaScript中如何终止forEach循环&跳出for(双层)循环?

    在JavaScript中,forEach方法是用于遍历数组的,通常没有直接终止循环的机制.然而,我们可以使用一些技巧来模拟终止forEach循环.以下是几种常见的方法 1.使用return语句:在fo ...

  9. 【ASeeker】Android 源码捞针,服务接口扫描神器

    ASeeker是一个Android源码应用系统服务接口扫描工具. 项目已开源: ☞ Github ☜ 如果您也喜欢 ASeeker,别忘了给我们点个星. 说明 ASeeker 项目是我们在做虚拟化分身 ...

  10. 算法金 | A - Z,115 个数据科学 机器学习 江湖黑话(全面)

    大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 机器学习本质上和数据科学一样都是依赖概率统计,今天整整那些听起来让人头大的机器学习江湖 ...