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