View previous topic :: View next topic |
Author |
Message |
future
Joined: 14 May 2004 Posts: 330
|
Divide by 12 |
Posted: Tue Jun 28, 2005 8:36 pm |
|
|
Hi all,
I need to divide a long by 12 inside a fast int handler, so any scratch register usage needs to be avoided.
Does anyone knows about a clever way to do this? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 29, 2005 1:05 am |
|
|
I don't about a clever way, but you could make your divide-by-12
routine with ASM code. Then create some global variables that
are used only by that code. (You can use C variables in code).
In this way, you avoid using the CCS library routines and their
scratch variables.
You can get the ASM code from the CCS library by compiling
a test program with an int16 variable divided by 12. You can
see the CCS code by commenting out the #nolist statement
at the top of your PIC's .H file.
Another source for ASM division code is on this page:
http://www.piclist.com/cgi-bin/constdivmul.exe
To generate code for Divide-by-12, enter .08333 into the box
for Multiply by Constant. For the Input Register Size, enter 16
because that's your variable size. If you want reasonable
accuracy the generated code can get fairly long. Maybe
it's best to use the CCS code. |
|
|
Ttelmah Guest
|
|
Posted: Wed Jun 29, 2005 2:42 am |
|
|
It would help if you said 'what' you need to divide by twelve. Answers will differ for an int, int16 etc..
Remember that using a fast handler, does not mean that you cannot use scratch registers, it just means that _you_ have to save these yourself.
You can get a pretty close approximation to /12, by taking the value >>4, plus the value >>5. Not 'exact', but for low numbers in the integer range, it may be 'close enough'...
Best Wishes |
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Wed Jun 29, 2005 9:46 am |
|
|
Quote: | It would help if you said 'what' you need to divide by twelve. Answers will differ for an int, int16 etc.. |
It is there... "I need to divide a LONG by 12".
When I said that it shouldn't use the scratch registers it was because the way I write the code, FAST means fast... so saving and restoring must be avoided if possible.
I would place the division in main, but there is not enough time to run it right after the return from the interrupt. There isn't any priority control over the tasks. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 29, 2005 5:26 pm |
|
|
I don't know if it can be done quickly with 16-bit variables on an 8-bit PIC.
Here's a page with some C code that consists of shifts and adds.
http://www.hackersdelight.org/divcMore.pdf
I converted the Divide-by-12 code to a CCS test program.
With PCH vs. 3.188, the routine takes about 100 instructions.
Code: | #include <18F452.h>
#fuses XT, WDT, NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
int16 divu12(int16 n)
{
int16 q, r;
q = (n >> 1) + (n >> 3);
q = q + (q >> 4);
q = q + (q >> 8);
q = q + (q >> 16);
q = q >> 3;
r = n - q*12;
return q + ((r + 4) >> 4);
// return q + (r > 11);
}
//===========================================
void main(void)
{
int16 result;
result = divu12(65535);
printf("%lu\n\r", result);
while(1);
} |
|
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Wed Jun 29, 2005 6:14 pm |
|
|
Thank you all for the time and effort to help me.
It seems that result = (int16>>4) + (int16>>5) - (int16>>7) is close enough for the application.
It just need some work so it won't use any scratch register.
Something like:
Code: | temp1 = var_to_divide>>4;
temp2 = temp1>>1;
result = temp1 + temp2;
temp1 = temp2>>2;
result -= temp1; |
|
|
|
|