-1

I am trying to create a conversion table using the C programing language. I want to convert the temperature from -250 °F to 250 °C increments of 10. However, I am not getting the Celsius output:

#include <p18f458.h>
#include <stdio.h>

#pragma config WDT = OFF

#define LOWER -250 /* lower limit of table */
#define UPPER 250 /* upper limit */
#define STEP 10 /* step size */

void main(void)
{
    int fh, cel;
    cel = (fh - 32) * 5 / 9;

    for (fh = LOWER; fh <= UPPER; fh = fh + STEP)
        printf("%d \t   %6.1f\n", fh, cel);

    while(1);  
} 
 Fahrenheit      Celsius

-250       
-240       
-230       
-220       
-210       
-200       
-190       
-180       
-170       
-160       
-150       
-140       
-130       
-120       
-110 .......

The code runs on a PIC18F458 microcontroller.

wovano
  • 4,543
  • 5
  • 22
  • 49
  • 3
    Well, for one thing `cel` is not an `f`. – 500 - Internal Server Error Sep 26 '22 at 18:06
  • 1
    You need to use floating point. Declare `fh` and `cel` as type `double`. – Steve Summit Sep 26 '22 at 18:10
  • 5
    You'll need to recalulate `cel` in each loop iteration. Your `cel = (fh - 32) * 5 / 9;` does not establish a *relationship* but is a one-off calculation (from an uninitialised `fh`). – Weather Vane Sep 26 '22 at 18:12
  • 1
    This exact question has been asked many times before. However, in your specific case the solution is _not_ to use floating point since you don't have a FPU. Floating point will mean massive overhead bloat in the form of software libs inlined with the code. Instead simply multiply the left operand sufficiently before division, until you get the precision required. – Lundin Sep 27 '22 at 06:53
  • Adding FP support to an embedded processor certainly is sizeable, yet the size needed - which tends to be fixed - is less and less of a concern each year as sizeable processors continue to increase dramatically. It use to be a significant concern with a 4k-byte processor, but with a 256k, less so. A key trade off is the cost of N * larger/more expensive processors vs the higher skill/cost of the programmer needed to handle FP-less applications. – chux - Reinstate Monica Sep 27 '22 at 13:58

3 Answers3

1

Recalculate each time

Use floating point math


//     dddd123456789012ffffff
puts(" Fahrenheit      Celsius");

// cel = (fh - 32) * 5 / 9;

for (fh = LOWER; fh <= UPPER; fh = fh + STEP) {
  double cel = (fh - 32.0) * 5.0 / 9.0;
  printf(" %4d            %6.1f\n", fh, cel);
}

If wanting to avoid floating point types and math, use a scaled integer math to calculate decidegrees to achieve "%6.1f" like output. Scale temperature by 10. Integer division truncates the fraction, so add a signed offset of 5 to form a rounded result.

  int offset = (fh - 32) > 0 : 5  : -5;
  int deci_celcuis = ((fh - 32) * 10 * 5 + offset) / 9;

Printing is a little tricky. Various approaches exist.

  int whole = deci_celcuis/10;
  int frac = deci_celcuis%10;
  char *sign = (whole < 0 || frac < 0) ? "-", ""; 
  printf(" %4d            %s%d.%d\n", fh, sign, abs(whole), abs(frac));
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Note the embedded tag, this is a PIC. The OP doesn't have a FPU so this is bad advise. The equation has to be carried out in fixed point, for example by multiplying the left operand by 10000 or so before division. – Lundin Sep 27 '22 at 06:50
  • @Lundin, Fixed point is a reasonable and not-so-difficult to do when FP math is expensive. Trivial with unsigned math, a tad more complex with signed math. Answer updated to support that. Converting signed fixed point though to text is a bit of a pain. A more expansive answer would use a generalized helper function. Above uses crafted code to get the job done. – chux - Reinstate Monica Sep 27 '22 at 13:09
  • I strongly suspect that this is an "XY" question anyway. A temperature sensor in an embedded system will not typically give output in degrees, but in a raw value between 0V and Vref. That's how simple, single-chip temp sensors work anyway. In which cases it is senseless for the MCU to use any other unit than "raw binary" from 0 to for example a max ADC ref value. You'd only convert to Fahrenheit or Celsius if you need to actually display something to humans. – Lundin Sep 27 '22 at 13:13
  • Duplicate answer at another SE site: https://electronics.stackexchange.com/a/494924/6102 – Lundin Sep 27 '22 at 13:15
  • @Lundin True, yet many embedded processors drive small displays, so text output not that uncommon. Also with IOT, converting to a transmittable standard form often involves common SI units. – chux - Reinstate Monica Sep 27 '22 at 13:16
  • Well, the SI unit in this case is Kelvin :) – Lundin Sep 27 '22 at 13:17
  • @Lundin, yes, the forecasted high today is a cool 288K. :) – chux - Reinstate Monica Sep 27 '22 at 13:25
0

As others have noted: 1) use floating point to avoid integer division and truncation errors, 2) recalculate values inside the loop.

It would be a shame to miss this opportunity to produce parallel tables of F->C and also C->F for the given range.

#define LOWER  -250
#define UPPER   250
#define STEP     10

int main() {
    puts( "    F        C             C        F" );

    for( int i = UPPER; i >= LOWER; i -= STEP ) {
        printf( "%6.0f   %6.0f", (double)i, (i - 32.0) * 5.0 / 9.0 );
        printf( "        " );
        printf( "%6.0f   %6.0f\n", (double)i, i * 9.0 / 5.0 + 32.0 );
    }

    return 0;
}
    F        C             C        F
   250      121           250      482
   240      116           240      464
   230      110           230      446
   220      104           220      428
   210       99           210      410
   200       93           200      392
// omitted...
  -220     -140          -220     -364
  -230     -146          -230     -382
  -240     -151          -240     -400
  -250     -157          -250     -418

Ordinary mercury thermometers condition people to expect warmer temperatures at the top, and cooler temperatures 'below'... This table reverses the sequence presented in the OP to conform to people's expectations.

Fe2O3
  • 6,077
  • 2
  • 4
  • 20
-2
cel = (fh - 32) * 5 / 9;

This statement is outside the loop, hence it will only ever print once. . Add it in the loop and your code would work as expected.

Harith
  • 4,663
  • 1
  • 5
  • 20