;**********************************************************************
;                                                                     *
;    Filename:  TOUCH.ASM                                             *
;    Date:      16 July 1999                                          *
;    Version:   1.2                                                   *
;                                                                     *
;    Author:    W.E.S.Couzijn                                         *
;                                                                     *
;    Processor: PIC12C671 (Microchip)                                 *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Description: Touch-screen controller with serial in/output;      *
;	          resolution about 6 bits (X and Y), single chip      *
;		  solution with internal A/D-converter and built-in   *
;		  calibration procedures.			      *
;                                                                     *
;                 Settings: internal 4 MHz oscillator, no MCLR,       *
;                           watchdog enabled, code protect on,        *
;			    no clock output.			      *
;                                                                     *
;                 Pins: GP0 (AN0, analog in, digital out) = contact 1 *
;                       GP1 (AN1, analog in, digital out) = contact 2 *
;			GP2 (AN2, analog in, digital out) = contact 3 *
;			GP3 (digital input only) = serial data input  *
;                       GP4 (AN3, analog in, digital out) = contact 4 *
;                       GP5 (digital output) = serial data output     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Operation: The module is inactive until it has received a 8-bit  *
;		command on terminal GP3 (serial in). Using the timing *
;		information of this received signal, the module will  *
;		adjust its internal (unstable!) RC-oscillator to be   *
;		able to receive and transmit serial data at the	      *
;		correct baudrate. After that, the command will be     *
;		executed: in case of a calibration-command, the	      *
;		module will wait for the next byte received, and will *
;		store this byte in one of the calibration registers.  *
;		If the command is a readout-command, the module will  *
;		measure the current touchscreen-input and send it     *
;		back (1 byte) after calculation and calibration.      *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Serial communications at 9600 baud, no parity, 2 stopbits.	      *
;                                                                     *
;    Commands given to the module:				      *
;		0Fh = Set offset-parameter X-axis top position.       *
;		2Fh = Set offset-parameter X-axis bottom position.    *
;		4Fh = Set offset-parameter Y-axis top position.       *
;		6Fh = Set offset-parameter Y-axis bottom position.    *
;		8Fh = Set screen-width parameter (pixels on X-axis).  *
;		AFh = Set screen-height parameter (pixels on Y-axis). *
;		CFh = Get software version, parameters and self-test. *
;		EFh = Read current touch-position and status.	      *
;                                                                     *
;    Data sent to the module (only with Set-commands):		      *
;		bit 7 = high, bit 0..6 = value to be set.	      *
;                                                                     *
;    Data received from the module:				      *
;	commands 0Fh..AFh -> the received data is echo-ed back.	      *
;	command CFh -> byte 1 contains the software version in BCD,   *
;		       byte 2 the offset-parameter X-axis (top),      *
;		       byte 3 the offset-parameter X-axis (bottom),   *
;		       byte 4 the offset-parameter Y-axis (top),      *
;		       byte 5 the offset-parameter Y-axis (bottom),   *
;		       byte 6 the screen-width parameter (X-axis),    *
;		       byte 7 the screen-height parameter (Y-axis),   *
;		       byte 8 the self-test status, and bit 7 high.   *
;			(0=Ok, 1=X-direction unconnected,	      *
;			 2=Y-direction unconnected, 3=both,	      *
;			 4=X-direction shorted to GND, 8=Y shorted,   *
;			 12=both shorted to GND)		      *
;	command EFh -> When the screen is not being touched at all,   *
;		       the first byte will be 80h, otherwise byte 1   *
;		       will give you the X-position (bit 7 low), and  *
;		       byte 2 will give the Y-position (bit 7 high).  *
;                                                                     *
;    In general: when bit 7=high, the command-execution has been      *
;		 finished and another command can be given.           *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Connections: GP0 and GP2 are connected to the contacts in the    *
;		  X-direction; GP1 and GP4 in the Y-direction.        *
;		  GP2 and GP4 are connected to ground with a 1nF      *
;		  capacitor to stabilize the analog inputs.           *
;                                                                     *
;    Measurements: GP0, GP1, GP2 and GP4 are digital outputs to GND   *
;		  when the module is inactive. When it starts a       *
;		  measurement, GP1 and GP4 are configured as analog   *
;		  inputs while GP0 and GP2 are still GND. Now, an     *
;		  A/D-conversion is done on GP4; if the result is     *
;		  not GND (with a small error), the status of the     *
;		  readout is a no-touch situation. GP1 has internal   *
;		  pull-ups enabled and will therefore pull GP4 up.    *
;		  Otherwise, GP1 is now set to Vcc and A/D-conversion *
;		  is done on GP0, GP2 and GP4. The digital outputs    *
;		  won't output exactly GND and VCC, and also the A/D  *
;		  converter makes some errors, so we can compensate   *
;		  for those errors if we measure both the input and   *
;		  the outputs with the same A/D-converter.	      *
;		  With the same procedure, the Y-position is measured *
;		  after which the calculations start. When H, L and X *
;		  are the A/D-converter values of GP0, GP2 and GP4,   *
;		  and T, B and S are the top-offset, bottom-offset    *
;		  and size in X-direction, this formula is used to    *
;		  get the correct X-position:			      *
;                                                                     *
;		  0<Xpos<S = S*((128(X-L)-T(H-L))/((H-L)(128-T-B))    *
;                                                                     *
;		  This way, the total screen is set to 128 pixels,    *
;		  the top and bottom margins are cut off, and the     *
;		  part of the screen which is left, is scaled to the  *
;		  desired sizes. It will be clear that the sum of the *
;		  offsets can't be greater than 128.		      *
;                                                                     *
;**********************************************************************

		LIST      P=12c671
		#INCLUDE <p12c671.inc>

		__CONFIG   _CP_OFF & _WDT_ON & _MCLRE_OFF & _INTRC_OSC_NOCLKOUT & _PWRTE_ON 

		__IDLOCS H'1100'+VERSION_NUM	;1=User interface,1=Touchscreen

VERSION_NUM	EQU H'12'	;Version number of this converter (BCD)

;*********************** BIT DEFINITIONS ******************************

TOUCHX1		EQU 0		;measure=AN0-in, internal pull-up
TOUCHY1		EQU 1		;measure=AN1-in, internal pull-up
TOUCHX2		EQU 2		;measure=AN2-in
TOUCHY2		EQU 4		;measure=AN3-in
ANX1		EQU 0x40
ANY1		EQU 0x48
ANX2		EQU 0x50
ANY2		EQU 0x58
SERIALIN	EQU 3		;Serial data input, internal pull-up
SERIALOUT	EQU 5		;Serial data output @9600 baud

;******************** CONSTANTS DEFINITIONS ***************************

F_OSC		EQU 4000	;4 Mhz internal oscillator
BAUDRATE	EQU 9600	;9600 baud (8 bits, 2 stopbits)
CYCLES		EQU (F_OSC*250)/BAUDRATE
MARGIN		EQU CYCLES/10
RDMARGIN	EQU 3

;*********************** BYTE DEFINITIONS *****************************

		CBLOCK 0x20

BITTIME		;Number of cycles for one serial bit-length, adjustable
BUFFER		;General buffer 8 bits
BITCNT		;Bit counter for serial communications
SERDATA		;Serial data buffer (transmit/receive)
OFFSETXT	;Offset parameter X-axis, top
OFFSETXB	;Offset parameter X-axis, bottom
OFFSETYT	;Offset parameter Y-axis, top
OFFSETYB	;Offset parameter Y-axis, bottom
SIZEX		;Size parameter X-axis, number of pixels
SIZEY		;Size parameter Y-axis, number of pixels
SELFTEST	;Self-test status (and bit 7=high)
OLDX		;Old X-position (for hysteresis)
OLDY		;Old Y-position (for hysteresis)
OLD_Y		;Old Y-position (for detection first touch)
XPOS		;X-position (and bit 7=no touch)
YPOS		;Y-position (and bit 7=high)
X_LO		;Low digital level while measuring X-position
X_HI		;High digital level while measuring X-position
X_VAL		;Measured value in X-direction
Y_LO		;Low digital level while measuring Y-position
Y_HI		;High digital level while measuring Y-position
Y_VAL		;Measured value in Y-direction
MUL1		;First multiply variable (8 bits)
MUL2		;Second multiply variable (7 bits)
MULRES1:2	;Result of 8*7=15 bits multiplication
MUL3:2		;First multiply variable (15 bits)
MULRES2:3	;Result of 15*7=22 bits multiplication

		ENDC

;************************ PROGRAM START *******************************

		ORG 0x000
		GOTO INIT		;Execute init routine

;************************ INIT ROUTINE ********************************

INIT		BSF STATUS,RP0
		CALL OSCVALUE
		MOVWF OSCCAL		;Set oscillator calibration value
		CLRF INTCON
		CLRF PIE1		;No interrupts used
		CLRWDT
		MOVLW 7
		MOVWF OPTION_REG	;Internal pull-ups, 1:256 prescaler
		MOVLW 7
		MOVWF ADCON1		;All channels can be digital I/O
		MOVLW (1<<SERIALIN)+3
		MOVWF TRISIO		;Set pins as in&outputs
		BCF STATUS,RP0
		MOVLW 1<<SERIALOUT
		MOVWF GPIO		;Serial output high
		MOVLW 0x40
		MOVWF ADCON0		;Conversion-time 19us
		MOVLW 24
		MOVWF OFFSETXT
		MOVLW 24
		MOVWF OFFSETXB
		MOVLW 32
		MOVWF OFFSETYT
		MOVLW 32
		MOVWF OFFSETYB
		MOVLW 127
		MOVWF SIZEX
		MOVWF SIZEY		;No offsets, X/Y-sizes both 0..127
		MOVLW 128
		MOVWF OLDX
		MOVWF OLDY		;No old X/Y-positions
		CLRF SELFTEST
		MOVLW 100
		CALL WAIT
		BTFSC GPIO,TOUCHX1
		BSF SELFTEST,0
		BTFSC GPIO,TOUCHY1
		BSF SELFTEST,1
		BSF GPIO,TOUCHX2
		BSF GPIO,TOUCHY2
		MOVLW 100
		CALL WAIT
		BTFSS GPIO,TOUCHX1
		BSF SELFTEST,2
		BTFSS GPIO,TOUCHY1
		BSF SELFTEST,3		;Selftest completed
		BSF STATUS,RP0
		MOVLW (1<<SERIALIN)
		MOVWF TRISIO
		BCF STATUS,RP0

;************************ MAIN PROGRAM ********************************

MAIN		MOVLW 0x3F
		MOVWF GPIO		;Inactive: all pins high
		CLRF BITTIME
		CLRF SERDATA
		MOVLW 4
		MOVWF BITCNT
MAINWAIT1	MOVLW 8
		MOVWF INTCON
		BTFSS GPIO,SERIALIN	;Wait for startbit
		GOTO MAINWAIT2
		CLRWDT
		SLEEP
		GOTO MAINWAIT1
MAINWAIT2	BTFSS GPIO,SERIALIN
		GOTO MAINWAIT2		;Wait for bit 0 (should be low)
MAINWAIT3	INCF BITTIME,F
		BTFSC GPIO,SERIALIN
		GOTO MAINWAIT3		;Wait for bit 4 (should be low)
MAINWAIT4	RRF BITTIME,W
		ANDLW 0x7F
		CALL WAIT		;Wait for 0.5 bit (sampling in middle)
MAINRECV	MOVLW -9
		ADDWF BITTIME,W
		CALL WAIT		;Wait for next bit to receive
		BCF STATUS,C
		BTFSC GPIO,SERIALIN
		BSF STATUS,C
		RRF SERDATA,F		;Receive bit
		DECFSZ BITCNT,F
		GOTO MAINRECV		;Receive next bit
		CLRWDT
		BTFSS SERDATA,7		;Received: bit 7=STOP, 6..4=command
		GOTO MAINEND		;Wrong reception: stopbit not 1
		MOVLW -CYCLES+MARGIN	;Check reliability of bittime found
		ADDWF BITTIME,W
		BTFSS STATUS,C
		GOTO MAINEND		;Bittime too small
		MOVLW -CYCLES-MARGIN
		ADDWF BITTIME,W
		BTFSC STATUS,C
		GOTO MAINEND		;Bittime too large
		MOVLW 0xE0
		XORWF SERDATA,W
		BTFSC STATUS,Z		;Command=Read params and self-test?
		GOTO READPARAMS		;Yes -> return parameters & status
		MOVLW 0xF0
		XORWF SERDATA,W
		BTFSC STATUS,Z		;Command=Read touch position?
		GOTO READPOS		;Yes -> return touch position
		SWAPF SERDATA,W
		ANDLW 7
		ADDLW OFFSETXT
		MOVWF FSR
		MOVLW 8
		MOVWF BITCNT
MAINDATA	CLRWDT
		BTFSC GPIO,SERIALIN
		GOTO MAINDATA
		RRF BITTIME,W
		ADDWF BITTIME,W
		ADDLW -5
		CALL WAIT
MAINREC		BCF STATUS,C
		BTFSC GPIO,SERIALIN
		BSF STATUS,C
		RRF SERDATA,F
		MOVLW -9
		ADDWF BITTIME,W
		CALL WAIT
		DECFSZ BITCNT,F
		GOTO MAINREC
		BTFSS GPIO,SERIALIN
		GOTO MAINEND
		BSF OLDX,7
		BSF OLDY,7
		MOVFW SERDATA
		BTFSC SERDATA,7
		MOVWF INDF
		BCF INDF,7
		CALL SEND9600
		GOTO MAIN
MAINEND		MOVLW CYCLES
		CALL WAIT
		GOTO MAIN

READPARAMS	BSF SELFTEST,7
		MOVLW VERSION_NUM
		CALL SEND9600
		MOVFW OFFSETXT
		CALL SEND9600
		MOVFW OFFSETXB
		CALL SEND9600
		MOVFW OFFSETYT
		CALL SEND9600
		MOVFW OFFSETYB
		CALL SEND9600
		MOVFW SIZEX
		CALL SEND9600
		MOVFW SIZEY
		CALL SEND9600
		MOVFW SELFTEST
		CALL SEND9600
		GOTO MAIN

READAGAIN	BCF YPOS,7
		GOTO RDPOSLOOP
READPOS		BSF YPOS,7
		MOVFW OLDY
		MOVWF OLD_Y
RDPOSLOOP	MOVLW (1<<SERIALOUT)+(1<<TOUCHY1)+(1<<TOUCHY2)
		MOVWF GPIO
		BSF STATUS,RP0
		MOVLW (1<<SERIALIN)+(1<<TOUCHY1)+(1<<TOUCHY2)
		MOVWF TRISIO
		BCF STATUS,RP0
		CALL WAITSHORT
		BSF XPOS,7
		BTFSC GPIO,TOUCHY1
		GOTO POSREADY
		BSF STATUS,RP0
		BSF OPTION_REG,7
		BCF STATUS,RP0
		BSF GPIO,TOUCHX1
		CLRWDT
		BTFSC YPOS,7
		GOTO RDPOSXVAL
		MOVLW ANX1+1
		MOVWF ADCON0
		CALL WAITSHORT
		BSF ADCON0,GO
		BTFSC ADCON0,GO
		GOTO $-1
		MOVFW ADRES
		MOVWF X_HI
		CLRWDT
		MOVLW ANX2+1
		MOVWF ADCON0
		CALL WAITSHORT
		BSF ADCON0,GO
		BTFSC ADCON0,GO
		GOTO $-1
		MOVFW ADRES
		MOVWF X_LO
		CLRWDT
RDPOSXVAL	MOVLW ANY2+1
		MOVWF ADCON0
		MOVLW 60
		CALL WAIT
		BSF ADCON0,GO
		BTFSC ADCON0,GO
		GOTO $-1
		MOVFW ADRES
		SUBWF X_VAL,W
		BTFSS STATUS,C
		SUBLW 0
		MOVWF MUL1
		MOVFW ADRES
		MOVWF X_VAL
		MOVLW (1<<SERIALOUT)+(1<<TOUCHX1)+(1<<TOUCHX2)
		MOVWF GPIO
		BSF STATUS,RP0
		BCF OPTION_REG,7
		MOVLW (1<<SERIALIN)+(1<<TOUCHX1)+(1<<TOUCHX2)
		MOVWF TRISIO
		BCF STATUS,RP0
		CALL WAITSHORT
		BTFSC GPIO,TOUCHX1
		GOTO POSREADY
		BSF STATUS,RP0
		BSF OPTION_REG,7
		BCF STATUS,RP0
		BCF XPOS,7
		BSF GPIO,TOUCHY1
		CLRWDT
		BTFSC YPOS,7
		GOTO RDPOSYVAL
		MOVLW ANY1+1
		MOVWF ADCON0
		CALL WAITSHORT
		BSF ADCON0,GO
		BTFSC ADCON0,GO
		GOTO $-1
		MOVFW ADRES
		MOVWF Y_HI
		CLRWDT
		MOVLW ANY2+1
		MOVWF ADCON0
		CALL WAITSHORT
		BSF ADCON0,GO
		BTFSC ADCON0,GO
		GOTO $-1
		MOVFW ADRES
		MOVWF Y_LO
		CLRWDT
RDPOSYVAL	MOVLW ANX2+1
		MOVWF ADCON0
		MOVLW 60
		CALL WAIT
		BSF ADCON0,GO
		BTFSC ADCON0,GO
		GOTO $-1
		MOVFW ADRES
		SUBWF Y_VAL,W
		BTFSS STATUS,C
		SUBLW 0
		MOVWF MUL2
		MOVFW ADRES
		MOVWF Y_VAL
		BCF ADCON0,1
		MOVLW 0x3F
		MOVWF GPIO
		BSF STATUS,RP0
		BCF OPTION_REG,7
		MOVLW (1<<SERIALIN)
		MOVWF TRISIO
		BCF STATUS,RP0
		BTFSC YPOS,7
		GOTO READAGAIN
		MOVLW RDMARGIN
		SUBWF MUL1,W
		BTFSC STATUS,C
		GOTO READAGAIN
		MOVLW RDMARGIN
		SUBWF MUL2,W
		BTFSC STATUS,C
		GOTO READAGAIN
		MOVFW X_VAL
		SUBWF X_HI,W
		BTFSS STATUS,C
		GOTO READAGAIN
		MOVFW Y_VAL
		SUBWF Y_HI,W
		BTFSS STATUS,C
		GOTO READAGAIN
		CLRF XPOS
		CLRF YPOS
		MOVFW X_LO
		SUBWF X_HI,F
		SUBWF X_VAL,W
		MOVWF MUL3+1
		BCF STATUS,C
		RRF MUL3+1,F
		CLRF MUL3
		RRF MUL3,F
		MOVLW 128
		MOVWF X_LO
		MOVFW OFFSETXT
		ADDWF OFFSETXB,W
		SUBWF X_LO,F
		BTFSS STATUS,C
		GOTO XPOSZERO	;MUL3 = 128*(X-L); X_HI = (H-L); X_LO = (128-T-B)
		MOVFW X_HI
		MOVWF MUL1
		MOVFW OFFSETXT
		MOVWF MUL2
		CALL MULT8X7	;Calculate T*(H-L)
		MOVFW MULRES1
		SUBWF MUL3,F
		BTFSS STATUS,C
		DECF MUL3+1,F
		MOVFW MULRES1+1
		SUBWF MUL3+1,F	;MUL3 contains 128*(X-L)-T*(H-L)
		BTFSS STATUS,C
		GOTO XPOSZERO
		INCF SIZEX,W
		MOVWF MUL2
		CALL MULT15X7	;Calculate S*(128*(X-L)-T*(H-L))
		MOVFW X_HI
		MOVWF MUL1
		MOVFW X_LO
		MOVWF MUL2
		CALL MULT8X7	;Calculate (H-L)(128-T-B)
		MOVFW OLDX
		MOVWF MUL3
		MOVFW SIZEX
		CALL DIV22X15	;Divide MULRES2 by MULRES1 -> W
		MOVWF XPOS
XPOSZERO	MOVFW Y_LO
		SUBWF Y_HI,F
		SUBWF Y_VAL,W
		MOVWF MUL3+1
		BCF STATUS,C
		RRF MUL3+1,F
		CLRF MUL3
		RRF MUL3,F
		MOVLW 128
		MOVWF Y_LO
		MOVFW OFFSETYT
		ADDWF OFFSETYB,W
		SUBWF Y_LO,F
		BTFSS STATUS,C
		GOTO YPOSZERO	;MUL3 = 128*(Y-L); Y_HI = (H-L); Y_LO = (128-T-B)
		MOVFW Y_HI
		MOVWF MUL1
		MOVFW OFFSETYT
		MOVWF MUL2
		CALL MULT8X7	;Calculate T*(H-L)
		MOVFW MULRES1
		SUBWF MUL3,F
		BTFSS STATUS,C
		DECF MUL3+1,F
		MOVFW MULRES1+1
		SUBWF MUL3+1,F	;MUL3 contains 128*(Y-L)-T*(H-L)
		BTFSS STATUS,C
		GOTO YPOSZERO
		INCF SIZEY,W
		MOVWF MUL2
		CALL MULT15X7	;Calculate S*(128*(Y-L)-T*(H-L))
		MOVFW Y_HI
		MOVWF MUL1
		MOVFW Y_LO
		MOVWF MUL2
		CALL MULT8X7	;Calculate (H-L)(128-T-B)
		MOVFW OLDY
		MOVWF MUL3
		MOVFW SIZEY
		CALL DIV22X15	;Divide MULRES2 by MULRES1 -> W
		MOVWF YPOS
YPOSZERO	EQU $		;end of calculation
POSREADY	MOVFW XPOS
		MOVWF OLDX
		MOVFW YPOS
		MOVWF OLDY
		BSF STATUS,RP0
		MOVLW (1<<SERIALIN)
		MOVWF TRISIO
		BCF STATUS,RP0
		MOVLW 0x3F
		MOVWF GPIO
		BCF ADCON0,1
		MOVLW 128
		BTFSC OLD_Y,7	;First touch?
		GOTO NOTOUCH	;Yes -> skip...
		BTFSS XPOS,7
		GOTO TOUCHED
		BSF OLDX,7
		BSF OLDY,7
		GOTO NOTOUCH
TOUCHED		BSF YPOS,7
		MOVFW XPOS
		CALL SEND9600
		MOVFW YPOS
NOTOUCH		CALL SEND9600
		GOTO MAIN

MULT8X7		CLRF MULRES1
		CLRF MULRES1+1
		CLRF BUFFER
MULTIPLY1	BTFSS MUL2,0
		GOTO MULTIPLY2
		MOVFW MUL1
		ADDWF MULRES1,F
		BTFSC STATUS,C
		INCF MULRES1+1,F
		MOVFW BUFFER
		ADDWF MULRES1+1,F
MULTIPLY2	BCF STATUS,C
		RLF MUL1,F
		RLF BUFFER,F
		RRF MUL2,F
		TSTF MUL2
		BTFSS STATUS,Z
		GOTO MULTIPLY1
		RETURN		;Multiply, MULRES1(15)=MUL1(8)xMUL2(7)

MULT15X7	CLRF MULRES2
		CLRF MULRES2+1
		CLRF MULRES2+2
		CLRF BUFFER
MULTIPLY3	BTFSS MUL2,0
		GOTO MULTIPLY4
		MOVFW MUL3
		ADDWF MULRES2,F
		BTFSC STATUS,C
		INCF MULRES2+1,F
		MOVFW MUL3+1
		ADDWF MULRES2+1,F
		BTFSC STATUS,C
		INCF MULRES2+2,F
		MOVFW BUFFER
		ADDWF MULRES2+2,F
MULTIPLY4	BCF STATUS,C
		RLF MUL3,F
		RLF MUL3+1,F
		RLF BUFFER,F
		RRF MUL2,F
		TSTF MUL2
		BTFSS STATUS,Z
		GOTO MULTIPLY3
		RETURN		;Multiply, MULRES2(22)=MUL3(15)xMUL2(7)

DIV22X15	MOVWF MUL1	;Save W=maximum result
		MOVLW 10
		MOVWF BUFFER
		CLRF MUL2
		BCF STATUS,C
DIVIDE1		RLF MUL2,F
		MOVFW MUL1
		BTFSC STATUS,C
		RETURN
		BCF STATUS,C
		RLF MULRES2,F
		RLF MULRES2+1,F
		RLF MULRES2+2,F
		MOVFW MUL1
		BTFSC STATUS,C
		RETURN		;Overflow -> maximum result
		MOVFW MULRES1
		SUBWF MULRES2+1,W
		MOVFW MULRES1+1
		BTFSS STATUS,C
		INCF MULRES1+1,W
		SUBWF MULRES2+2,W
		BTFSS STATUS,C
		GOTO DIVIDE2
		MOVFW MULRES1
		SUBWF MULRES2+1,F
		MOVFW MULRES1+1
		BTFSS STATUS,C
		INCF MULRES1+1,W
		SUBWF MULRES2+2,F
DIVIDE2		DECFSZ BUFFER,F
		GOTO DIVIDE1
		BTFSC MUL3,7
		GOTO DIVIDE3
		BTFSS STATUS,C
		GOTO DIVIDE4
		BCF STATUS,C
		RLF MUL3,F
		INCF MUL2,W
		XORWF MUL3,W
		BTFSC STATUS,Z
		INCF MUL2,F
		GOTO DIVIDE3
DIVIDE4		BSF STATUS,C
		RLF MUL3,F
		INCF MUL3,W
		XORWF MUL2,W
		BTFSC STATUS,Z
		DECF MUL2,F
DIVIDE3		BCF STATUS,C
		RRF MUL2,F
		MOVFW MUL1
		SUBWF MUL2,W
		MOVFW MUL1
		BTFSS STATUS,C
		MOVFW MUL2
		RETURN		;Divide, W=Min(W,MULRES2(22)/MULRES1(15))

SEND9600	BCF GPIO,SERIALOUT
		MOVWF SERDATA
		MOVLW 9
		MOVWF BITCNT
		MOVLW -11
		ADDWF BITTIME,W
		CALL WAIT
SENDBIT		BSF STATUS,C
		RRF SERDATA,F
		BTFSS STATUS,C
		GOTO SENDLOW
		BSF GPIO,SERIALOUT
		GOTO SENDNEXT
SENDLOW		BCF GPIO,SERIALOUT
		NOP
SENDNEXT	MOVLW -12
		ADDWF BITTIME,W
		CALL WAIT
		DECFSZ BITCNT,F
		GOTO SENDBIT
		RETURN

WAITSHORT	GOTO $+1
		GOTO $+1
		GOTO $+1
		GOTO $+1
		GOTO $+1
		GOTO $+1
		GOTO $+1
		GOTO $+1
		GOTO $+1
		GOTO $+1
		RETURN

WAIT		MOVWF BUFFER		;WAIT waits for a variable number
		MOVLW -9		;of clock cycles, given by the value
		ADDWF BUFFER,F		;in W, between 41 and 255, incl. CALL
WAIT2		MOVLW -7		;BUFFER is used (!)
		ADDWF BUFFER,F
		MOVLW 3
		ANDWF BUFFER,W
		BTFSS STATUS,Z
		GOTO WAIT2
		RRF BUFFER,F
		RRF BUFFER,F
		MOVLW 0x3F
		ANDWF BUFFER,F
WAIT1		CLRWDT
		DECFSZ BUFFER,F
		GOTO WAIT1
		RETURN

;************************ OSCCAL VALUE ********************************

		ORG 0x3FF
OSCVALUE	RETLW 0xB0

		END
