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 want

**BIG**numbers? .... you got 'em.

**N-Bit**means any number of bits.

16F, 18F ... doesn't matter (other than RAM space), and you

**must be using MPASM**.

<hr>

The number of bytes used in the math depends on the

**PRECISION**constant.

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 ...

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]

@ MATH_SUB _SetPoint, _Position, _Error ; subtract Position from setpoint

**Position**from

**Setpoint**and puts the result in

**Error**.

<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.

@ 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_Z

**P**RECISION 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.

@ 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

@ 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 ...

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 ...

'----[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

**@ FSRSAVE**and

**@ FSRREST**can 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

## Re: Elapsed timer not working as expected at 64MHz

Sorry to resurrect this thread. I have read all the posts but am still confused.

retepsnikrep Today, 10:14I'm struggling to get my DT_elapsed timer 1ms interrupt working at the correct frequency when running at 64mhz...