Jump to content

Recommended Posts

Posted

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"

Posted

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.

Posted

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

Posted

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

Posted

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

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...