;; ;; $Id: ds18b20.asm,v 1.2 2004/08/11 10:41:50 james Exp james $ ;; ;; ds18b20.asm, a PIC 12C509 or 16F84 based DS18B20 translator ;; Copyright (C) 2005 James Cameron (quozl@us.netrek.org) ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;; ;; ;; Refer to http://quozl.netrek.org/ts/ or http://quozl.linux.org.au/ts/ ;; for further documentation. ;; ;; Variable prefix conventions ;; b_ bit number ;; m_ bit mask ;; r_ static file register ;; ;; Function prefix conventions ;; t_ entry point for a lookup table ;; ow_ one wire bus communication functions ;; tx_ serial data transmission functions ;; sb_ sixteen bit math functions ;; ;; Source code reading hints ;; - INDF is a data stack pointer, FSR is top of stack, ;; - stack macros are used, check their definitions carefully, ;; - explicit bank switching is done in the code, using macros. ;; ifdef __16f84 processor 16f84 list f=inhx8m include "p16f84.inc" __config _cp_off & _wdt_on & _hs_osc endif ifdef __12c509 processor 12c509 list f=inhx8m include "p12c509a.inc" ifdef jw __config _mclre_off & _cp_off & _wdt_on & _iNTrc_osc endif ifdef cp __config _mclre_off & _cp_on & _wdt_on & _iNTrc_osc endif endif ifdef __12c509 base equ 0x07 ; first free file register address stack equ 0x1f+1 ; end address of stack port equ gpio ; port on which bits are used movwt macro ; move w to tris tris gpio endm bank0 macro ; select low bank for goto/call bcf status,pa0 endm bank1 macro ; select high bank for goto/call bsf status,pa0 endm endif debug equ 0 ; set to one to enable calculation stack trace ;; port bit allocations b_ow0 equ 0 ; one wire bus to first DS18B20 b_ow1 equ 1 ; one wire bus to second DS18B20 b_tx equ 2 ; serial output 2400 baud to host b_in equ 3 ; mode flag input b_ow2 equ 4 ; one wire bus to third DS18B20 b_ow3 equ 5 ; one wire bus to fourth DS18B20 ;; r_trism extra allocations b_noisy equ 6 ; display more data b_fahre equ 7 ; display in fahrenheit ;; mask of one wire bus valid bits m_ow equ 1<c incf fsr,f ; ->b movwf indf ; b ! decf fsr,f ; ->c movf indf,w ; c @ incf fsr,f ; ->b incf fsr,f ; ->a movwf indf ; a ! decf fsr,f ; ->b retlw 0 ;;; ;;; sb_over, sixteen bit over, copy item under current item ;;; ;;; data stack: ( a b -- a b a ) [total 6] ;;; stack: none ;;; sb_over_ ; ( a b c d -- a b c d a b ) incf fsr,f ; ( a b c ^ d ) incf fsr,f ; ( a b ^ c d ) incf fsr,f ; ( a ^ b c d ) movf indf,w ; a decf fsr,f ; ( a b ^ c d ) decf fsr,f ; ( a b c ^ d ) decf fsr,f ; ( a b c d ^ ) decf fsr,f ; ( a b c d ? ^ ) movwf indf ; a incf fsr,f ; ( a b c d ^ a ) incf fsr,f ; ( a b c ^ d a ) incf fsr,f ; ( a b ^ c d a ) movf indf,w ; b decf fsr,f ; ( a b c ^ d a ) decf fsr,f ; ( a b c d ^ a ) decf fsr,f ; ( a b c d a ^ ) decf fsr,f ; ( a b c d a ? ^ ) movwf indf ; b retlw 0 ;;; ;;; sb_multiply, sixteen bit multiply ;;; ;;; data stack: ( multiplicand multiplier -- product ) [total 7] ;;; stack: calls others that do not call ;;; sb_multiply_ ; ( al ah bl bh -- cl ch ) pushl16 d'0' ; clear product ;; ( al ah bl bh cl ch ) pushl d'16' ; count of bits to process ;; ( al ah bl bh cl ch count ) sb_multiply_loop ; for each bit ;; ( al ah bl bh cl ch count ) ;; shift multiplier down by one movlw 5 addwf fsr,f ; ->ah rrf indf,f incf fsr,f ; ->al rrf indf,f decf fsr,f ; ->ah decf fsr,f ; ->bl ;; ( al ah bl ^ bh cl ch count ) ;; if the bit is set ... btfss status,c goto sb_multiply_skip ;; add the multiplicand to the product decf fsr,f ; ->bh movf indf,w decf fsr,f ; ->cl decf fsr,f ; ->ch addwf indf,f movlw 3 addwf fsr,f ; ->bl movf indf,w decf fsr,f ; ->bh decf fsr,f ; ->cl addwf indf,f decf fsr,f ; ->ch btfsc status,c incf indf,f movlw 3 addwf fsr,f ; ->bl sb_multiply_skip ;; ( al ah bl ^ bh cl ch count ) ;; shift up multiplicand bcf status,c rlf indf,f decf fsr,f ; ->bh rlf indf,f ;; ( al ah bl bh ^ cl ch count ) ;; and loop for remainder of bits movlw 3 subwf fsr,f ; ->count decfsz indf,f goto sb_multiply_loop ;; ( al ah bl bh cl ch count ) popl ; count call sb_nip ; bl bh goto sb_nip ; al ah ;;; ;;; sb_divide, sixteen bit divide ;;; ;;; data stack: ( numerator denominator -- remainder quotient ) [total 10] ;;; stack: calls others that do not call ;;; sb_divide_ ; ;; ( nl nh dl dh -- rl rh ql qh ) ;; prepare stack for results ;; ( nl nh dl dh ) call sb_over ;; ( nl nh dl dh nl nh ) call sb_over ;; ( nl nh dl dh nl nh dl dh ) ;; ( rl rh ql qh nl nh dl dh ) movlw d'4' addwf fsr,f ; ->qh clrf indf ; qh incf fsr,f ; ->ql clrf indf ; ql incf fsr,f ; ->rh clrf indf ; rh incf fsr,f ; ->rl clrf indf ; rl movlw d'7' subwf fsr,f ; ->dh ;; ( rl rh ql qh nl nh dl dh ) ;; save effective sign difference ;; sign = xor(nh,dh) ;; ( nl nh dl dh ) movf indf,w ; dh incf fsr,f ; incf fsr,f ; ->nh xorwf indf,w ; nh decf fsr,f ; decf fsr,f ; ->dh pushw ;; ( nl nh dl dh sign ) ;; force arguments to positive ;; n = abs (n) ;; ( nl nh dl dh sign ) movlw d'3' addwf fsr,f ; ->nh call sb_abs decf fsr,f ; ->dl decf fsr,f ; ->dh ;; d = abs (d) ;; ( nl nh dl dh ^ sign ) call sb_abs decf fsr,f ; ->sign ;; set the bit counter pushl d'16' ; for 16 shifts ;; ( nl nh dl dh sign count ) ;; ( rl rh ql qh nl nh dl dh sign count ) sb_divide_loop ;; ( rl rh ql qh nl nh dl dh sign count ) ;; shift bits left from numerator to remainder movlw d'5' addwf fsr,f ; ->nl bcf status,c ; clear status.c rlf indf,f ; nl decf fsr,f ; ->nh rlf indf,f ; nh incf fsr,f ; (must keep status.c) incf fsr,f ; incf fsr,f ; incf fsr,f ; incf fsr,f ; ->rl rlf indf,f ; rl decf fsr,f ; ->rh rlf indf,f ; rh ;; ( rl rh ^ ql qh nl nh dl dh sign count ) ;; check if remainder is greater than denominator movlw d'6' subwf fsr,f ; ->dh movf indf,w ; dh movwf r_ephemeral movlw d'6' addwf fsr,f ; ->rh movf r_ephemeral,w subwf indf,w ; rh btfss status,z goto sb_divide_skip_1 ;; ( rl rh ^ ql qh nl nh dl dh sign count ) ;; msb equal, so check lsb movlw d'5' subwf fsr,f ; ->dl movf indf,w ; dl movwf r_ephemeral movlw d'6' addwf fsr,f ; ->rl movf r_ephemeral,w subwf indf,w ; rl decf fsr,f ; ->rh ;; ( rl rh ^ ql qh nl nh dl dh sign count ) sb_divide_skip_1 btfss status,c goto sb_divide_skip_2 ; remainder is less ;; ( rl rh ^ ql qh nl nh dl dh sign count ) ;; carry set, remainder is greater than denominator ;; subtract denominator from remainder and save in remainder movlw d'5' subwf fsr,f ; ->dl movf indf,w ; dl movwf r_ephemeral movlw d'6' addwf fsr,f ; ->rl movf r_ephemeral,w subwf indf,f ; rl decf fsr,f ; ->rh btfss status,c decf indf,f ; rh movlw d'6' subwf fsr,f ; ->dh movf indf,w ; dh movwf r_ephemeral movlw d'6' addwf fsr,f ; ->rh movf r_ephemeral,w subwf indf,f ; rh bsf status,c ; shift a 1 into quotient ;; ( rl rh ^ ql qh nl nh dl dh sign count ) sb_divide_skip_2 ;; shift the quotient left decf fsr,f ; ->ql rlf indf,f ; ql decf fsr,f ; ->qh rlf indf,f ; qh ;; loop until all bits checked movlw d'6' subwf fsr,f ; ->count decfsz indf,f ; count goto sb_divide_loop popl ; drop count ;; ( rl rh ql qh nl nh dl dh sign ) ;; adjust stack popf r_ephemeral movlw d'4' addwf fsr,f ; drop nl nh dl dh ;; ( rl rh ql qh ) ;; check effective sign difference and adjust quotient btfss r_ephemeral,7 retlw 0 ; signs were same ;; signs different, negate quotient goto sb_negate ;;; bank 1 follows ifdef __12c509 org 0x200 ; push main to high bank endif ;;; ;;; main program ;;; main ;; clear stack movlw stack movwf fsr ;; clear output port clrf port ;; clear tris mirror clrf r_trism bsf r_trism,b_ow0 bsf r_trism,b_ow1 bsf r_trism,b_in bsf r_trism,b_ow2 bsf r_trism,b_ow3 movf r_trism,w movwt ;; set option register to enable pull-ups and enable GP2 ifdef __12c509 movlw b'10011111' ; NOT_GPPU, T0CS option endif ;; set option register ifdef __16f84 ;; enable port b weak pullups (NOT_RBPU=0) ;; free RA4/TOCKI pin (T0CS=0) ;; prescaler to WDT (PSA=1) ;; prescaler at 1:64, 18ms x 64 = 1.152sec movlw b'01011110' movwf OPTION_REG endif ;; pause for 0.5s to let supply stabilise before chatting pushl d'195' pause_loop pushl d'0' ; 2.65ms bank0 call us10 bank1 decfsz indf,f goto pause_loop popl ;; test for fahrenheit mode, gp3 low ;; (if left open, it is pulled up to high) btfss port,b_in bsf r_trism,b_fahre ifdef notdef noisy ;; need to account for gp0 being input now ;; test for noisy mode; gp0 connected to gp3 bank1 bsf port,gp0 ; turn on gp0 btfss port,gp3 ; see if gp3 goto noisy_skip bcf port,gp0 btfsc port,gp3 goto noisy_skip bsf b_noisy,r_trism goto noisy_done noisy_skip noisy_done endif ;; say g'day gday pushl 'R' ; reset bank0 call tx_header pushl 0 ; start at beginning of table gday_loop movf indf,w ; pull down index bank0 call t_gday ; get the byte from the string iorlw 0 ; is zero? bank1 bz gday_exit ; if so, exit loop pushw bank0 call tx_byte ; transmit the character incf indf,f ; increment index bank1 goto gday_loop gday_exit ;; print C or F according to b_fahre movlw 'C' ; assume low btfsc r_trism,b_fahre movlw 'F' ; set high if non zero pushw bank0 call tx_space call tx_byte ; display the F or C call tx_crlf ; followed by a new line pair ;; select starting sensor movlw 1< 0x1f messg "error: last allocated file register is not in bank 0" endif if last0 > 0xff messg "error: last function in page 0 is beyond call limit" endif if last2 > 0x3ff messg "error: code in page 3 runs over to page 4 (>0x3ff)" endif endif end