0

I am writing a program that obtains a temperature from a thermistor and then needs to determine what temperature range it falls in to then turn on a specific coloured LED. The issue I am having is that when the temperature falls in a certain range, more than one light turns on and I only want one of the 3 from an RGB LED.

Right now, my if statement to check the value of the temperature is:

if (-40.0 < tempValue && tempValue < 20.5)
{
    //turn blue light on
}

else if (20.5 < tempValue && tempValue < 37.3)
{
    //turn green light on
}

etc... where tempValue is the temperature obtained from the thermistor.

After reading a bunch of posts about floats and comparing them/equality statements, I know that there is definitely an issue in doing so the "regular" way of comparing, but I am not sure how else to check the temperature based on a given range with a max and min value.

lcmting17
  • 45
  • 5
  • Note that if the temperature equals 20.5, neither light turns on. Note that 20.5 can be represented exactly, as can -40.0, but 37.3 cannot be represented exactly. – Jonathan Leffler Mar 16 '20 at 19:11
  • 3
    There is almost nothing wrong with your code, it's just that you might want to replace one of the `20.5` comparisons with `<=`. Also you might want to add some hysteresis as you are going to get crazy flickering when around `20.5`. – Eugene Sh. Mar 16 '20 at 19:11
  • 1
    Do you need to turn off whatever light is already on before turning on the new light? Or, at least, turn it off if the new light is different; if it is unchanged, don't turn it off and then on to avoid flicker. – Jonathan Leffler Mar 16 '20 at 19:12
  • Comparsion seems fine, since you use else if therefore only 1 branch should execute. Maybe the problem is the lack of hysteresis, so when temp is near 25 then you might read in 24.99... then 25.001.. then again 24.99.. something and if the program fast enough then both led will flash. So it could be caused by noise. – Eraklon Mar 16 '20 at 19:13
  • @JonathanLeffler yes I keep the light on for 5 seconds then turn it off before it loops again (it's all in a while loop). Also, what do you mean by 20.5 and -40.0 can be represented exactly, whereas 37.3 cannot? Does this pose an issue if the temp value is actually 37.3? – lcmting17 Mar 16 '20 at 19:17
  • @EugeneSh. I actually have noticed some flickering and I didn't know what it was from. I'll give that a try thank you! – lcmting17 Mar 16 '20 at 19:17
  • See [Is floating-point math broken?](https://stackoverflow.com/q/588004/15168) However, some decimal numbers cannot be represented exactly in IEEE 754 binary floating-point numbers — a simple example is `0.1`. The value `37.3` is also a multiple of `0.1`. So of course are -40.0 and 20.5, but the difference is that 0.5 can be represented exactly in binary (1/2), as can 0.25 and 0.75 (1/4, 3/4), and so on. And smallish integers can be represented exactly. Big enough integers run into representation problems too. – Jonathan Leffler Mar 16 '20 at 19:22
  • @JonathanLeffler ah I see, ok I'll give that post a read, thanks! I also just realized that the problem I'm having is with an LCD initialization line (I'm also using an LCD in this to display the temp), so that seems to be the root cause of all my lights turning on, not what I thought. Thank you anyway! – lcmting17 Mar 16 '20 at 19:27
  • 1
    I dare say that floating point has greater accuracy than the temperature measuring device, so as long as you don't trigger an event on an equality it is probably irrelevant whether the temperature reading is `37.3` or `37.29999999`. – Weather Vane Mar 16 '20 at 19:30
  • The code you show is not consistent with the behavior you report, that “more than one light turns on”. It is not possible for both the code in the `if` and the code in the `else if` to be executed (unless there is a prior error affecting program execution, such as behavior not defined by the C standard). Therefore, either the code you show is not the actual code or there is something else affecting it. For example, a prior cycle might have turned on the blue light, and then, on another cycle, it was decided to turn on the green light (and only it), and that was done, but the code did not… – Eric Postpischil Mar 16 '20 at 20:14
  • … turn off the blue light. That is, each run through the code only decides to turn on one light, but the code fails to turn off previous lights. In any case, this is not caused by the floating-point issue you ask about: The problem is some prior error affecting program execution, is some incorrect code controlling the lights, or is due to the actual code being different from what you show. – Eric Postpischil Mar 16 '20 at 20:14
  • @EricPostpischil that's the issue I'm trying to look into at the moment. Right now, the temp is ~19/20 degrees so the blue light should be the only one on, but all of the lights are on so it looks whiteish (with a tint of blue). Same when it's increased to the green interval, green and red are both on. There's a third interval for orange where I turn on both green and red because I don't know how to set the colour amounts in this program, but when it is in that interval it just shows the same as what green should be (red and green both on). It's very strange, but when I take everything out... – lcmting17 Mar 16 '20 at 20:17
  • It is not a floating-point comparison problem. The question is based on a faulty premise. There is a different bug in your code, and that is what you should be looking for. – Eric Postpischil Mar 16 '20 at 20:18
  • make sure the RGB LED is working, each light functions properly. I am not sure if it has to do with my ADC conversions of obtaining an analog temp from the thermistor, converting it to digital, then converting that to temp, but it's all a bit strange right now as the colours aren't just going on one at a time. Yes I realized after asking that the floating point part of my code was fine, and it's actually another bit not doing something correctly. – lcmting17 Mar 16 '20 at 20:18

2 Answers2

1

how else to check the temperature based on a given range with a max and min value(?)

I only want one of the 3 from an RGB LED.

Given only 1 of N colors is the desired result and ranges apparently are adjacent, I'd recommend instead of min/max pairs, use a list of the boundaries. This readily insures only 1 color selected and prevents "more than one light turns on".

Then the boundaries are at -40.0, 20.5, 37.3

#include <math.h>

int TemperatureToColor(double tempValue) { 
  const double Temperature Limit[] = {-40.0, 20.5, 37.3, HUGE_VAL};
  size_t n = sizeof Limit/sizeof Limit[0];
  // Assume if less than -40.0, use red.  
  // Assume if more than 37.3, also use red.  
  const int color[n] = {RED, BLUE, GREEN, RED};
  for (size_t i = 0; i<n; i++) {
    if (tempValue <= Limit[i]) {
      return color[i];
    }
  }
  return BLACK;  // tempValue is not-a-number, or maybe RED in this odd case
}

Detail: some adjustment could be had for boundary cases.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • This does not speak to OP’s question. It is just a different way of arranging the code, not a fundamental change to their tests (aside from correcting `<=` instead of `<`) and does not answer about how accumulated rounding errors in calculations may affect them. (Although OP reports “more than one light turns on”, that is not possible from the `else if` code shown, so there is some other issue at play.) – Eric Postpischil Mar 16 '20 at 20:11
1

should be the only one on, but all of the lights are on so it looks whiteish (with a tint of blue

A common contributor to this is noise. The LEDs' RGB lamps on-time can persists past being enabled. The green/blue are turning on/off in rapid succession when near the transition point given an unsteady temperature reading. Even though only one lamp is enabled, it optically appears as multiple lamps are on. There is also human eye persistence that adds to this.

Solutions include:

  • Slow the sample rate to say 1.0 Hertz to limit the LED change rate.

  • Add hysteresis to the color selection. Once a color selected, the temperature must change by say 1.0 degrees more that the colors range to be considered for a color change.

  • Low pass filter: Rather than use the raw temperature reading, use a running average of the last M samples

  • A combo of the above: once a color changes, it remains that color for at least a time (e.g. 1.0 sec) unless the temperature change is extreme (say 5 degrees out of range). After that minimum time, behave as usual.

I expect the issue about RED is due to faulty unposted code.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • So for some very strange reason, I had to have the LEDs turned off -after- I wrote to my LCD, which I do not understand. Now, the only issue is that in between cycles of checking the temp (5 seconds LED/LCD ON, then it starts the loop again) there is a small flash of white b/c all lights are being turned on for some reason. When the temp changes during/in between cycles, there is no flash and it just goes straight from for example, blue to green, no flash. – lcmting17 Mar 17 '20 at 00:23