Help with lookup table

Hi all, I’ve been using arduino for a while now but I’m still a novice when it comes to code, this is my first attempt to utilise a lookup table and i just can’t get my head around how to do it. Basically I’m trying to figure out how to use a lookup table for the values below (Vin being converted from adc) so that i can output a whole number to a display.

Temp; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
Vin (mV) 1034, 1028, 1023, 1017, 1012, 1007, 1001, 996, 990, 985, 980, 974, 969, 963, 958, 952, 947, 941, 936, 931, 925

I understand how to convert the adc value to a voltage, I just can’t figure out how to convert the voltage into the assosciated temp value in a form that will output The nearest whole number.

I have tried searching for examples but I either can’t find exactly what I’m looking for, or i just don’t understand what I’m looking at.

Usually, a lookup table is used to get fast answers (at a cost in memory). Do you really need to do this?

I would help, but you haven't specified what should happen with Vin of 1033, 1032, 1031, 1030, 1029, 1027, 1026, 1025, 1024, etc. Also 1035 and above. Also 924 and below.

The short version is to take Vin, subtract 925, and then access a table, but the table is going to need at least 109 (110?) entries, and you are going to have to do something about Vin above 1034 and below 925.

Do you know how to initialize and use an array?

I suppose you could use a table of 21 entries and use a loop and some logic to find the closest entry and use the associated index, but this may be more than a novice task. Conceptually, your table would contain the int values 1034, 1028, 1023, ... in entries 0, 1, 2, etc. You would scan the table (looking at entries 0, 1, 2,...) looking for your Vin to be equal to the table entry (or perhaps between two table entries). When this happens, get the index of the table entry and output that index value on the display.

There are ways to reduce the memory cost (by subtracting 925 and using the byte datatype) but this is the main idea. It is hard to help when some issues are unspecified.

I should probably explain more, I’m using an LMT86 sensor (datasheet here http://www.ti.com/lit/ds/symlink/lmt86.pdf) to monitor temperature in an engine’s oil system, I’ve attached my current code which uses an equation to calculate the temp based on input voltage from the sensor. although this code does run it is not as accurate as i would like, and is off by approx 4 degrees centigrade at the extremes. The datasheet for the sensor contains a look up table for it’s complete range of meassurement so I would like to use this instead as it appears to give much more accurate results. I’m only interested in a specific range of values and would like anything smaller or greater than my specific range to display the appropriate warning image on my display. This is currently set to any reading over 130 and under 50 although I will be changing this to any readings over 150 degrees and under -50.

#include <Goldelox_Const4D.h>
#include <Goldelox_Const4DSerial.h>
#include <Goldelox_Serial_4DLib.h>
#include <SoftwareSerial.h>
#define DisplayTemp mySerial
#define tempPin 0

SoftwareSerial mySerial(3, 4); // RX, TX
Goldelox_Serial_4DLib DisplayT(&DisplayTemp);

int oilValue;
int oilTemp;
int vccConst = 1;
int offSwitch = 5;

void setup() {
  delay (3000);
  DisplayTemp.begin(38400) ;
  DisplayT.TimeLimit4D = 2000 ;  // 2 second timeout on all commands
  DisplayT.gfx_Cls();
  DisplayT.media_Init();
  DisplayT.media_SetSector(0xA200, 0x0000) ;
  pinMode(vccConst, OUTPUT);
  pinMode(offSwitch, INPUT);
  digitalWrite(vccConst, HIGH); 
   
}

void loop()  { 
  int sensorValue = analogRead(A0);
  float voltage= (sensorValue * (5.0 / 1023.0))*1000;
  oilTemp = (((10.888 - sqrt((sq(-10.888)) + (4 * 0.00347 * (1777.3 - voltage)))) / (2 * (-0.00347))) + 30);


  if (oilTemp < 50) {
    DisplayT.media_VideoFrame(0, 0, 83) ;
  }
  else if (oilTemp > 130)  {
    DisplayT.media_VideoFrame(0, 0, 82) ;
  }
  else {
  oilValue = (oilTemp-49);
  DisplayT.media_Init();
  DisplayT.media_SetSector(0x0000, 0x0000) ;
  DisplayT.media_VideoFrame(0, 0, oilValue) ;
  }

  if (digitalRead(offSwitch) == HIGH) {
  DisplayT.media_Init();
  DisplayT.media_SetSector(0x0000, 0x0000);
  DisplayT.media_VideoFrame(0, 0, 0) ;
  delay (5000);
  DisplayT.gfx_Contrast(0);
  delay(2000);
    if (digitalRead(offSwitch) == HIGH) {
    digitalWrite(vccConst, LOW);
    }
    else {
    DisplayT.gfx_Contrast(10);
    }
  }
}

In answer to your question regarding the inbetween voltage readings, I would like to somehow assosciate these values to the nearest mapped voltage/temp as i only need to display whole numbers, which I’m also unsure how to achieve. I’m also unsure of how to initialize and use an array.

OilTemp.ino (1.48 KB)

Equation 2 in the temperature sensor datasheet gives the right result for 420mV, and is only 1 degree C off for 2616 mV. If you are seeing an error of 4 degrees C, I suggest that the problem lies elsewhere and you do not need a lookup table. You do not need to learn about C/C++ arrays, either, but it would be a good idea to learn this anyway.

You do a floating point calculation and then store the result in an int. The storing into an int does NOT do any rounding and can lead to a nearly 1 degree C error.

I do not know where the remaining error is located. I do notice that the Atmel datasheet for the ATmega48PA/88PA/168PA/328P uses 1024 (NOT 1023) in the conversion from ADC reading to voltage. Also, if the voltage at the AVCC pin is not precisely 5.000 volts, this will cause some error. The temperature sensor itself can also have a small error.

You need to print out the calculated voltage and compare it with the result from a high accuracy (at least 5 digits) DVM. There may be a voltage error rather than a temperature error.

If you want to go further, a circuit diagram and some additional data would be helpful.

So you have two arrays, one with inputValue, one with desired outPutValue

inputValue should start and end with min and max of the possible readings and represent your intervals sorted in ascending order

Like inputValue ← 0 … 225 … 345 … 576 … 900 … 1023

outPutValue Should have 1 less element and correspond to what output you want t o see when you fall in a given interval

Like outPutValue ← 0 1 2 3 4

Assuming you have nbInputValue in the inputValue array, and you read a value inputSample then you want to do something like this in plain English

If nbInputValue is less than 2 then you have not defined really intervals. Stop
For inputIndex varying between 0 and nbInputValue-2
    If inputSample is between inputValue[inputIndex] and inputValue[inputIndex+1] then
         You found in which interval segment the input sample is, outputValue[inputIndex] is your Output
     
If you did not find the sample by scanning the array then you did not define the inputValue array correctly.

Within an interval you might want to check if you are pretty close to the the end of the range and possibly decide to return the next value (round up) if there is one. In my example above, if your sample is 222 you might want to return 1 not 0, but if it is 1020 still return 4 because you are at the end of the range. To decide when you are close to the top you need to have a rule you define, like if I am after the mid point of the interval, then round up.

Is that enough to help you code this?

It helps me but is unlikely to help someone who does not know arrays. Furthermore, an equation-based approach should be sufficient.

That is kind of the point unless he wants to stay a novice...he asked about lookup tables (which is not exactly this as I went for intervals, not matching each input to each output)

And equation based approach with a set of constant y for varying x is just a bunch of if else. You can hardcode them manually without arrays

If inputSample is greater than v0 and less than v1 then output is a0 else If inputSample is greater than V1 and less than v2 then output is a1 else ....

or solve it in a more general case with arrays, which is what I proposed as a learning exercise and less lines of code if you need many intervals

If dan22h will insert and use this function:

int roundFloatToInt(float r) {return (r > 0.0) ? (r + 0.5) : (r - 0.5);}

with the equation that dan22h already has, there will be no need for lookup tables or if...else.

dan22h has other issues. The lookup table was a false lead. (In American English, the lookup table was a red herring.)

I heartily agree that dan22h should learn about arrays and lookup tables if dan22h does not want to stay a novice.