0

I am new to embedded System. I would like to perform division between 2 unsigned 16 bit integer and display the answer(including the decimal values). I wonder how can I accomplish this in embedded-C. Float,double and unsigned long does not seem to work. I am using TI's TM4C launchpad.

uint8_t PPGMsg[5];
unsigned long PPG;
uint16_t IR_combined,RED_combined;
IR_combined = (PPGMsg[1]<< 8)|PPGMsg[2];
RED_combined = (PPGMsg[3]<< 8)|PPGMsg[4];
PPGMsg[0]=(RED_combined/IR_combined);
PPG=(RED_combined/IR_combined);
UARTprintf("IR_combined is: %d\n",IR_combined);
UARTprintf("RED_combined is: %d\n",RED_combined);
UARTprintf("PPG is: %d\n",PPGMsg[0]);
UARTprintf("long PPG is: %d\n",PPG);

For example when IR_combined is: 147 and RED_combined is: 1012, the PPG: 6. However I would like the answer to be displayed as 6.88 instead.

Thale
  • 123
  • 4
  • 15
  • It's useful to specify which target hardware you're running on, since it might matter. Do you have floating-point support, either in the hardware or in software? – unwind Dec 12 '17 at 11:59
  • `PPGMsg[0]=(RED_combined/IR_combined);` How exactly does this make any sense? The left operand of = is 8 bits. – Lundin Dec 12 '17 at 12:01
  • **Unrelated:** **INFO** I would recommend handling the conversion on the machine where you are reading the UART. You will be wasting a lot of the clock cycle for the conversion on the controller and might face some timing/resource issues also if the application is time sensitive. – AmeyaVS Dec 13 '17 at 07:47
  • The tm4c has a single precision floating point unit (FPU). If single precision is enough, use the FPU for added performance if needed. Also, the UARTprintf() supplied by TI in the SDK utils for that platform does not handle floats. If you need to print a float out the UART, you can break your result into two ints or use/make a different UARTprintf() function. – GC78 Dec 14 '17 at 17:52

1 Answers1

2

For 2 decimals precision, you need to do (uint32_t)RED_combined*100/IR_combined. Then print the decimals as you would like them. Example:

#include <stdint.h>
#include <inttypes.h>
...
uint16_t RED_combined = 1012;
uint16_t IR_combined = 147; 
uint16_t x = ((uint32_t)RED_combined*100u / IR_combined);
printf("%"PRIu16".%.2"PRIu16, x/100, x%100);

However, you also have lots of other problems/bugs:

  • IR_combined = (PPGMsg[1]<< 8)|PPGMsg[2]; is dangerous/buggy code. Since PPGMsg[1] is a small integer type, it gets promoted to int and you end up performing left shifts on a signed type. Similarly, the | invokes implicit promotion to signed type.
    You must study Implicit type promotion rules.
  • (PPGMsg[3]<< 8)|PPGMsg[4]; Same bugs here.
  • PPGMsg[0]=(RED_combined/IR_combined); You store the result in a 8 bit variable that is too small to hold the result. I don't understand how this makes any sense. Are you trying to parse out the ls byte?
  • %d is used to print signed integers. UARTprintf("IR_combined is: %d\n",IR_combined); should be "IR_combined is: %"PRIu16 "\n",IR_combined. You find these format specifier macros in inttypes.h.
  • Same bug: UARTprintf("PPG is: %d\n",PPGMsg[0]);. Should be UARTprintf("PPG is: %"PRIu8 "\n",PPGMsg[0]);.
  • unsigned long is printed with %ld

Using the correct type matters, everywhere!

Also consider using a good compiler like gcc that does warn if you use the wrong format specifier. Or better yet, don't use printf-like functions at all - they are unsafe, slow and resource-heavy.

Lundin
  • 195,001
  • 40
  • 254
  • 396