Separation using / without using floats in C

Below is the main function that I wrote in C (for the PIC18F8722 microprocessor), trying to control 2 multiplexing of 7 segments with a specific frequency specified by the unsigned int get_ADC_value() function. Displays also show the current multiplex frequency. This frequency range is set by #define in the range of LAB_Fmin and LAB_Fmax and should scale as get_ADC_value() increases or decreases from 0 to 255.

This code, however, does not work, as I think there is an implicit conversion from int to float to freq = .

The task is to fix this error with float and find an alternative using only integer types ( int , char ...).

  while (1) { unsigned int x, y, z; float freq, delay; x = get_ADC_value(); y = x & 0b00001111; z = (x & 0b11110000) >> 4 ; freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255)*x ; delay = 1/(freq*1000); // convert hZ to ms delay accurately LATF = int_to_SSD(y); LATH = 0b11111110; //enable 7seg U1 for (unsigned int i = 0; i<(delay) ; i++){ Delay10TCYx(250); //1ms delay } LATF = int_to_SSD(z); LATH = 0b11111101; //enable 7seg U2 for (unsigned int j = 0; j<(delay) ; j++){ Delay10TCYx(250); //1ms delay } } 
+7
c floating-point microchip integer-division truncation
source share
5 answers

C is defined for splitting int using integer division, and only when there is a float does it first “push” the other int into the float . Note that this even happens if it is assigned a float - if the right side is all int s, then the division will be integer, and only for the final assignment C will convert the int result to float .

So, with your line:

 freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255)*x ; 

it all depends on what LAB_Fmax and LAB_Fmin . It doesn't matter if freq or x , because the "damage" has already been done due to the brackets that make the division be the first.

If these variables are LAB_F int s, the easiest way to use floating point division is to simply tell C what you want by making the constant 255 a floating point number rather than an integer using the decimal point: 255. (or 255.0 will be less thin) .

If you want to use only integer arithmetic, then the usual suggestion is to do all your multiplications before any divisions. Of course, this can lead to an overflow of the intermediate result - you can use the long type to help you. Define the LAB_F or x variables as long , and split the latter:

 freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin)) * x / 255); 
+16
source share

Code Review:

  • unsigned int x, y, z; Avoid using raw integer types in embedded systems. The exact width types from stdint.h should always be used for use, so you know exactly what size you are using. If you do not have access to stdint.h, then typedef these types yourself.

  • float freq, delay; On most embedded systems, floating point numbers should generally be avoided. In particular, on 8-bit microcontrollers without FPU! This will result in software floating point numbers that are incredibly slow and consume a lot of memory. It seems that you have no reason to use floats in this program, it seems that you should write this algorithm with uint16_t or less if you do not have requirements for maximum accuracy.

  • x = get_ADC_value(); Since it seems to you that you are only interested in 8 bits of ADC reading, why not use the 8-bit type?

  • Note that binary literals are not standard.

  • ((LAB_Fmax) - (LAB_Fmin))/ 255 This looks suspicious. First of all, are these integers or floats? What are their sizes? The answer to your question depends on it. 255.0f over the 255.0f literal, you can force it into a float. But are you sure that the division should be at 255? And not 256?

  • i<(delay) . You should always avoid using floating point expressions inside loop conditions, as this makes the loop uselessly slow and can potentially lead to floating point error errors. In addition, brackets have no purpose.

In general, your program suffers from "sloppy typing", which means that the programmer did not think about what types are used in each expression. Note that literals also have types. Implicit conversions can cause many of these expressions to be evaluated on too large types, which is very bad news for PIC. I would recommend reading “balancing” as well as regular arithmetic conversions.

This "careless input" will cause your program to be very bloated and slow because nothing works. You should remember that PIC is perhaps the most compact MCU that is still being produced. When writing C code for any 8-bit MCU, you should avoid types larger than 8 bits. In particular, you should avoid 32-bit integers and floating-point numbers such as the plague.

Your program re-scales all the data to types that make it easier for the programmer to think. This is a common design error - instead, your program should use types that are easy to use for the processor. For example, instead of milliseconds, you can use a timer as a unit of measure.

+10
source share

You are right about integer division. Change to

 freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin)) / 255.0)*x; ^^ 
+6
source share
  freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255)*x ; 

This is really an implicit conversion to an integer, and for that you do integer division.

This is because 255 is an integer literal.

Change it to 255.0 as a double literal that should work well with your calculations.

If you want to be more precise, you can even use a floating point literal, such as 255.0f or an explicit listing, such as (float)255 .

Your code might look like this:

 freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255.0)*x ; 

Or that:

 freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ (float)255)*x ; 
+4
source share

Mathematical operations with integers will by default lead to an integer, so you need to either express one of the literals as double / float

 freq = LAB_Fmin + (((LAB_Fmax) - (LAB_Fmin))/ 255.0)*x ; 

or cast (float)

like many other conditions, the first option is most often implemented.

+3
source share

All Articles