I recently came across these great routines from Alexander Avtanski, on the PicList ...

http://avtanski.net/projects/math/

All credit goes to Alexander!

Everything was there, it just needed a few tweaks to be used with PicBasic Pro.

They're so cool ...

8, 16, 24, 32, 64, 128-bit Integer Math or more.

You wantBIGnumbers? .... you got 'em.

N-Bitmeans any number of bits.

16F, 18F ... doesn't matter (other than RAM space), and youmust be using MPASM.

<hr>

The number of bytes used in the math depends on thePRECISIONconstant.

If PRECISION = 4, then all math is done as 32-bit operations.

So you need to have variables of the same size, which is easy to do with ...

Then you can do the math on those variables with ...Code:PRECISION CON 4 SYSTEM ' 4 bytes = 32-bit SetPoint VAR BYTE[PRECISION] Position VAR BYTE[PRECISION] Error VAR BYTE[PRECISION] Current VAR BYTE[PRECISION] MyVar VAR BYTE[PRECISION]

Which subtractsCode:@ MATH_SUB _SetPoint, _Position, _Error ; subtract Position from setpointPositionfromSetpointand puts the result inError.

<hr>

All I've done is put a"wrapper"around the original routines from Alexander, so they can still be used exactly like the webpage says.

I've also added some macros to make things easier with PBP.

At this point I'm calling them Pvar's because unlike a byte or word, they could be any length specified by theCode:@ MATH_CLR _Pvar ; clear an N-Bit variable @ MATH_INC _Pvar ; increment an N-Bit variable @ MATH_DEC _Pvar ; decrement an N-Bit variable @ MATH_ROL _Pvar ; rotate LEFT @ MATH_ROR _Pvar ; rotate RIGHT @ MATH_CMP _A, _B ; Compare Pvars - result in M_EQ and M_GTE bits @ MATH_ADD _A, _B, _Res ; Res = A + B @ MATH_SUB _A, _B, _Res ; Res = A - B @ MATH_MUL _A, _B, _Res ; Res = A * B @ MATH_DIV _A, _B, _Res ; Res = A / B - Remainder in REG_ZPRECISION constant.

ALL math done with these routines are done at the PRECISION level, and all variables used with the MATH functions must be (PRECISION) bytes in length.

Additional macros were created to allow movement of variables between bytes, words, longs and the Pvars.

And the inverse of those puts them back into PBP variables again.Code:@ MOVE?CP Cin, _Pout ; copy a CONSTANT to a Pvar @ MOVE?BP _Bin, _Pout ; copy a BYTE to a Pvar @ MOVE?WP _Win, _Pout ; copy a WORD to a Pvar @ MOVE?LP _Lin, _Pout ; copy a LONG to a Pvar (PBPL only) @ MOVE?PP _BeerIN, _Pout ; copy a Pvar to a Pvar

Code:@ MOVE?PB _Pin, _Bout ; truncate a Pvar into a BYTE var @ MOVE?PW _Pin, _Wout ; truncate a Pvar into a WORD var @ MOVE?PL _Pin, _Lout ; truncate a Pvar into a LONG var (PBPL only)

So let's say you were getting a 16-bit value from the QEI counter, and the upper 16-bits from a Rollover interrupt.

You could move them all into a Pvar with two lines ...

This way you can do 32-bit math without PBPL. Or 64-bit if you needed.Code:RollOvers VAR WORD ; QEI rollovers (from interrupt) @ MOVE?WP POSCNTL, _Position ; copy QEI count to Position.Word0 @ MOVE?WW _RollOvers, _Position + 2 ; copy rollovers to Position.Word1 ;-- Calculate the Error -- @ MATH_SUB _SetPoint, _Position, _Error ; Error = Setpoint - Position @ MOVE?PW _Error, _pid_Error ; copy Pvar result to a WORD variable

It's not as easy as PBPL, but can be very useful.

Keep in mind that the math is all Software. Multiplication does not use the hardware multiplier.

So with 18F's, MATH_MUL at 32-bits will take longer than PBPL with 32-bits.

However, you can still use all of the math statements within PBP, and they will be faster without PBPL, or BIGGER with PBPL.

Another recent request from someone in this forum was to have a counter that keeps track of the number of milliseconds since the power was turned on.

That can be a pretty big number ... if it's been powered-up for a decade or two.

No problem ...

That will happily count the number of milliseconds passed for over 34 years. 2<sup>^</sup>40/(1000*60*60*24*365)Code:'----[N-Bit Math]----------------------------------------------------------- PRECISION CON 5 SYSTEM ; 5 bytes=40-bit INCLUDE "N-Bit_MATH.pbp"Powered_MSVAR BYTE[PRECISION] MS_intHandler: ; this routine should be called every mS via a timer interrupt @ FSRSAVE ; Save FSR value before interrupt code @ MATH_INC_Powered_MS; increment # of mS since PWR_ON @ FSRREST ; Restore FSR ; return from interrupt, depends on the type of interrupt. ; interrupt code and context saving not shown.

If you need it to count longer ... go with 6 byte PRECISION (8,925 years).

<hr>

The routines are completely ASM, and do not use any of PBP's system variables. So it's OK to use them within ASM type Interrupts if desired.

But you'll need to save the FSR value before doing any MATH because it uses the FSR and would disrupt the flow of the Main program if not saved.

The@ FSRSAVEand@ FSRRESTcan be used to make it easy.

Note: DT_INTS already saves/restores the FSR's at the beginning/end of an interrupt, so you don't have to.

For ASM interrupts, you will need to save it. FSR's don't matter with ON INTERRUPT.

<hr>

Please understand that these are "Advanced Level" math routines.

I can not debug everyone's program that ends up not compiling because of syntax errors.

If you truely believe that something is wrong with the routines, I would love to hear it. And I will do my best to fix it.

If you can't get it to compile ...keep trying... it will.

Here's the Include File.

Current Version = 1.4 Beta(8/4/2010); Workaround for MPASMs shift > 32-bits

History:

1.3 Beta 1/7/2010 ; compatability with 16F1xxx chips (enhanced core)

1.2 Alpha 1/4/2010 ; adds ability to turn Case Sensitivity off in MPASM

1.1 Alpha 1/4/2010 ; fixes FSR conflict with DT_INTS-18

1.0 Alpha 1/3/2010 ; initial release

## Bookmarks