' program for orienteering control using an iButton (DS1992, DS1993 and up) ' works with PIC16F628 ' maximum number of numbered controls: 31 (DS1992), 127 (DS1993) ... ' maximum number of controls in one iButton: 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 Kutijica #DEFINE versionRound '#DEFINE versionBox1 '#DEFINE versionBox2 #IFDEF versionRound THEN ' ibutton input ports for version ROUND BOX symbol REDLED=1 ' LED flash symbol BUZZ=2 ' piezo buzzer symbol IBUTTPIN=4 ' ibutton socket #ENDIF #IFDEF versionBox1 THEN ' ibutton input ports for version HAMMOND BOX v1 symbol REDLED=1 ' VERSION-1 (pin 18) symbol IBUTTPIN=2 ' iButton socket symbol BUZZ=3 ' piezo buzzer #ENDIF #IFDEF versionBox2 THEN ' ibutton input ports for version HAMMOND BOX v2 symbol REDLED=0 ' VERSION-2 (pin 17) symbol IBUTTPIN=2 ' iButton socket symbol BUZZ=3 ' piezo buzzer #ENDIF ' General symbol LEDON=0 ' pull-down for on symbol LEDOFF=1 ' pull-up for off symbol ONHOURS=36 ' max hrs on after a clock reset const SIXTY = 60 dim js as byte[8] dim js1 as byte[8] dim js2 as byte[8] dim counter as byte dim sec as longword dim tim as byte dim crcTest as byte dim i as byte dim idBox as byte ' controlID - max no. is 31 (DS1992), 127 (DS1993) ... ' read from dip switch dim idBoxLoc as word dim wasConnected as boolean dim clockSet as short dim sleepSec as longword 'read some memory 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 ' set the PIC clock to real time sub procedure readTimeFromButton() dim numOfTries as byte dim secs1 as longword dim secs2 as longword clockSet = -1 sleepSec = $FFFFFFFF numOfTries=0 secs1 = 0 secs2 = 1 do inc(numOfTries) ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$CC) ' request skip read ROM ow_write(PORTA,IBUTTPIN,$66) ' request time to r/w buffer Ow_Read_Serial(PORTA,IBUTTPIN,js,5) secs1 = ((((js[4] << 8) or js[3])<<8) or js[2] ) <<8 or js[1] ' time delay_ms(50) ' read second time ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$CC) ' request skip read ROM ow_write(PORTA,IBUTTPIN,$66) ' request time to r/w buffer Ow_Read_Serial(PORTA,IBUTTPIN,js,5) secs2 = ((((js[4] << 8) or js[3])<<8) or js[2] ) <<8 or js[1] ' time if (secs1 = secs2) and (js[4]>$49) and (js[4]<$FF) then ' time must be after october 2008 PORTA.REDLED = LEDON delay_ms(50) PORTA.REDLED = LEDOFF delay_ms(250) sec = secs1 clockSet = 6 ' sets LED counter to flash on the minute, for 5 minutes sleepSec = sec + (ONHOURS * SIXTY * SIXTY) end if loop until ((clockSet>0) or (numOfTries>10)) if clockSet = -1 then clockSet = 0 end if end sub ' write time to button sub procedure writeTimeToButton(dim location as word) dim currentTime as longword dim firstWriteOK as byte dim endbyte as byte firstWriteOK=0 currentTime=sec 'calculate location of 4th byte of the time in page (0-31) endbyte=$31 and (Lo(location) + 3) ' use low 5 bits only (0-31) do ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$CC) ' write skip read ROM ow_write(PORTA,IBUTTPIN,$0F) ' write to Scratch pad ow_write(PORTA,IBUTTPIN,Lo(location)) ' write location lower byte ow_write(PORTA,IBUTTPIN,Hi(location)) ' write location higher byte ow_write(PORTA,IBUTTPIN,Highest( currentTime )) ' write time (highest byte) ow_write(PORTA,IBUTTPIN,Higher( currentTime )) ' write time (more higher byte) ow_write(PORTA,IBUTTPIN,Hi( currentTime )) ' write time (higher byte) ow_write(PORTA,IBUTTPIN,Lo( currentTime )) ' write time (lower byte) delay_us(200) 'delay, needed to work ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$CC) ' skip ROM ow_write(PORTA,IBUTTPIN,$AA) ' read scratchpad Ow_Read_Serial(PORTA,IBUTTPIN,js,7) ' address(0-1), end-byte(2), time-stamp (3-7) delay_us(200) ' check if scratchpad is correct if (js[0]=Lo(location)) and (js[1]=Hi(location)) and (js[2]=endbyte) then ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$CC) ' skip ROM ow_write(PORTA,IBUTTPIN,$55) ' copy to memory ow_write(PORTA,IBUTTPIN,js[0]) ' verify location lo ow_write(PORTA,IBUTTPIN,js[1]) ' verify location hi ow_write(PORTA,IBUTTPIN,js[2]) ' verify end-byte delay_us(200) ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$CC) ' skip ROM ow_write(PORTA,IBUTTPIN,$F0) ' read from memory ow_write(PORTA,IBUTTPIN,Lo(location))' set location from where to read ow_write(PORTA,IBUTTPIN,Hi(location)) delay_us(100) Ow_Read_Serial(PORTA,IBUTTPIN,js,4) ' read 4 bytes of data from memory if ((js[3] = Lo(currentTime)) and (js[2] = Hi (currentTime)) and (js[1] = Higher(currentTime)) and (js[0] = Highest (currentTime))) then firstWriteOK=1 end if end if ' loop until time is correctly written loop until ( firstWriteOK=1 ) or (currentTime+20) and(sec>=sleepSec) then PORTA.REDLED = LEDOFF PORTA.BUZZ=0 TRISA = $FF ' all portb is input TRISB = $FF ' all portb is input asm sleep end ASM end if if (sec mod SIXTY = 0) then if(clockset > 1) then ' flash red LED on the minute PORTA.REDLED = LEDON dec(clockSet) else ' quiet tick PORTA.BUZZ=1 delay_ms(5) PORTA.BUZZ=0 end if end if if (clockSet = 0) then ' warning that clock is not set PORTA.REDLED = LEDON delay_ms(50) PORTA.REDLED = LEDOFF PORTA.BUZZ=1 delay_ms(100) PORTA.BUZZ=0 end if end if end sub main: TRISA = 0 ' porta is output (except RA1) PORTA = 0 ' initialize porta TRISB = $FF ' portb is input OPTION_REG.NOT_RBPU=0 ' enable individual pull-up CMCON = 7 ' Disable Comparators counter = 0 ' Initialize counter sec=0 tim=0 clockSet = 0 T1CON = $31 ' start the timer PIR1.TMR1IF = 0 ' clear TMR1IF PIE1 = 1 ' enable TMR1 interrupts INTCON = $C0 ' Enable global TMR interrupt ' read DIP for idBox idbox = PORTB idBox = idBox xor $FF ' invert bits idBoxLoc=idBox*4 OPTION_REG.NOT_RBPU=1 ' disable individual pull-up _loop: ' first, we read iButton if present ow_reset(PORTA,IBUTTPIN) ' onewire reset signal ow_write(PORTA,IBUTTPIN,$33) ' read iButton - read ROM Ow_Read_Serial(PORTA,IBUTTPIN, js,8) ' read 8 bytes of Dallas iButton crcTest=0 for i=0 to 6 ByteCRC(crcTest,js[i]) next i ' check if iButton present if (((js[0] and js[1] and js[3] and js[4] and js[5] and js[6] and js[7])<>$FF) and (crcTest <> $FF) and (crcTest<>$00) and crcTest=js[7]) then ' iButton is not present if wasConnected=0 then ' ibutton present, check if multiple writing if js[0]=$24 then readTimeFromButton() ' read time from button else writeTimeToButton(idBoxLoc) ' normal button - write current time to button end if end if ' ibutton is not present else ' it was already wasConnected and now is disconnected (wasConnected=0) wasConnected=0 end if if wasConnected=1 then ' flash red led PORTA.REDLED=LEDON delay_ms(30) PORTA.REDLED=LEDOFF delay_ms(30) PORTA.BUZZ=1 delay_ms(200) PORTA.BUZZ=0 delay_ms(200) end if goto _loop end.