应用笔记 4600

简单软件实现1-Wire®温度器件的硬件CRC校验和串行码流的误码检测

By: Hrishikesh Shinde

摘要 : 所有1-Wire温度器件均包含一个唯一的识别码,保存在只读存储器(ROM)内,该识别码在1-Wire总线中用作唯一的网络地址。另外,部分温度器件的暂存器还有一个CRC (循环冗余校验)字节用于1-Wire通信验证。本应用笔记以及附带的程序提供了一种简单途径,验证1-Wire器件之间通信的正确性,并检测串行数据流的误码。这种方法能够在每个器件中通过软件计算DOW (Dallas单线) CRC,并与器件的硬件CRC值进行对比。本文将以DS1822经济型1-Wire数字温度计为例进行说明。

CRC算法

CRC (循环冗余校验)是串行数据流中检测误码最有效的方法,CRC校验能够使用户确保温度检测器件之间的数据传输正确,该方法对硬件需求最小。DOW (Dallas单线) CRC用于Maxim的1-Wire温度检测产品,例如:DS1821DS1822DS18B20。DOW CRC可以利用下列多项式表示:
多项式 = X8 + X5 + X4 + 1
详细的CRC算法,请参考应用笔记27:“理解和运用Maxim iButton®产品中的循环冗余校验(CRC)”。

从以下硬件电路的功能可以很容易理解CRC,通常表示为带反馈的移位寄存器,图1给出了DS1822的硬件电路框图。

图1. CRC硬件模型
图1. CRC硬件模型

ROM码CRC

每个DS1822都在其ROM中保存了一个唯一的8字节识别码,该ROM码的最低有效字节为DS1822的1-Wire家族码:22h。随后6个字节是唯一的序列号,最高有效字节为CRC字节,由ROM码的前面7个字节计算得到。

暂存器CRC

DS1822暂存器的前8个字节为高温、低温门限以及配置寄存器。这些字节还包括DS1822读取的温度值和保留备用的寄存器。第9个字节是由前8个字节计算得到的CRC值。

用于暂存器和ROM的CRC字节的计算方法相同,请参考应用笔记27。图1中的移位寄存器的初始条件为每位数值均为零。LSB首先移入寄存器,当所有位均移入寄存器后,其结果即为特定数据的CRC值。总之,ROM码需要移入56位(7字节)数据,暂存器需要移入64位(8字节)数据。

硬件CRC校验

DS1822具有CRC硬件电路,可以为ROM码或暂存器提供CRC计算,该值将传送到1-Wire总线。接收到的数据可能被通信接口破坏,利用软件计算的CRC可以检验接收到的数据包(ROM码为8字节,暂存器为9字节)是否正确。

可使用Microsoft® Excel表格(采用Microsoft Excel 2003)计算DS1822的CRC值,图2给出了一个屏幕截图示例。

图2. Excel CRC计算器屏幕截图示例
图2. Excel CRC计算器屏幕截图示例

用户输入ROM码的最后7个字节或暂存器的前8个字节后,按下“Calculate CRC”按钮,即可得到对应的CRC值,这些数值可以用来与硬件给出的结果进行比较。

用于开发该Excel电子表的VBA程序如下。


Private Sub ROMCRC_Click()
    
    Dim InHex, OutBinStr As String
    Dim OutBinArr(1 To 56) As Integer
    Dim OutDec, i, CRC(1 To 8), CRCTemp As Integer
    
    InHex = Range("ROMByte1").Value & Range("ROMByte2").Value &
      	Range("ROMByte3").Value & Range("ROMByte4").Value &
      	Range("ROMByte5").Value & Range("ROMByte6").Value &
      	Range("ROMByte7").Value
    OutBinStr = HexToBin(InHex)
    
    ' Convert string to array, LSB = OutBinArr(1)
    For i = 1 To 56
        OutBinArr(57 - i) = Mid$(OutBinStr, i, 1) ' Split(OutBinStr)
    Next i
    
    'Initialize CRC
    For i = 1 To 8
        CRC(i) = 0
    Next i
    
    'Calculate CRC
    For i = 1 To 56
        CRCTemp = CRC(1) Xor OutBinArr(i)
        CRC(1) = CRC(2)
        CRC(2) = CRC(3)
        CRC(3) = CRC(4) Xor CRCTemp
        CRC(4) = CRC(5) Xor CRCTemp
        CRC(5) = CRC(6)
        CRC(6) = CRC(7)
        CRC(7) = CRC(8)
        CRC(8) = CRCTemp
    Next i
    
    DecCRC = BinToDec(CRC)
    
    Range("ROMCRCValue").Value = DecCRC

End Sub


Private Sub ScratchCRC_Click() Dim InHex, OutBinStr As String Dim OutBinArr(1 To 64) As Integer Dim OutDec, i, CRC(1 To 8), CRCTemp As Integer InHex = Range("HexByte1").Value & Range("HexByte2").Value & Range("HexByte3").Value & Range("HexByte4").Value & Range("HexByte5").Value & Range("HexByte6").Value & Range("HexByte7").Value & Range("HexByte8").Value OutBinStr = HexToBin(InHex) ' Convert string to array, LSB = OutBinArr(1) For i = 1 To 64 OutBinArr(65 - i) = Mid$(OutBinStr, i, 1) ' Split(OutBinStr) Next i 'Initialize CRC For i = 1 To 8 CRC(i) = 0 Next i 'Calculate CRC For i = 1 To 64 CRCTemp = CRC(1) Xor OutBinArr(i) CRC(1) = CRC(2) CRC(2) = CRC(3) CRC(3) = CRC(4) Xor CRCTemp CRC(4) = CRC(5) Xor CRCTemp CRC(5) = CRC(6) CRC(6) = CRC(7) CRC(7) = CRC(8) CRC(8) = CRCTemp Next i DecCRC = BinToDec(CRC) Range("DecCRCValue").Value = DecCRC End Sub
Private Function HexToBin(hstr) 'convert hex string to binary string cnvarr = Array("0000", "0001", "0010", "0011", _ "0100", "0101", "0110", "0111", "1000", _ "1001", "1010", "1011", "1100", "1101", _ "1110", "1111") bstr = "" For i = 1 To Len(hstr) hdgt = Mid(hstr, i, 1) cix = CInt("&H" & hdgt) bstr = bstr & cnvarr(cix) Next HexToBin = bstr End Function
Function BinToDec(bstr) 'convert 8 bit Binary number to Decimal Dim j, Out As Integer Out = 0 For j = 1 To 8 Out = Out + bstr(j) * 2 ^ (j - 1) Next j BinToDec = Out End Function

结论

计算CRC可以很容易地保证1-Wire器件之间的通信正确,对照基于软件的CRC结果和1-Wire器件的硬件CRC计算结果,从而保证1-Wire总线通信的可靠性。