' program for orienteering control using an iButton (DS1992, DS1993 and up) ' works with PIC16F628 ' maximum number of numbered controls: 31 (DS1992), 127 (DS1993) ... ' works by dividing memory in 4 byte blocks - every block is one control written in unix timestamp format ' this design is pretty simple, at the cost of smaller number of controls program iButtonReader ' ibutton input ports symbol REDLED=1 symbol BUZZ=2 ' piezo buzzer symbol KEY=0 symbol IBUTTPIN=4 ' ' General symbol LEDON=0 ' pull-down for on symbol LEDOFF=1 'Start and Finish Numbers symbol STARTNR=30 symbol FINISHNR=31 symbol READING = "READ", "30>31" dim k as byte[8] ' 64 bit data dim time32 as longword dim runTime as word ' 16 bit = 2^16 secs = 18 hrs dim punch as byte[32] dim extent as short[32] dim index as byte[32] dim crcTest as byte dim crcSave as byte dim i as byte dim j as byte dim readOK as bit dim text1 as string [8] ' Variable for LCD display line-1 dim text2 as string [8] ' Variable for LCD display line-2 dim found as short ' starts at -2 dim isConnected as bit dim resultsPage as byte dim currentPage as byte dim LCD_EN as sbit at RB1_bit dim LCD_RS as sbit at RB2_bit dim LCD_D4 as sbit at RB4_bit dim LCD_D5 as sbit at RB5_bit dim LCD_D6 as sbit at RB6_bit dim LCD_D7 as sbit at RB7_bit dim LCD_EN_Direction as sbit at TRISB1_bit dim LCD_RS_Direction as sbit at TRISB2_bit dim LCD_D4_Direction as sbit at TRISB4_bit dim LCD_D5_Direction as sbit at TRISB5_bit dim LCD_D6_Direction as sbit at TRISB6_bit dim LCD_D7_Direction as sbit at TRISB7_bit ' End Lcd module connections const pause = 200 const noOfBoxes = 31 ' 0 - 31 'read some ibutton memory - up to 8 bytes sub procedure Ow_Read_Serial(dim byref PORT as byte, dim pin as byte, dim byref out as byte[8], dim leng as byte) dim i as byte dim tmpRead as byte i = 0 while i < leng ' we will move 8 bytes tmpRead = ow_read(PORT,PIN) ' get one byte from Dallas iButton out[i] = tmpRead ' move the byte into array inc(i) ' next i wend end sub '======================================================= 'CRC8 without table 'All you have to do is to initialise the crc variable (to zero or $FFFF) ' and then call the procedure for every byte of your data. '======================================================= sub procedure ByteCRC(dim byref CRC as byte,dim CRCData as byte) dim i,TstBit as byte For i = 0 to 7 ' Do for all 8 bits in data byte TstBit = CRC xor CRCData 'CRC.0 xor CRCData.0 ' XOR bit0 of data byte and crc TstBit = TestBit(TstBit,0) CRCData = CRCData >> 1 ' Position data byte for next bit test If TstBit = 1 then ' If test bit not set, just shift CRC CRC = CRC xor $18 ' If set, account for EXOR feedback end if ' Shift right the CRC byte CRC = CRC >> 1 ' CRC bit 0 to bit bucket CRC.7 = TstBit ' Test bit rotates into CRC bit 7 Next i end sub ' assemble 32 bit number from 4 byte array sub procedure getLongWord(dim byref b4 as byte[8], dim byref out as longword) out = ((((b4[0] << 8) or b4[1])<<8) or b4[2] ) <<8 or b4[3] end sub sub procedure printLCD(dim byref line1 as string[8], dim byref line2 as string[8]) Lcd_Cmd(_LCD_CLEAR) ' LCD command (clear LCD) Lcd_Out(1,1,line1) Lcd_Out(2,1,line2) delay_ms(500) end sub sub procedure secsTohhmmss(dim t as word, dim byref s as string[8] ) dim d as byte 'divisor dim i as byte 'character dim j as byte s = " : : " j=7 'character position 7 down-to 0 for i = 1 to 6 ' numeric characters d=10 ' default divisor select case i case 2,4 d=6 case 3,5 ' charcter position for : dec(j) ' skip to next position end select s[j]= chr((t mod d)+ 48) t = t/d dec(j) next i end sub sub procedure rewindIbuttonROM( dim x as byte) ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$CC) ' rom code not required ow_write(PORTA,IBUTTPIN,$F0) ' read memory command ow_write(PORTA,IBUTTPIN,x*4) ' memory location ow_write(PORTA,IBUTTPIN,$00) delay_us(pause) end sub sub procedure readFromButton() dim startTime as longword dim finishTime as longword 'read memory from start slot rewindIbuttonROM(STARTNR) Ow_Read_Serial(PORTA,IBUTTPIN,k,4) getLongWord(k,startTime) ' start time rewindIbuttonROM(FINISHNR) Ow_Read_Serial(PORTA,IBUTTPIN,k,4) getLongWord(k,finishTime) ' finish time runTime = 0 time32 = finishTime-startTime ' run time in 32 bit if Higher(time32)=0 then ' run time must be less than 18hrs runTime = LoWord(time32) ' run time in 16 bit end if crcTest=0 found = 0 rewindIbuttonROM(0) for i = 0 to noOfBoxes Ow_Read_Serial(PORTA,IBUTTPIN,k,4) delay_us(pause) getLongWord(k,time32) ' punch time if (time32 >=startTime) and (time32 <= finishTime) then time32 = time32 - startTime 'lapsed time in secs punch[i] = time32 / 60 'lapsed time in minutes inc(found) for j=0 to 4 ByteCRC(crcTest,k[j]) next j else punch[i]=$FF end if next i found = found - 2 ' exclude start & finish end sub sub procedure indexTimes() dim n as byte dim swapped as bit dim temp as byte 'init Index for n = 0 to noOfBoxes index[n] = n next n 'bubble sort do swapped=0 for n = 1 to noOfBoxes if Punch[index[n-1]] > Punch[index[n]] then temp = index[n-1] index[n-1]=index[n] index[n]=temp swapped=1 end if next n loop until swapped = 0 end sub sub procedure displayResults(dim byref n as byte) dim splitTime as byte if n=0 then secsTohhmmss(RunTime,text1) byteToStr(found,text2) strcat(text2, " fox") printLCD(text1,text2) else text1 = "--> " byteToStr(index[n],text2) strcat(text1, text2) splitTime=punch[index[n]]-punch[index[n-1]] byteToStr(splitTime,text2) strcat(text2, " mins") printLCD(text1,text2) end if currentPage = n end sub main: TRISA = %11001 ' porta (0=out) PORTA = 0 ' initialize porta TRISB = 0 ' portb is output PORTB = 0 ' initialize porta INTCON = 0 ' All interrupts disabled CMCON = 7 ' disable comparitor Lcd_Init() ' LCD display initialization Lcd_Cmd(_LCD_CURSOR_OFF) ' LCD command (cursor off) printLCD("OPORCON" , "v1.1") PORTA.REDLED=LEDOFF delay_ms(1000) isConnected=0 readOK = 0 _loop: ' first, we read iButton if present ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$33) ' request ROM header 64bit code Ow_Read_Serial(PORTA,IBUTTPIN,k,8) ' read 8 bytes of Dallas iButton crcTest=0 for i=0 to 6 ByteCRC(crcTest,k[i]) next i ' check if iButton present if (((k[0] and k[1] and k[3] and k[4] and k[5] and k[6] and k[7])<>$FF) and (crcTest <> $FF) and (crcTest<>$00) and crcTest=k[7]) then ' iButton is present if isconnected = 0 then ' do not read until button disconnected if (k[0] = $06) or (k[0] = $08) then readOK=0 printLCD(READING) readFromButton() ' first time read times from button crcSave=crcTest readFromButton() ' second time read times from button if (crcTest=crcSave) and (runTime <> 0) then indexTimes() resultsPage=0 currentPage=$FF PORTA.REDLED = LEDON PORTA.BUZZ=1 delay_ms(pause) PORTA.BUZZ=0 PORTA.REDLED = LEDOFF readOK = 1 isconnected=1 else printLCD("ERR", "") end if ' if crc is good end if ' if button is ds1992/3 end if ' if button detected else isConnected=0 end if if (readOK=1) then if (resultsPage<>currentPage) then displayResults(resultsPage) end if if PORTA.KEY=0 then Inc(resultsPage) if resultsPage>found+1 then resultsPage = 0 end if displayResults(resultsPage) end if end if goto _loop end.