PIC16C84 - Simple Integer Calculations

copyright, Peter H. Anderson, Morgan State University,
Baltimore, MD 21239, July 11, '97

Introduction.

This discussion deals with simple integer calculations using the PIC.

Another discussion offers that in many cases, calculations may not be required or the calculations may be so complex involving natural logs and similar that table lookup might be a much better alternative to performing the calculations using a PIC.

The discussion then offers that in many instances calculations may be reduced to requiring no more than 16-bit addition and subtraction routines, an 8-bit X 8-bit multiply routine, a 16-bit divided by 8-bit divide routine, and BCD conversion routines.

This discussion presents all of these tools except the BCD conversion tools which are discussed eleswhere.

Integer Calculations.

Program CALC_1.ASM presents simple 16-bit add and subtract routines. It also presents 16 bit division and multiplication by powers of two using right and left shifts on a 16-bit quantity.

In the ADD routine two 16-bit quantities Q1 and Q2 are added and the result is returned in R. In the SUB routine, R = Q1 - Q2.

In the simple MULT_SHIFT, R = Q1 << POW. In DIV_SHIFT, R = Q1 >> POW. These may be used for simple multiply and divide by powers of two.

Program CALC_2.ASM presents an 8-bit by 8-bit multiply and a 16-bit divided by 8-bit divide.

In MULT8X8, R = M1 * M2. The routine does not seal with the case of M1 = 0.

In DIV16X8, Q = DIV / DIVSOR. It does not deal with the case of divide by zero.

; CALC_1.ASM
;
; Illustrates routines for 16-bit addition, 16 bit subtraction and
; multiplying and dividing a quantity by a power of two.
;
; Program calculates (8980 + 16657 - 4369) / 128)  * 64
;
; Display is a dummy as a convenient place to set a breakpoint.
;
; Addition 	8950 + 16657 = 25,607
; Subtraction	25,607 - 4369 = 21,238
; Division	21,238 / 128 = 165
; Multiplication	165 * 64 = 10560
;
; copyright, Peter H. Anderson, MSU, July 10, '97
;
	LIST p=16c84
#include <p16c84.inc>	
	__CONFIG 11h

	CONSTANT VARS=0CH

Q1_HI	EQU VARS+0		
Q1_LO	EQU VARS+1

Q2_HI	EQU VARS+2		 
Q2_LO	EQU VARS+3

POW	EQU VARS+4

R_HI	EQU VARS+5
R_LO	EQU VARS+6

	ORG 000H
	
	MOVLW 23H		; Q1 = 2314H (8980 Decimal)
	MOVWF Q1_HI
	MOVLW 14H
	MOVWF Q1_LO

	MOVLW 41H		; Q2 = 4111H (16657 Decimal)
	MOVWF Q2_HI
	MOVLW 11H
	MOVWF Q2_LO

	CALL ADD		; Q1 + Q2 is now in R_HI and R_LO
	CALL DISPLAY
	
	MOVF R_HI, W		; Q1 = (2314H + 4111H) or 25,637
	MOVWF Q1_HI
	MOVF R_LO, W
	MOVWF Q1_LO

	MOVLW 11H		; Q2 = 1111H (4369 Decimal)
	MOVWF Q2_HI
	MOVLW 11H
	MOVWF Q2_LO

	CALL SUB		; R = Q1 - Q2 = 21,268 dec
	CALL DISPLAY

	MOVF R_HI, W		; Q1 = 21,268
	MOVWF Q1_HI
	MOVF R_LO, W
	MOVWF Q1_LO

	MOVLW .7
	MOVWF POW

	CALL DIV_SHIFT		; R = 166 dec
	CALL DISPLAY

	MOVF R_HI, W		; Q1 = 166 dec
	MOVWF Q1_HI
	MOVF R_LO, W
	MOVWF Q1_LO

	MOVLW .6
	MOVWF POW

	CALL MULT_SHIFT		; R = 10,560
	CALL DISPLAY

DONE:	GOTO DONE

;;;;;;

ADD:  ; R = Q1 + Q2

	MOVF Q1_LO, W
	ADDWF Q2_LO, W
	MOVWF R_LO

	MOVF Q1_HI, W
	BTFSC STATUS, C
	ADDLW .1		; if a carry occurred, add 1

	ADDWF Q2_HI, W
	MOVWF R_HI
	
	RETURN

SUB:	; R = Q1 - Q2

	MOVF Q2_LO, W
	SUBWF Q1_LO, W	; W = Q1_LO - Q2_LO
	MOVWF R_LO

	BTFSS STATUS, C
	GOTO BORROW
	GOTO SUB_1
BORROW:
	DECF Q1_HI, F
	
SUB_1:
	MOVF Q2_HI, W
	SUBWF Q1_HI, W	; W = Q1_HI - Q2_HI
	MOVWF R_HI

	RETURN

DIV_SHIFT:	; Q1 / 2^POW.  Note that POW is destroyed

	MOVF Q1_HI, W
	MOVWF R_HI
	MOVF Q1_LO, W
	MOVWF R_LO

DIV_SHIFT_1
	BCF STATUS, C
	RRF R_HI, F
	RRF R_LO, F
	DECFSZ POW, F
	GOTO DIV_SHIFT_1
	RETURN

MULT_SHIFT:	; Q1 * 2^POW.  Note that POW is destroyed

	MOVF Q1_HI, W
	MOVWF R_HI
	MOVF Q1_LO, W
	MOVWF R_LO

MULT_SHIFT_1
	BCF STATUS, C
	RLF R_LO, F
	RLF R_HI, F
	DECFSZ POW, F
	GOTO MULT_SHIFT_1
	RETURN

DISPLAY:
	; this is a dummy.  a convenient place to set a break point
	RETURN

	END


; CALC_2.ASM
;
; Illustrates an 8-bit X 8-bit multiplication and 16-bit divided by 8-bit
; division.
;
; Program calculates 100 * (SLOPE - COUNT)/SLOPE.  This might be used
; in calculating the extended resolution temperature of a DS1621 Digital
; Thermometer.
;
; copyright, Peter H. Anderson, MSU, July 10, '97
;
	LIST p=16c84
#include <p16c84.inc>	
	__CONFIG 11h

	CONSTANT VARS=0CH

SLOPE	EQU VARS+0		; used for example
COUNT	EQU VARS+1

M1	EQU VARS+2		; for 8 X 8 multiply 
M2	EQU VARS+3
R_HI	EQU VARS+4
R_LO	EQU VARS+5

DIV_HI	EQU VARS+6		; for 16 / 8 divide
DIV_LO	EQU VARS+7
DIVSOR	EQU VARS+8			
Q	EQU VARS+9


	ORG 000H
	
	MOVLW .234
	MOVWF SLOPE
	MOVLW .56
	MOVWF COUNT

	MOVF COUNT, W
	SUBWF SLOPE, W	; W = SLOPE - COUNT
	MOVWF M1

	MOVLW .100
	MOVWF M2

	CALL MULT8X8	; result is in R_HI and R_LO ..  100 *
(SLOPE-COUNT)

	MOVF R_LO, W
	MOVWF DIV_LO
	MOVF R_HI, W
	MOVWF DIV_HI	; DIV high and low is now 100 * (SLOPE-COUNT)

	MOVF SLOPE, W
	MOVWF DIVSOR	; divisor is now SLOPE

	CALL DIV16X8	; result is now in Q
	MOVF Q, W
	CALL DISPLAY

DONE:	GOTO DONE


MULT8X8:  ; Multiplies M1 * M2 and places result in R_HI and R_LO
	  ; does not deal with case where M1 is 0	
	CLRF R_HI
	CLRF R_LO
MULT_1:
	MOVF R_LO, W
	ADDWF M2, W
	BTFSC STATUS, C
	INCF R_HI, F	; if a carry, increment high byte
	MOVWF R_LO
	DECFSZ M1, F
	GOTO MULT_1
	RETURN

DIV16X8:	; DIV_HI and DIV_LO / DIVSOR.  result to Q
		; does not deal with divide by 0 case

	CLRF Q
DIV_1:
	MOVF DIVSOR, W
	SUBWF DIV_LO, F
	BTFSS STATUS, C	; if positive skip
	GOTO BORROW
	GOTO DIV_2
BORROW:
	MOVLW .1
	SUBWF DIV_HI, F	; DIV_HI = DIV_HI - 1
	BTFSS STATUS, C	; if no borrow occurred
	GOTO DIV_DONE	
DIV_2:
	INCF Q, F
	GOTO DIV_1
DIV_DONE:
	RETURN


DISPLAY:	; This is a dummy routine .. a convenient place to set a 
		; breakpoint 
	RETURN

	END