Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
#DEFINE BANK0 BCF 3,5
#DEFINE BANK1 BSF 3,5
INDF EQU 0x00
OPTN EQU 0x01
PCL EQU 0x02
STATUS EQU 0x03
FSR EQU 0x04
PORTA EQU 0x05
TRISA EQU 0x05
PORTB EQU 0x06
TRISB EQU 0x06
INTCON EQU 0x0B
MISC1 EQU 0x0C ;misc use
MISC2 EQU 0x0D ;misc use
COUNT0 EQU 0x0E ;counter 0
COUNT1 EQU 0x0F ;counter 1
FEET1 EQU 0x10 ;feet byte 1 LSB
FEET2 EQU 0x11 ;feet byte 2 MSB
ANSA1 EQU 0x12 ;answer byte 1 LSB
ANSA2 EQU 0x13 ;answer byte 2 MSB
ANSA3 EQU 0x14 ;answer byte 3 MSB
ANSA4 EQU 0x15 ;answer byte 4 LSB
ANSA5 EQU 0x16 ;answer byte 5 MSB
ANSA6 EQU 0x17 ;answer byte 6 MSB
TOP0 EQU 0x18 ;top of division byte 1 LSB
TOP1 EQU 0x19 ;top of division byte 2 NSB
TOP2 EQU 0x1A ;top of division byte 3 MSB
DIV1 EQU 0x1B ;divider byte 1 LSB
DIV2 EQU 0x1C ;divider byte 2 MSB
LOOPB EQU 0x1D ;loop counter B
STORE1 EQU 0x1E ;general store 1
STORE2 EQU 0x1F ;general store 2
LOOPA EQU 0x20 ;loop counter A - for LCD only
RSLINE EQU 0x21 ;bit 4 = RS line flag for LCD
CLKCNT EQU 0x22 ;pre-counter for CLOCK
METRE0 EQU 0x23 ;metres byte 1 LSB
METRE1 EQU 0x24 ;metres byte 2 NSB
METRE2 EQU 0x25 ;metres byte 3 MSB
INCH1 EQU 0x26 ;inches byte 1 LSB
INCH2 EQU 0x27 ;inches byte 2 MSB
MASK EQU 0x28 ;foreground mask value (1 per metre)
ZERO EQU 0x29 ;zero count flag
SAVE EQU 0x2A ;SAVE flag
W EQU 0
F EQU 1
C EQU 0
DC EQU 1
Z EQU 2
GIE EQU 7 ;global interrupt bit
RBIF EQU 0 ;RB4-RB7 change interrupt flag
ORG 0
goto START
START clrf PORTA
movlw B'01000000'
movwf PORTB
BANK1
movlw B'00011100'
movwf TRISA ;Port A0-A1 as output, A2-A4 as input
movlw B'11000000'
movwf TRISB ;Port B0-B5 as output, B6-B7 as input
movlw B'00000101' ;set timer ratio 1:64
movwf OPTN ;pull-ups on (bit 7 = 0)
BANK0
CLRINT bcf INTCON,GIE ;disable all interrupts
btfsc INTCON,GIE ;are all interrupts disabled?
goto CLRINT ;no, try again
CLRALL movlw 0x0C ;clear registers
movwf FSR
CLRA2 clrf INDF
incf FSR,F
btfss FSR,6 ;increment until registers through 0x40 are clear
goto CLRA2
goto SETUP
TBDEC1 ADDWF PCL,F ;table for decimalisation lsb
retlw 0x0A ;lsb of 10
retlw 0x64 ;lsb of 100
retlw 0xE8 ;lsb of 1000
retlw 0x10 ;lsb of 10000
TBDEC2 ADDWF PCL,F ;table for decimalisation msb
retlw 0 ;msb of 10
retlw 0 ;msb of 100
retlw 0x03 ;msb of 1000
retlw 0x27 ;msb of 10000
MESSAG1 addwf PCL,F
retlw 'U'
retlw 'A'
retlw 'H'
retlw ' '
retlw 'R'
retlw 'A'
retlw 'N'
retlw 'G'
retlw 'E'
retlw ' '
retlw 'F'
retlw 'I'
retlw 'N'
retlw 'D'
retlw 'E'
retlw 'R'
MESSAG2 addwf PCL,F
retlw 'P'
retlw 'R'
retlw 'E'
retlw 'S'
retlw 'S'
retlw ' '
retlw 'S'
retlw 'E'
retlw 'N'
retlw 'D'
retlw ' '
retlw 'K'
retlw 'E'
retlw 'Y'
retlw ' '
retlw ' '
SETUP call PAUSIT ;delay
LCDSET MOVLW B'00000011' ;initialize display
movwf PORTB
NOP
BSF PORTB,5
NOP
NOP
BCF PORTB,5
CALL PAUSIT
BSF PORTB,5
NOP
NOP
BCF PORTB,5
CALL PAUSIT
BSF PORTB,5
NOP
NOP
BCF PORTB,5
CALL PAUSIT
movlw B'00000010' ;set for 4bit operation
movwf PORTB
NOP
BSF PORTB,5
NOP
NOP
BCF PORTB,5
CALL PAUSIT
MOVLW B'00101100'
CALL LCDLIN
MOVLW B'00000110' ;Display Off
CALL LCDLIN
MOVLW B'00001100' ;Clear Display
CALL LCDLIN
CALL PAUSIT
MOVLW B'00000001' ;Entry Mode Set - Increment, shift
CALL LCDLIN
MOVLW B'00000010' ;Display On - Set cursor off and blink off
CALL LCDLIN
CALL PAUSIT
clrf LOOPB
call LCD1
TITLE1 movf LOOPB,W ;get table address
call MESSAG1 ;get set-up instruction
call LCDOUT ;perform it
incf LOOPB,F ;inc loop
btfss LOOPB,4
goto TITLE1
clrf LOOPB
call LCD21
TITLE2 movf LOOPB,W ;get table address
call MESSAG2 ;get set-up instruction
call LCDOUT ;perform it
incf LOOPB,F ;inc loop
btfss LOOPB,4
goto TITLE2
INTRPT btfsc PORTA,2 ;is SEND switch on RA2 pressed?
call TXIT ;yes
btfsc PORTA,4 ;is MASK switch on RA4 pressed?
call MASKIT ;yes
goto INTRPT
TXIT movlw D'10'
movwf LOOPB ;set transmission loop to 10
clrf COUNT0 ;clear counters
clrf COUNT1
bsf PORTA,0
bsf SAVE,0
BEAMIT nop ;send 40kHz signal
nop
nop
nop
nop
nop
nop
nop
comf PORTA,F ;toggle RA0/RA1
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
comf PORTA,F ;toggle RA0/RA1
decfsz LOOPB,F
goto BEAMIT
clrf PORTA
call RECEIVE
call PAUSIT ;pause
call PAUSIT
return
RECEIVE movf MASK,W
btfsc STATUS,Z
goto DEFMASK ;if mask 0 do default delay
movf MASK,W
movwf LOOPB
goto MASK1 ;perform mask delay
DEFMASK movlw D'240'
movwf ANSA1
movlw D'2'
movwf ANSA2
DEFMLP decfsz ANSA1,F
goto DEFMLP
decfsz ANSA2,F
goto DEFMLP
goto MASK0
MASK1 movlw D'2' ;masking delays
movwf ANSA2
movlw D'48'
movwf ANSA1
MASK2 movlw D'4'
movwf ANSA3
MASK3 decfsz ANSA3,F
goto MASK3
decfsz ANSA1,F
goto MASK2
decfsz ANSA2,F
goto MASK2
decfsz LOOPB,F
goto MASK1
MASK0 bcf INTCON,RBIF ;clear RB4-RB7 interrupt change flag
bcf ZERO,0
LISTEN btfsc INTCON,RBIF ;has echo been heard
goto SHWCNT
movlw D'1'
addwf COUNT0,F
movf STATUS,W
andlw 1
addwf COUNT1,F ;add Carry to COUNT1
btfss STATUS,C
goto LISTEN
bsf ZERO,0 ;if count registers exceeded set zero
goto METRES
SHWCNT movf MASK,W
btfss STATUS,Z
goto SHWCNT1
movlw D'157' ;add transmission time + minimum distance
addwf COUNT0,F
btfsc STATUS,C
incf COUNT1,F
goto METRES
SHWCNT1 movf MASK,W
movwf LOOPB ;add 490 to count for each MASK value
MASKAD movlw D'234' ;(= LSB 234, MSB 1)
addwf COUNT0,F
btfsc STATUS,C
incf COUNT1,F
incf COUNT1,F
decfsz LOOPB,F
goto MASKAD
METRES call GETMMS ;calculate millimetres
call LCD1 ;show metres on line 1 part 1
movlw METRE1
call DECIMAL ;decimalise metres
movf ANSA5,W
movwf ANSA6
movf ANSA4,W
movwf ANSA5
movlw '.'
movwf ANSA4
movlw D'6'
movwf LOOPB
movlw ANSA6
movwf FSR
movf ANSA6,W
xorlw D'48'
btfss STATUS,Z
goto SHOWMT
movlw ' ' ;blank leading zero
movwf ANSA6
SHOWMT call SHOWDEC
movlw 'm'
call LCDOUT
movlw 't'
call LCDOUT
movlw ' '
call LCDOUT
call LCDOUT
call LCDOUT
call LCDOUT
call LCDOUT
call LCDOUT
call LCDOUT
call LCDOUT
call GETINS ;calculate feet & inches
call GETFEET
call INVERT ;correct for final inches
movf TOP1,W
bcf STATUS,C
btfss ZERO,0 ;is ZERO set?
addlw D'12' ;no
movwf INCH1
movf STATUS,W
andlw 1
addwf TOP2,W
movwf INCH2
movf INCH1,W
xorlw D'12'
btfss STATUS,Z
goto SHOWFT
clrf INCH1
clrf INCH2
incfsz FEET1,F
goto SHOWFT
incf FEET2,F
SHOWFT call LCD21
movlw FEET1
call DECIMAL ;decimalise feet
movlw D'3'
movwf LOOPB
movlw ANSA3
movwf FSR
movf ANSA3,W
xorlw D'48'
btfss STATUS,Z
goto SHWFT2
movlw ' ' ;blank leading zero
movwf ANSA3
movf ANSA2,W
xorlw D'48'
btfss STATUS,Z
goto SHWFT2
movlw ' ' ;blank leading zero
movwf ANSA2
SHWFT2 call SHOWDEC
movlw 'f'
call LCDOUT
movlw 't'
call LCDOUT
SHOWIN movlw INCH1
call DECIMAL ;show remaining inches
movlw D'2'
movwf LOOPB
movlw ANSA2
movwf FSR
movf ANSA2,W
xorlw D'48'
btfss STATUS,Z
goto SHOWIN2
movlw ' ' ;blank leading zero
movwf ANSA2
SHOWIN2 call SHOWDEC
movlw 'i'
call LCDOUT
movlw 'n'
call LCDOUT
movlw ' '
call LCDOUT
call SHOWSW
return
GETMMS clrf METRE0 ;muliply x 1.78 (MSB 1, LSB 200)
movf COUNT0,W ;(a count of 562 = 1 metre)
movwf METRE1 ;(1000/562 = 1.77935943)
movf COUNT1,W
movwf METRE2
movf COUNT0,W
btfsc STATUS,Z
goto GETCM2
movwf LOOPB
GETCM1 movlw D'200'
addwf METRE0,F
movf STATUS,W
andlw 1
addwf METRE1,F
movf STATUS,W
andlw 1
addwf METRE2,F
decfsz LOOPB,F
goto GETCM1
GETCM2 movf COUNT1,W
btfsc STATUS,Z
return
movwf LOOPB
GETCM3 movlw D'200'
addwf METRE1,F
movf STATUS,W
andlw 1
addwf METRE2,F
decfsz LOOPB,F
goto GETCM3
return
GETINS movlw D'25' ;divide by 25.4 for inches measurement
movwf DIV2 ;set divider msb for 25
movlw D'102' ;set lsb for 102 (= 0.4 decimal as binary)
movwf DIV1
movf METRE1,W
movwf STORE1
movf METRE2,W
movwf STORE2
call DIVIDE
movf ANSA1,W
movwf INCH1
movf ANSA2,W
movwf INCH2
return
GETFEET movlw D'12' ;divide by 12.0 for feet measurement
movwf DIV2 ;set divider msb for 12
movlw D'0' ;set lsb for 0
movwf DIV1
movf INCH1,W
movwf STORE1
movf INCH2,W
movwf STORE2
call DIVIDE
movf ANSA1,W
movwf FEET1
movf ANSA2,W
movwf FEET2
return
DIVIDE movf STORE1,W
movwf TOP1
movf STORE2,W
movwf TOP2
clrf TOP0
clrf ANSA1
clrf ANSA2
movf TOP1,W ;is TOP = zero?
iorwf TOP2,W
btfsc STATUS,Z
goto DIVIDE3 ;yes
call INVERT ;invert TOP for adding instead of subtraction
DIVIDE2 movf DIV1,W ;add lsb of DIV to lsb of TOP
addwf TOP0,F
movlw D'1'
andwf STATUS,C ;add carry flag to msb of TOP
addwf TOP1,F
movlw D'1'
andwf STATUS,C ;add carry flag to msb of TOP
addwf TOP2,F
btfsc STATUS,C ;is there a carry?
goto DIVIDE3 ;yes
movf DIV2,W ;no, add msb of DIV to msb of TOP
addwf TOP1,F
movlw D'1'
andwf STATUS,C ;add carry flag to msb of TOP
addwf TOP2,F
btfsc STATUS,C ;is there a carry?
goto DIVIDE3 ;yes
incfsz ANSA1,F ;no, inc counter lsb, is there a zero rollover?
goto DIVIDE2 ;no
incf ANSA2,F ;yes, inc counter msb
goto DIVIDE2
DIVIDE3 return
LCD210 movlw B'11001010'
goto LCDLIN
LCD28 movlw B'11001000'
goto LCDLIN
LCD21 movlw B'11000000'
goto LCDLIN
LCD11 movlw B'10001011'
goto LCDLIN
LCD8 movlw B'10001000'
goto LCDLIN
LCD1 movlw B'10000000'
LCDLIN BCF RSLINE,4 ;clear RS flag - sets LCD command/line
LCDOUT MOVWF STORE1 ;temp store data for LCD
MOVLW D'20' ;set min time between sending full bytes to LCD
MOVWF LOOPA
DELAY DECFSZ LOOPA,F
GOTO DELAY
CALL SENDIT ;send MSB
CALL SENDIT ;send LSB
BSF RSLINE,4 ;set RS flag (default is flag set)
return
SENDIT SWAPF STORE1,F ;get and send data nibble
MOVF STORE1,W
ANDLW 0x0F
IORWF RSLINE,W ;OR the RS bit
MOVWF PORTB ;output the byte
NOP
BSF PORTB,5 ;set E high
NOP
NOP
BCF PORTB,5 ;set E low
RETURN
PAUSIT MOVLW D'10' ;delay set
MOVWF CLKCNT
CLRF INTCON
PAUSE BTFSS INTCON,2 ;has a timer time-out been detected?
GOTO PAUSE ;no
BCF INTCON,2 ;yes
DECFSZ CLKCNT,F ;dec loop, is it zero?
GOTO PAUSE ;no
RETURN ;yes
DECIMAL clrf ANSA1
clrf ANSA2
clrf ANSA3
clrf ANSA4
clrf ANSA5
movwf FSR
movf INDF,W ;check for zero value
incf FSR,F
iorwf INDF,W
btfsc STATUS,Z
goto DEC4
movf INDF,W ;copy value into TOP
movwf TOP2
decf FSR,F
movf INDF,W
movwf TOP1
movlw D'4'
movwf LOOPB
movlw ANSA5
movwf FSR
DECA1 clrf STORE2
decf LOOPB,W
call TBDEC1
movwf MISC1
decf LOOPB,W
call TBDEC2
movwf MISC2
call ADDIT
movwf INDF
decf FSR,F
decfsz LOOPB,F
goto DECA1
movf TOP1,W
movwf INDF
DECA2 addlw D'6'
btfss STATUS,DC
goto DEC4
clrf INDF
incf FSR,F
incf INDF,F
movf INDF,W
goto DECA2
ADDIT call INVERT ;invert to allow adding
ADDIT2 incf STORE2,F
movf MISC1,W
addwf TOP1,F
movlw D'1'
andwf STATUS,W
addwf MISC2,W
addwf TOP2,F
btfss STATUS,C
goto ADDIT2
call INVERT ;invert to allow adding
movf MISC1,W ;subtract last addition value
addwf TOP1,F
btfsc STATUS,C
incf TOP2,F
movf MISC2,W
addwf TOP2,F
decf STORE2,W
return
DEC4 movlw D'48'
iorwf ANSA1,F
iorwf ANSA2,F
iorwf ANSA3,F
iorwf ANSA4,F
iorwf ANSA5,F
return
SHOWDEC movf INDF,W
call LCDOUT
decf FSR,F
decfsz LOOPB,F
goto SHOWDEC
return
INVERT comf TOP1,F
incf TOP1,F
btfsc STATUS,Z
decf TOP2,F
comf TOP2,F
return
MASKIT incf MASK,F
movf MASK,W
xorlw D'5'
btfsc STATUS,Z
clrf MASK
SHOWSW call LCD210
movlw 'M'
call LCDOUT
movlw 'a'
call LCDOUT
movlw 's'
call LCDOUT
movlw 'k'
call LCDOUT
movf MASK,W
btfsc STATUS,Z
goto SW2
movf MASK,W
iorlw D'48'
call LCDOUT
movlw 'm'
goto SW3
SW2 movlw ' '
call LCDOUT
movlw '0'
SW3 call LCDOUT
call PAUSIT
call PAUSIT
call PAUSIT
return
BLANKS movlw D'5'
movwf LOOPB
movlw ANSA5
movwf FSR
movlw D'4'
movwf LOOPA
ZERO1 movf INDF,W ;blank leading zeros
xorlw D'48'
btfss STATUS,Z
goto SHWCT2
movlw D'32'
movwf INDF
decf FSR,F
decfsz LOOPA,F
goto ZERO1
SHWCT2 movlw ANSA5
movwf FSR
call SHOWDEC
return
END