Dr. Imre Bartfai says:
[this is my] iButton reader routine, especially for [PIC type] processors having only 2-level stack. The dialect is the Parallax Assembler one. 4MHz clock is assumed. When routine returns with zero, the iBData structure is filled with the appropriate data. The routine seems to be pretty robust. Please note, that the copyright is retained for me, even if the use [of] the routine is free.
;--------------------------------------------------- ; This code fragment handles the Dallas iButton(TM) ;--------------------------------------------------- ; ;Line must be equated as a bit also: LPort.LBit LFloat = IOCfg ; line bit as input LOut = 1 << LBit ^ LFloat ; all bits input but LBit iButOrg = $ Org iBData Cnt DS 1 ; counter TCnt DS 1 ; delay counter SSave DS 1 ; STATUS save cell FamCod DS 1 ; Family code \ SerNo DS 6 ; serial number } do not separate! CRC DS 1 ; CRC value / Cmd DS 1 ; command/data cell Acc DS 1 ; virtual accumulator CSave EQU SSave.0 iBEnd EQU $ Org iButOrg iButton Call _Init ; reset prom Or W,#0 ; check for zero SZ ; skip if good RetW 1 ; otherwise return Mov W,#0Fh ; Read ROM command _SndCmd Mov Cmd,W ; store command Mov Cnt,#8 ; # of bits :loop Rr Cmd ; LSB first _SendC Mov SSave,STATUS ; send Cy Mov !LPort,#LOut ; turn line to output ClrB Line ; low pulse Jmp $+1 ; tlow1 Jmp $+1 Jmp $+1 ; tlow1 Jmp $+1 JNB CSave,:Slot ; if zero, do not float Mov !LPort,#LFloat :Slot Mov Acc,#20 ; for 1 usec / instruction! :loopi Nop ; loopi makes 80 usec DJNZ Acc,:loopi ; sampling window JB CSave,:cont ; continue if 1 Mov !LPort,#LFloat :cont DJNZ Cnt,_SndCmd:loop Call _GetByt ; receive byte Mov FamCod,Cmd ; save family code Mov Cnt,#6 ; length of serial number Mov FSR,#SerNo ; serial number address :loop1 Call _GetByt ; Receive SerNo Mov INDF,Cmd ; received value Inc FSR DJNZ Cnt,:loop1 Call _GetByt ; receive CRC ; ---- ; From here compare received CRC in Cmd with that to be calculated ; upon FamCod & SerNo ; CRCChk Mov FSR,#FamCod ; start: Mov Cnt,#7 ; length Clr CRC ; clear initial CRC :loop2 Mov W,INDF ; fetch the byte Mov SSave,W ; save bits to be shifted Mov TCnt,#8 ; set shift=8bits Mov W,SSave ;; restore result :loop XOr W,CRC ; calculate CRC Mov Acc,W ;; last CRC value Rr Acc ; move it to carry JNC :Zero ; skip if data=0 XOr CRC,#18h ; update the CRC value :Zero Rr CRC ; position the new CRC Rr SSave ; position the next bit Mov W,SSave ; use the remaining bits DJNZ TCnt,:loop Inc FSR ; next pointer DJNZ Cnt,:loop2 ;------ now xchg CRC & Cmd Mov W,CRC XOr W,Cmd ; here exchange Cmd with W XOr Cmd,W XOr W,Cmd Mov CRC,W ;------ Clr Wdt CSE CRC,Cmd ; received==calculated RetW 2 RetW 0 ; good ;--------------------------------------------------- _Init Mov !LPort,#LOut ; turn port to output ClrB Line ; master reset Mov TCnt,#125 ; about 500 usec :loopi NOp ; loopi makes about 500 usec DJNZ TCnt,:loopi Mov !LPort,#LFloat Mov Acc,#7 ; for 1 usec / instruction! :looph NOp ; looph makes 30 usec for Tpdh DJNZ Acc,:looph Clr Cnt ; clear counter :pres Mov Acc,#3 ; for 1 usec / instruction! NOp :loop NOp DJNZ Acc,:loop ; 15 usec waiting JB Line,:eoi ; if high again, end of init Inc Cnt ; count length of presence pulse CJAE Cnt,#20,:bad ; too long: shortcut Clr Wdt Jmp :pres :eoi CJB Cnt,#1,:bad RetW 0 ; iButton found :bad RetW 1 ; iButton not found ;--------------------------------------------------- _GetByt Mov Cmd,#128 ; hibit as exit condition :loop Mov !LPort,#LOut ClrB Line ; low pulse Jmp $+1 ; short pulse (8 usec) Jmp $+1 Jmp $+1 Jmp $+1 Mov !LPort,#LFloat Jmp $+1 ; tRDV = 15 æsec Jmp $+1 Jmp $+1 Jmp $+1 Jmp $+1 Jmp $+1 Jmp $+1 MovB C,Line ; line state Rr Cmd ; put received bit Mov SSave,Status ; save status register Mov Acc,#14 ; for 1 usec / instruction! :loopi NOp DJNZ Acc,:loopi ; 60 usec waiting JNB CSave,:loop ; hibit not reached yet? Ret
See