Problem to convert "float" into "unsigned char"

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem to convert "float" into "unsigned char"

5,106 Views
xuejun
Contributor II

I am using MC9S12XEP100 AND CW5.1 on my automotive project,  I need to convert a mapped analog value ( this value has been mapped ranged from 3.35v – 3.65v to a new range of 0 - 5v, it is virtual rather than real, therefore it cannot be directly connected to the PAD00-PAD15 pins for A/D conversion).

part1. I have successfully built up the mapping program which is good, the part1 program is here:

 

//...map the (3.35v-3.65v) ADC output to a value between 0-5v

// Inputs: adcout = ADC result, adcmin/adcmax = min and max value of the ADC

//         rmin/rmax = min and max value in physical value

// Return outputs: mapped 0-5v value from real measured 3.35v-3.65v ADC result

float ADC_to_map (unsigned int adcout, unsigned int adcmin, unsigned int adcmax, float mapmin, float mapmax)

{

   float rslt1;

   if(adcout>adcmax) adcout = adcmax;

   else if(adcout<adcmin) adcout = adcmin;

   rslt1 = (float)(adcout-adcmin)*(mapmax-mapmin)/(float)(adcmax-adcmin) + mapmin;

   if(rslt1<mapmin) rslt1 = mapmin; else if(rslt1>mapmax) rslt1=mapmax;

   return (rslt1);

}

 

part2. however, there is a problem when convert the float to unsigned char, the part2 program is here:

 

//...Convert the mapped 0-5vl value into 8-bit quantised unsigned char for further comparison

// Inputs: rval = mapped value to be converted into an unsigned char 

//         mapmin/mapmax = min and max value of the mapped value (0v and 5v respectively)

// Return outputs: unsigned char to be used for further comparison

unsigned char Map_to_wantedchar (float rval, float mapmin, float mapmax)

{

   float rslt2 = 255*(rval-mapmin)/(mapmax-mapmin);

   return((unsigned char)rslt2);

}

The above part2 program was previously successfully compiled in my C167 Microprocessor project using Keil uvision development suite, but this time it gives a warning “C5915: Conversion of float to unsigned integral” with freescale MC9S12XEP100 and CodeWarrior5.1.

 

I read the C5919 information and tried to modify the code in part2 as:

Option A (NOT SUCCESSFUL):

 unsigned char Map_to_wantedchar (float rval, float mapmin, float mapmax)

{

   float rslt2 = 255*(rval-mapmin)/(mapmax-mapmin);

  signed char tempA = (signed char)(rslt2);

  unsigned char testA = (unsigned char)tempA;

   return((unsigned char)testA);

}

 

Option B (NOT SUCCESSFUL):

 unsigned char Map_to_wantedchar (float rval, float mapmin, float mapmax)

{

   float rslt2 = 255*(rval-mapmin)/(mapmax-mapmin);

  signed int tempB = (signed int)(rslt2);

  unsigned char testB = (unsigned char)tempB;

   return((unsigned char)testB);

}

 

Anyone please give me a hand, thanks!

Labels (1)
Tags (1)
8 Replies

2,211 Views
kef
Specialist I

Xxuejun,

 

C5915 warning just warns that in case float is negative, converting it to unsigned will give you weird results. You convert -5.0 to unsigned char and get 251. You convert -5.0 to unsigned int and get 65531.

 

Regarding option A and B, it is absolutely not clear what doesn't work. You had to specify what values do you supply to your routines, what do you get and what do you expect to get.

0 Kudos

2,211 Views
xuejun
Contributor II

Hi Kef,

 

In my part 1 program I have restricted the mapped value between 0-5v (adcmax=5 and adcmin=0 respectively), so there is no chance to convert a (negative) float to the unsigned char, am I right?

 

I want to obtain an 8bit “unsigned char” result supplied from the mapped 32bit float “rslt1” between 0-5.

 

I will post my c program later, please check for me, many thanks!

 

Xuejun

0 Kudos

2,211 Views
xuejun
Contributor II

// My code is listed below, it is also included in the project_xj.zip, please help me to solve the problem!!!


#include <hidef.h>
#include "mc9s12xep100.h"
#include "sci.h"
#pragma LINK_INFO DERIVATIVE "mc9s12xep100"

/////////////////////////////////////////////////////////////////////////////////////////
// Defines and variables
/////////////////////////////////////////////////////////////////////////////////////////

#define pmh_sensitivity  4

// Unsecured status flash
const unsigned char flash_security  @0xFF0F = 0xFE;

/////////////////////////////////////////////////////////////////////////////////////////
// function: PeriphInit
// --------------------------------------------------------------------------------------
// Initializes various registers and peripherals
/////////////////////////////////////////////////////////////////////////////////////////
void PeriphInit(void)
{
   // config portK as output of HYDRAULIC (pk0, pk1 pk2 only)
  // pk0 and pk1 to go to relay 1&2,pk2 goes to relay 3

  // PORTK=0x00;
  DDRK=0x07;
 
  // Configures the ATD peripheral
  // 8 bit data resolution
  ATD0CTL1 = 0x10;
  // Left justified data, 2 conversion sequence(AN 0-1) and non-FIFO mode
  ATD0CTL3 = 0x13;
  // fBUS=2MHz, fATDCLK = 1 MHz (PRESCLAER = 0) Select 24 Sample Time
  ATD0CTL4 = 0xE0;
 
 EnableInterrupts;
}

//....part1: map the (3.35v-3.65v) ADC output to a value between 0-5v
//....INITIALIZATION: adcmin=3.35/5*256-1=170=0xAA; adcmax3.65/5*256-1=186=0xBA, rmin=0, rmax=5
// ....Inputs: adcout = ADC result, adcmin/adcmax = min and max value of the ADC
// ....mapmin/mapmax = min and max value in physical value
// ...Return outputs: mapped 0-5v value from real measured 3.35v-3.65v ADC result
float ADC_to_map (unsigned int adcout, unsigned int adcmin, unsigned int adcmax, float mapmin, float mapmax)
{
   float rslt1;
   if(adcout>adcmax) adcout = adcmax;
   else if(adcout<adcmin) adcout = adcmin;
   rslt1 = (float)(adcout-adcmin)*(mapmax-mapmin)/(float)(adcmax-adcmin) + mapmin;
   if(rslt1<mapmin) rslt1 = mapmin; else if(rslt1>mapmax) rslt1=mapmax;
   return (rslt1);
}
 
//...part2: Convert the mapped 0-5v value into 8-bit quantised unsigned char for further comparison
// ...Inputs: rval = mapped value to be converted into an unsigned char
//...mapmin/mapmax = min and max value of the mapped value (0v and 5v respectively)
// ...Return outputs: unsigned char to be used for further comparison
unsigned char Map_to_wantedchar (float rval, float mapmin, float mapmax)
{
   float rslt2 = 255*(rval-mapmin)/(mapmax-mapmin);
   return((unsigned char)rslt2);
}

/////////////////////////////////////////////////////////////////////////////////////////
// Main
/////////////////////////////////////////////////////////////////////////////////////////
void main(void)
{
  Bool angleh_pos;
  Bool angleh_neg;
  float scale_pmh;
  unsigned char pmh_feedback;
  unsigned char comp_pmh;
     
  PeriphInit();
 
    // Select AN00 as input channel and enable multi channel conversions
    ATD0CTL5 = 0x10;  
    while(!(ATD0STAT0 & 0x80))
      ;
   
 
//******Determine if hydraulic pump needs to be positively, negatively turn; or just stay static*******
//*** receive system input signal from AN00 and A/D converting it ATD0DR0H
//***the feedback signal is received from AN01 (3.35-3.65v) and automatically A/D converted to ATD0DR1H
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 pmh_feedback= ATD0DR1H; 
    // receive feedback signal from AN01 (3.35v-3.65v) and map it to 0-5v and convert to unsigned char
 scale_pmh = ADC_to_map(pmh_feedback, 0xAA, 0xBA, 0, 5);//mapping
 comp_pmh = Map_to_wantedchar(scale_pmh, 0, 5); //convert the mapped 0-5 float result to 8bit unsigned char
//***judge if the angle need to be changed, in which direction
angleh_pos = ATD0DR0H > comp_pmh && (ATD0DR0H - comp_pmh > pmh_sensitivity);
angleh_neg = ATD0DR0H < comp_pmh && (comp_pmh - ATD0DR0H > pmh_sensitivity);
       
    if (angleh_pos)
    PORTK = 0x02;
    else if (angleh_neg)
    PORTK = 0x01;
    else
    PORTK = 0x07;
}

0 Kudos

2,211 Views
kef
Specialist I

C5919 is warning, not an error.

 

You get linker errors because you specified in project wizard that you don't want floating point. You need to recreate project, specifying you want floating point. It is possible to replace *.lib file with correct one and removing -D__NO_FLOAT__ from compiler options string.

0 Kudos

2,211 Views
xuejun
Contributor II

Actually, my question and problem is due to here: that a "float" value when converted to an "unsigned char", it is not directly allowed.

 

float rslt2 = 255*(rval-mapmin)/(mapmax-mapmin); // this instruction is ok

return((unsigned char)rslt2); //it causes C5919 error, but is definitely allowed in my previous project using C167 +uvision

 

 

But I have to do this conversion, I have tried with many other methods and got no success. Please anyone help me with this?  

0 Kudos

2,211 Views
Lundin
Senior Contributor IV

Converting a float to an unsigned char is undefined behavior in the C language. It is not ok to do that on any C compiler.

 

The C standard, ISO 9899:2011 6.3.1.4

"When a finite value of real floating type is converted to an integer type..." /--/

"If the value of the integral part cannot be represented by the integer type, the behavior is undefined."

 

Undefined behavior means that anything is allowed to happen. Compiler errors, runtime crashes or perhaps even a result that seems to make sense somwhat. You cannot know which of these that will happen, and the compiler doesn't need to document what it will do. To be safe, always avoid undefined behavior. Relying on it is considered to be a severe bug and such code will not be portable, as we can see in your case.

 

If you must do such a conversion, you need to first convert the float into a signed integer type, and then from there into an unsigned integer type.

 

---

 

However, I really don't see why you must use float in the first place? Applications where it makes sense to use floating point are signal/sampling modulation algorithms, high resolution positioning systems, PID regulation etc etc. Such systems would likely not use a crude 8-bit ADC. I suspect that floats will only make your project needlessly complex. Bigmac's suggestion is very sensible and likely hundreds of times more efficient than floats.

 

 

0 Kudos

2,211 Views
bigmac
Specialist III

Hello,

 

I assume that what you are attempting to do is convert an analog voltage within the range 3.35 to 3.65 volts, using a 10-bit or 12-bit ADC.  Assuming you have an ADC reference voltage of 5.00 volts, the raw ADC reading would be -

 

10-bit:  686-748, a span of 62

12-bit:  2744-2990, a span of 246

 

Am I correct?  I assume that this integer value is then converted to a floating point value within the range 0 to 5.000.  This is a numeric range, and not a "voltage" range.  You could have equally chosen an integer range of 0-500, or 0-5000, or any other arbitrary integer range.

 

However, in this instance it would seem much simpler, and far more efficient, to directly convert the ADC reading to a scaled 8-bit value, without any intermediate floating point conversion.

 

byte getcharval( word adcout, word adcmin, word adc max){   word span;   span = adcmax - adcmin;   if (adcout < adcmin)  return 0;   if (adcout >= adcmax) return 255;   return (byte)((adcout - adcmin) * 256 / span);}

 This will truncate the returned value.  For rounding of the return value, the following code might be used.

 

byte getcharval( word adcout, word adcmin, word adcmax){   word span, round;   span = adcmax - adcmin;   if (adcout < adcmin)  return 0;   if (adcout >= adcmax  return 255;   return (byte)(((adcout - adcmin) * 256 + span / 2) / span);}

 

Regards,

Mac

 

0 Kudos

2,211 Views
xuejun
Contributor II

Hi Bigmac,

 

I am sure I am using 8 bit A/D conversion (ATDCTRL1=0X10), my part1 program maps the 3.35v-3.65v analog into new range 0-5v which is a “float” number, that is working.

 

My part2 program intends to convert the float number (32 bits, range 0-5v) into a (8bit) unsigned char for further comparison.

 

If I directly convert floatàunsigned charàreturn, there is C5919 warning, so I use two options either:

My option A: floatàsigned charàunsigned charàreturn

 My option B: floatàsigned intàunsigned intàreturn

 

The C5919 warning is gone, instead there are 8 link errors (L1822, I wonder CW gives wrong error information, cos I am sure all symbols were pre-defined).

 

Both option A&B still cannot work, could you please analyse it for me, many thanks.

 

Xuejun

0 Kudos