
Introduction.
When data is communicated between two devices, it is common to use some type of error checking. Common examples are parity, a checksum and a cyclic redundancy check (CRC). The general idea is that the transmitter calculates and transmits a value and the receiver performs the same calculations and compares the result with the check value.
When interfacing with the Dallas 1820 1-wire digital thermometer, various commands are issued by the PIC to a specific DS1820 and data is then returned to the PIC as a series of nine bytes. Eight of these bytes contain data related to the temperature or are user bytes. The ninth and final byte is the cyclic redundancy check (CRC).
The DS1820 calculates this final CRC byte using a defined algorithm to operate on the other eight data bytes.
The receiving processor may then operate on the eight received data bytes using the same algorithm and compare this calculated CRC with that calculated by the DS1820. If the two do not agree, a transmission error has occurred and the designer may opt to structure the program so as to repeat the process until the two CRCs do agree.
Detailed Discussion.
The algorithm is based on the 8-bit shift register model as shown. Note that the shift register is initially cleared.
For each data bit received, the bit is exclusive ored with the least significant bit of the shift register. The result is termed the feedback bit. The feedback bit is then exclusive ored with bits 4 and 3 in the shift register, the shift register is shifted one place to the right and the feedback bit is inserted in the most significant bit position.
Thus, if the shift register was originally;
D7 D6 D5 D4 D3 D2 D1 D0
The new value is
FB D7 D6 D5 D4^FB D3^FB D2 D1
Where;
FB = D0 ^ data_bit
Another way of looking at this, is to calculate the feedback bit by exclusive oring the data bit with the least significant bit of the shift register. Then shift the shift register one place to the right. Thus, the most significant bit is now zero, former bits 4 and bits 3 are now in the bit 3 and bit 2 positions and then exclusive or bits 7, 3 and 2 with the feedback bit.
However, consider the truth table for the an exclusive or function.
LINE X Y Q
(1) 0 0 0
(2) 0 1 1
(3) 1 0 1
(4) 1 1 0
Note that in lines (1) and (3), that any quantity exclusive ored with a 0 is the quantity itself.
This, if the feedback bit is zero, there is no need to exclusive or bits 7, 3 and 2 with a zero. Bit 7 is already a logic zero, the value of the feedback bit. Exclusive oring bits 3 and 2 with a zero will produce the same values of bits 3 and 2.
Note that in lines (2) and (4), that any quantity exclusive ored with a logic one is the inverse of the original quantity. Thus, if the feed back bit is a logic one, one need only invert bits 7, 3 and 2. That is, after the shift, bit 7 is a logic zero. However, by exclusive oring it with a logic one, it becomes a one which is the value of the feedback bit. By exclusive oring bits 3 and 2 with a logic one, they are inverted.
Thus, a simple algorithm using the C language;
byte calc_CRC_bit (byte shift_reg, byte data_bit)
{
byte fb;
fb = (shift_reg & 0x01) ^ data_bit;
/* exclusive or least sig bit of current shift reg with the data bit */
shift_reg = shift_reg >> 1;
/ * shift one place to the right */
if (fb==1)
{
shift_reg = shift ^ 8C; /* CRC ^ binary 1000 1100 */
}
return(shift_reg);
}
The above routine is called for each byte received. Thus, in the case of the DS1820, eight bytes (64 data bits) are received and the above algorithm is applied 64 times. The result is the CRC value.
An interesting property of this algorithm is that if the shift register has a particular value and if the same byte value is then applied, the result will be zero.
For example, if after receiving 64 bits from the DS1820, assume the receiving processor has calculated the value of the shift register as 0x3C. The DS1820 will then send the calculated 8-bit CRC which will be 0x3C if no transmission errors have occurred. When the receiving processor applies the above algorithm to the additional eight bits, the result will be zero.
Thus, by applying this algorithm to the eight data bytes and then finally to the CRC byte, a result of zero indicates no transmission errors.
In the following program, the nine values received from the DS1820 are displayed on lines 1, 2 and 3 of the PIC-n-LCD display. The result of the CRC algorithm is displayed on line 4. Note that it should be zero.
In the CRC calculation, variable SHIFT_REG is initially cleared.
As each value is received from the DS1820, the byte is passed to CALC_CRC_BYTE which isolates each of the eight bits, beginning with the least significant and passes the value to CALC_CRC_BIT in variable DATA_BIT.
; Program 1820_CRC.ASM
;
; Performs temperature measurement. No addressing.
;
; Illustrates the calculation of the cyclic redundancy check (CRC).
;
; Program fetches the nine bytes from the DS1820. These are displayed
; on the PIC-n-LCD using the LCD module which is included near the end
; of this program.
;
; The CRC result is calculated and displayed.
;
; Although values are saved in a data buffer for later use, they are
; not used in this program.
;
; 16C84 DS1820
; PortB.0 (term 6) ------------------------------ DQ (term 2)
;
; PORTA, Bit 0 (terminal 17) ------ TX ----------> to RX on Serial LCD
;
;
; copyright, Peter H. Anderson, June, '98
LIST p=16f84
#include <c:\mplab\p16f84.inc>
__CONFIG 11h
CONSTANT DATA_PIN=0
CONSTANT BASE_VAR=0C
CONSTANT DATA_BUFF=28H
CONSTANT BUFF_SIZE=7
N EQU BASE_VAR+0
INDEX EQU BASE_VAR+1 ; these vars used by the
O_BYTE EQU BASE_VAR+2 ; common 1-wire routines
I_BYTE EQU BASE_VAR+3
TEMP EQU BASE_VAR+4
LOOP1 EQU BASE_VAR+5 ; used for timing
TEMP_1 EQU BASE_VAR+6 ; used for calculating CRC
DATA_BIT EQU BASE_VAR+7
SHIFT_REG EQU BASE_VAR+8
FB EQU BASE_VAR+9
TEMP_MSB EQU DATA_BUFF+0 ; first location in DATA_BUFF
TEMP_LSB EQU DATA_BUFF+1
TH_UB1 EQU DATA_BUFF+2
TL_UB2 EQU DATA_BUFF+3
COUNT_REM EQU DATA_BUFF+4
COUNT_D_C EQU DATA_BUFF+5
CRC EQU DATA_BUFF+6
ORG 000H
MAIN:
BSF STATUS, RP0
BCF TRISA, 0
BCF STATUS, RP0
BCF PORTA, 0 ; set serial output to idle
MOVLW 0CH ; clear the LCD
CALL LCD_CHAR
CALL INIT ; init DS1820
MOVLW 0CCH ; skip ROM
MOVWF O_BYTE
CALL OUT_BYTE
MOVLW 44H ; perform temperature conversion
MOVWF O_BYTE
CALL OUT_BYTE
CALL WAIT ; wait for conversion to complete
; wait for all ones from 1820
CALL INIT
MOVLW 0CCH ; skip ROM
MOVWF O_BYTE
CALL OUT_BYTE
MOVLW 0BEH ; read scratchpad
MOVWF O_BYTE
CALL OUT_BYTE
CLRF SHIFT_REG ; initialize the CRC calculation
MOVLW 0CH ; clear the LCD
CALL IN_BYTE ; get from DS1820 and save
MOVWF TEMP_MSB
CALL LCD_VAL ; display the value
CALL CALC_CRC_BYTE
MOVLW " " ; space
CALL LCD_CHAR
CALL IN_BYTE
MOVWF TEMP_LSB
CALL LCD_VAL
CALL CALC_CRC_BYTE
MOVLW " " ; space
CALL LCD_CHAR
CALL IN_BYTE
MOVWF TH_UB1
CALL LCD_VAL
CALL CALC_CRC_BYTE
MOVLW " " ; space
CALL LCD_CHAR
CALL IN_BYTE
MOVWF TL_UB2
CALL LCD_VAL
CALL CALC_CRC_BYTE
MOVLW 0DH ; new line on LCD
CALL LCD_CHAR
MOVLW 0AH
CALL LCD_CHAR
CALL IN_BYTE ; these two values are not saved in buffer
CALL LCD_VAL
CALL CALC_CRC_BYTE
MOVLW " "
CALL LCD_CHAR
CALL IN_BYTE
CALL LCD_VAL
CALL CALC_CRC_BYTE
MOVLW " "
CALL LCD_CHAR
CALL IN_BYTE
MOVWF COUNT_REM
CALL LCD_VAL
CALL CALC_CRC_BYTE
MOVLW " "
CALL LCD_CHAR
CALL IN_BYTE
MOVWF COUNT_D_C
CALL LCD_VAL
CALL CALC_CRC_BYTE
MOVLW 0DH ; new line on LCD
CALL LCD_CHAR
MOVLW 0AH
CALL LCD_CHAR
CALL IN_BYTE ; this is CRC from DS1820
MOVWF CRC
CALL LCD_VAL
CALL CALC_CRC_BYTE ; result now should be zero
MOVLW 0DH ; new line on LCD
CALL LCD_CHAR
MOVLW 0AH
CALL LCD_CHAR
MOVF SHIFT_REG, W ; display the shift register
CALL LCD_VAL ; should be zero
MOVLW .120 ; 30 second delay (120 * 250 msecs)
MOVWF LOOP1
MAIN_1:
MOVLW .250
CALL LCD_DELAY
DECFSZ LOOP1, F
GOTO MAIN_1
GOTO MAIN ; do it again
;;;;;;;;;;;;
CALC_CRC_BYTE: ; applies bit by bit to shift reigister algorithm
MOVLW .8
MOVWF N
MOVF IBYTE, W
MOVWF TEMP_1 ; copy IBYTE to TEMP
CALC_CRC_BYTE_1:
MOVF TEMP_1, W
ANDLW 01H ; isolate least significant bit
MOVWF DATA_BIT
CALL CALC_CRC_BIT
RRF TEMP_1, F ; next data bit now in least sig bit
DECFSZ N, F ; do this for each of the eight bits
GOTO CALC_CRC_BYTE_1
RETURN
CALC_CRC_BIT:
MOVF DATA_BIT, W ; calculate the feed back bit
XORWF SHIFT_REG, W
ANDLW 01H
MOVWF FB
BCF STATUS, C ; shift_reg = shift_reg >> 1
RRF SHIFT_REG, F
BTFSS FB, 0
GOTO CALC_CRC_BIT_DONE ; if FB was zero, we are done
MOVLW 8CH ; otherwise, invert bits 7, 3 and 2
XORWF SHIFT_REG, F
CALC_CRC_BIT_DONE:
RETURN
; The following are standard 1-Wire routines.
INIT:
CALL PIN_HI
CALL PIN_LO
MOVLW .50 ; 500 us delay
CALL DELAY_10USEC
CALL PIN_HI
MOVLW .50 ; 500 usec delay
CALL DELAY_10USEC
RETURN
WAIT:
CALL IN_BYTE
MOVLW 0FFH
SUBWF I_BYTE, W
BTFSS STATUS, Z
GOTO WAIT
RETURN
IN_BYTE: ; returns byte in W
MOVLW .8
MOVWF INDEX
CLRF I_BYTE
IN_BYTE_1:
CALL PIN_LO ; momentary low on DATA_PIN
NOP
CALL PIN_HI
NOP
NOP
NOP
NOP
NOP
NOP
MOVF PORTB, W ; 7 usecs later, fetch from DATA_PIN
MOVWF TEMP
BTFSS TEMP, DATA_PIN
BCF STATUS, C ; its a zero
BTFSC TEMP, DATA_PIN
BSF STATUS, C ; its a one
RRF I_BYTE, F
MOVLW .6 ; now delay 60 usecs
CALL DELAY_10USEC
DECFSZ INDEX, F
GOTO IN_BYTE_1
MOVFW I_BYTE ; return the result in W
RETURN
OUT_BYTE:
MOVLW .8
MOVWF INDEX
OUT_BYTE_1:
RRF O_BYTE, F
BTFSS STATUS, C
GOTO OUT_0
GOTO OUT_1
OUT_BYTE_2:
DECFSZ INDEX, F
GOTO OUT_BYTE_1
RETURN
OUT_0:
CALL PIN_LO ; bring DATA_PIN low
MOVLW .6 ; for 60 usecs
CALL DELAY_10USEC
CALL PIN_HI
GOTO OUT_BYTE_2
OUT_1:
CALL PIN_LO ; momentary low
CALL PIN_HI
MOVLW .6
CALL DELAY_10USEC
GOTO OUT_BYTE_2
;;;;;;
PIN_HI:
BSF STATUS, RP0
BSF TRISB, DATA_PIN ; high impedance
BCF STATUS, RP0
RETURN
PIN_LO:
BCF PORTB, DATA_PIN
BSF STATUS, RP0
BCF TRISB, DATA_PIN ; low impedance zero
BCF STATUS, RP0
RETURN
DELAY_10USEC: ; provides a delay equal to W * 10 usecs
MOVWF LOOP1
DELAY_10USEC_1:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DECFSZ LOOP1, F
GOTO DELAY_10USEC_1
RETURN
#include <lcd_f84.asm> ; PIC-n-LCD Module Version for 16F84
END
