( 1WireMJB.fth ) TACHYON [~ : 1WIREMJB.fth ." 1-wire interface extensions MJB 140525:0000 " ; \ CREATE SMALL \ define SMALL before a load to specify a SMALL build to limit the sections included IFNDEF SMALL { \ DESCRIPTION \ \ Maxim 1-wire ROM Search algorithm \ straight forward implementation \ per AN937 "Book of iButton Standards", figure 5-3 \ for TACHYON Forth 2014 by Markus Baer aka MJB @ parallax forums, \ inspired by am-forth implementation by Bradford J. Rodriguez. \ USES \ 1WIRE.fth from Tachyon Forth by Peter Jakacki \ and of course the TACHYON System (Kernel 2.3 + EXTEND) - thanks Peter \ \ ** USES from 1-wire.fth **** \ 1W.RESET ( -- ack ) \ 1W.BITWR ( iomask dat -- iomask dat/2 ) \ 1W.BITRD ( iomask dat -- iomask dat+ ) \ 1W! ( c -- ) Write one byte to the 1-wire bus. \ 1W@ ( -- c ) Read one byte from the 1-wire bus. } { if you need it ... : 1W.!N ( xN .. x1 N -- ) FOR 1W! NEXT ; \ send N characters/bytes from stack : 1W.@N ( N -- x1 .. xN ) FOR 1W@ NEXT ; \ fetch N characters/bytes to stack : 1W..ROM RDROMH ; \ print 1Wire single device ROM code } BYTE 1W.lastdisc ( used as byte variable to hold last discrepancy ) BYTE 1W.doneflag BYTE 1W.rombit ( used as byte variable, 1..64 ) BYTE 1W.discmark \ buffer for one ROM-ID 1W.romid ( 8 byte array ) 8 BYTES 1W.romid PRI 1W.!rombit ( f -- \ set the bit (1..32) given by 1W.rombit in buffer 1W.romid to flag value f ) 1W.rombit C@ 1- 8 U/MOD ( -- f bit# byte# ) 1W.romid + ( f bit# addr ) SWAP MASK SWAP ( f bitmask addr ) ROT ( bitmask addr f ) BIT! ; PRI 1W.@rombit ( -- f \ f is 0 or non-0 not necc. 1 \ fetch the bit (1..32) given by 1W.rombit from buffer 1W.romid to flag f ) 1W.rombit C@ 1- 8 U/MOD ( -- bit# byte# ) 1W.romid + C@ ( -- bit# byte ) SWAP MASK ( -- byte bitmask ) AND ; \ helper pub <>0 ( val -- 0or1 \ convert any non 0 to 1 instead of -1 as 0<> does ) IF 1 ELSE 0 THEN ; #P14 |< DQ! \ for my setup MJB, this is the pin my 1-wire bus is attached to 4.7k or 5k pullup required \ single bit operations to read and write 1-wire bus PRI 1W.BIT@ ( -- bit ) DQ@ 0 1W.BITRD NIP <>0 ; \ gives bit as 0 or 1 PRI 1W.BIT! ( bit -- ) DQ@ SWAP 1W.BITWR 2DROP ; \ takes bit as 0 or 1 { for test PRI .rombit ( bitnumber -- ) 1W.rombit C! 1W.@rombit . ; \ print 1W.rombit value PRI .RB ( -- ) 1W.@rombit . ; PRI .romid ( -- ) 1W.romid 8 ADO I C@ . SPACE LOOP ; } PRI 1W.NEWSEARCH ( -- \ clear variables used in search ) 1W.lastdisc C~ 1W.doneflag C~ 1W.rombit C~ 1W.romid #8 ERASE 1W.devcnt C~ \ set device count to 0 ; : 1W.SEARCHROM ( -- f ) ( search for one additional device. Returns 0 if done or 1 if more to come. see 1W.SCAN ) 0 ( default return value ) ( 0 ) 1W.doneflag C@ IF 1W.doneflag C~ \ clear doneflag EXIT ( leaves 0 ) THEN 1W.RESET IF ( presence signal detected? ) 1W.rombit C!~~( yes: set ROM bit index to 1 ) 1W.discmark C~ ( set discrepancy marker to 0 ) ( 0 ) $F0 1W! ( send search command on bus ) ( 0 ) BEGIN 1W.BIT@ 1W.BIT@ 2* + ( 0 BA ) \ 2 bits A & B in bit pos 0 AND 1 DUP $03 = ( 0 BA flag ) IF ( bitA = bitB = 1?) DROP 1W.lastdisc C~ \ clear EXIT ( leaves 0 ) ELSE ( 0 BA ) ?DUP 0= ( 0 BA false | 0 true ) IF ( bitA = bitB = 0?) ( 0 ) 1W.rombit C@ 1W.lastdisc C@ = ( 0 flag ) IF 1 1W.!rombit ( 0 ) ELSE 1W.rombit C@ 1W.lastdisc C@ > ( 0 flag ) IF 0 1W.!rombit 1W.rombit C@ 1W.discmark C! ( 0 ) ELSE 1W.@rombit 0= ( 0 flag ) IF 1W.rombit C@ 1W.discmark C! ( 0 ) THEN THEN ( 0 ) THEN ( 0 ) ELSE ( 0 BA ) $01 AND ( bit A value , bit B is inverse so we don't need it ) 1W.!rombit ( 0 ) THEN THEN ( 0 ) 1W.@rombit <>0 \ gives 0 or 1 as logical values instead of 0 -1 1W.BIT! ( DROP what is this drop for ??? )( send ROM bit to bus ) .S \ should be 0 1W.rombit C@ 1+ DUP 1W.rombit C! ( 0 1W.rombitVal ) \ increment 1W.rombit index $40 > UNTIL \ check > 64 ( 0 ) 1W.discmark C@ DUP 1W.lastdisc C! ( 0 discmark ) 0= IF 1 1W.doneflag C! ( 0 ) ELSE 1+ ( set return value to 1 = true ) THEN ELSE ( no presence signal ) 1W.lastdisc C~ \ set 0 THEN ; \ Demonstrates how to use SEARCHROM to find all attached devices and store them in table 1W.1Wdevs BYTE 1W.devcnt LONG 1W.devaddr TABLE 1W.1Wdevs #8 #8 * ALLOT \ prepare for 8 devices here, change as appropriate { test 1W.1Wdevs $20 DUMP 1W.1Wdevs $16 ERASE 1W.1Wdevs $20 ADO I C@ .BYTE SPACE LOOP } PRI 1W.PRINTromid ( addr -- ) \ print the ROM-ID at address 8 ADO I C@ .BYTE SPACE LOOP CR ; pub 1W.SCAN ( -- ) \ scan for any devices on 1-wire bus and store them in table 1W.1Wdevs 1W.NEWSEARCH 1W.1Wdevs 1W.devaddr ! \ begin at start of table CR BEGIN 1W.SEARCHROM 1W.romid 1W.PRINTromid \ print it \ ' CMOVE ( src dst cnt -- ) Copy bytes from src to dst address for cnt bytes using increment for up or down 1W.romid 1W.devaddr @ 8 CMOVE \ SEARCHROM could be optimized to store directly to table, \ by making 1W.romid a CONST pointing to the table entry and changing it for each run 1W.devaddr DUP @ 8 + SWAP ! 0= UNTIL CR ; { some demo / test code pub 1W..1Wdevs \ print the table of 1W.1Wdevs discovered by 1W.SCAN ( if table is not full ) 1 1W.1Wdevs CR BEGIN \ BEGIN condition WHILE code REPEAT DUP C@ WHILE ( 1 1W.1Wdevs ) \ works only if there is at least one element in table which is 0ed SWAP DUP .BYTE ":" EMIT SPACE 1+ SWAP DUP 1W.PRINTromid 8 + REPEAT DROP ; pub 1W..1WdevsT \ print the table of 1W.1Wdevs discovered by 1w.scan in Table format for inclusion in Tachyon code 1W.1Wdevs CR ." TABLE 1W.my1Wdevs" CR BEGIN \ BEGIN condition WHILE code REPEAT DUP C@ WHILE ( 1 1W.1Wdevs ) SPACE DUP 8 ADO ." $" I C@ .BYTE ." | " LOOP CR \ ADO ( from cnt -- ) 8 + REPEAT DROP ; } { test it on 2 devices NEWCNT 1W.SCAN .LAP } \ 1 Wire Multibus CoMmanD takes the address of a ROM code and performs a matchROM command pub 1W.MCMD ( -- ) 1W.RESET DROP MATCHROM ; \ reset and send Match ROM command pub 1W.MATCH ( addr -- ) \ address sensor with 64-bit rom code given at addr then ready for next command 1W.MCMD 8 ADO I C@ 1W! LOOP ; IFNDEF SMALL \ 18B20 diagnostic routines : 1W.SHOWTEMPM ( tableaddr n -- \ reads and displays a DS18B20 on a multibus. n is the index into the table of devices 1W.1Wdevs ) \ 1W.1Wdevs table of discovered 1W devices with SEARCHROM 1- 8 * + \ calculate start of ROM code to address DUP 1W.MATCH CONVERTT #750 ms \ 1W.MATCH TEMP@ DUP .TEMP 1W.MATCH TEMP@ .TEMP \ SPACE 4 SHR 0 DO ." *" LOOP \ bar graph ; : 1W.SHOWSPM ( tableaddr n -- \ reads and displays a DS18B20 SCRATCHPAD on a multibus n is the index into the table of devices 1W.1Wdevs ) \ 1W.1Wdevs table of discovered 1W devices with SEARCHROM 1- 8 * + \ calculate start of ROM code to address DUP 1W.MCMD CONVERTT #750 ms 1W.MCMD RDSCRH ; \ for sensor# from I = 1 to n from ROM-Code table given show the temp readings cyclically until key pressed : 1W.SHOWTEMPSM ( tableaddr n -- ) BEGIN 1 OVER ADO \ from 1 to n OVER I 1W.SHOWTEMPM CR 2 seconds LOOP KEY? AND \ AND required, since KEY? ( -- key flag ) UNTIL 2DROP ; } \ end IFNDEF SMALL \ 1W.1Wdevs 2 1W.SHOWTEMPSM { TABLE 1W.my1Wdevs $28 | $09 | $6C | $CD | $04 | $00 | $00 | $82 | $28 | $F7 | $E6 | $BF | $04 | $00 | $00 | $3A | 1W.my1Wdevs 2 1W.SHOWTEMPSM \ show the temp for my 2 sensors } ]~ END