I have a (hopefully not too silly :-[ ) question:
I am using some sensors that don’t deliver exact 0 - 5V as AIN-Value.
For example: a resulting MIDI-value from a sensor/softPot would be typically ranging from ~10 to ~80 instead from 0 to 127.
Now I want to implement this formula, that “expands” this value to the maximum range of 0 to 127:
unsigned char min = 10;
unsigned char max = 80;
unsigned char sevenBitValue = ((sevenBitValue - min) * 127.0 / (max - min));
Here comes the problem: If I am using multiplication and division, I am forced to include these sdcc-libs, which increase the codesize from 3 kB to > 10 kB:
#include "sdcc/include/float.h"
#include "sdcc/lib/_fsmul.c"
#include "sdcc/lib/_mullong.c"
#include "sdcc/lib/_fsdiv.c"
#include "sdcc/lib/_sint2fs.c"
#include "sdcc/lib/_fs2uchar.c"
#include "sdcc/lib/_fs2ulong.c"
#include "sdcc/lib/_slong2fs.c"
#include "sdcc/lib/_ulong2fs.c"
Is there any possibility to avoid multiplications and / or divisions in this case? Can this be calculated by bit-operators? ??? Thanks for any hint, Michael btw: unfortunately I get a strange linker error if I divide through 127 (integer) instead of 127.0 (float): :o
gplink -s m5.lkr -m -o m5.hex _output/mios_wrapper.o _output/pic18f452.o _output/main.o
error: missing definition for symbol "__gptrget1", required by "_output/main.o"
T.K
January 6, 2006, 10:18pm
2
Hi Michael,
divisions are always time consuming, and with floating point values it will take even longer to get the result.
For scaling values I’m normaly using a 8*8 bit multiplication, the scaled result will be in the high byte of the result register.
Here a function which you can use (it’s from the sid_random application, and it’s assembler optimized)
unsigned char Scale_8bit(unsigned char value, unsigned char min, unsigned char max)
{
// scaled value is (<8-bit random> * <range>) >> 8
PRODL = value; // 8bit value
PRODH = max-min+1; // range
__asm
movf _PRODL, W
mulwf _PRODH, 0
__endasm;
return min + PRODH;
}
[/code]
Best Regards, Thorsten.
Hi Thorsten,
thank you very much for that super-fast answer!
now my app is back @ 5 kB and there’s plenty of space left for many, many knobs & sensors ;D
…and I’ve also learned how it’s possible to mix C and ASM code! 8)
Thanks again,
Cheers
Michael
well after thinking about a division of 2, I realized, that bit-operator can be really helpful.
(the curse of autodidacts)
maybe there are other newbies wondering how to divide / 2:Â Â ;D
1023 >> 1 = 255
255 >> 1 = 127
and vice versa:
1 << 1 = 2
10 << 1 = 20
10 << 2 = 40
so easy :
btw: I’ve just found “ch”, a tool for the shell (all major os) to evaluate c-syntax: http://www.softintegration.com
the standard edition comes for free ;D
a lot easier than compiling (or even worser: compiling and sending to the PIC to evaluate)…
cheers,
Michael
goule
January 8, 2006, 2:50am
5
Same as you, with our exotic controllers we are in need of arithmetic calculations to rescale the analog input. I found it was too heavy to deal with floats and decided to go with a DIV( ) function :
unsigned int ADK_DIV(unsigned int a, unsigned int b)
{
 unsigned int reste = 0;
 unsigned char count = 16;
 char c;
 do
 {
  c = ((a >> (8*sizeof(a)-1)) & 1);
  a <<= 1;
  reste <<= 1;
  if © reste |= 1;
  if (reste >= b)
  {
   reste -= b;
   a |= 1;
  }
 }
 while (–count);
 return a;
}
That way, you can stay in the integer world :
int coeff=4;Â // Sensitivity in LIN (linear) mode
if (DBEAM_TYPE == LOG)
   DBEAM_VALUE = MIOS_AIN_PinGet(pin)/4 - DBEAM_SEUIL;
else
   DBEAM_VALUE = 128-(ADK_DIV(3615*coeff,MIOS_AIN_PinGet(pin)+24)-coeff-18);
This code also shows the linearization (or not) of the GP2D120 as it is naturally scaled LOG
Bye,
Goule
wonderful!
this is working great!
I’ll send my source in the distance-sensor thread
Michael