Help required, Bug in my very first library

I built my first library using an existing one as a base.

Library contains lookup table for a specific thermistor (ntc) and makes the neccesary calculations to provide temperature from analog input.

Unfortunately there is a bug when using the library with ESP32 devices, the temperature reads approx 10 degrees too high (approx 32 degrees when ambiant temp is about 22 degrees celcius)

I can confirm the following:

  1. When using lib with an UNO temp readings are fine
  2. When using another lib (THERMISTOR.h) on the ESP32 temp readings are fine
  3. In my lib both resolution and voltage of the ESP32 are taken into account.

At first I thought it could be caused by the non linearity of the ESP32 ADC, but 10°C deviation @ 22°c seems like way too much to be caused by the ADC

I would appreciate the help very much

I suspected a problem due to the voltage, but you say that's already taken care of in your code. Perhaps that's where the bug is. I'd suggest some serial.prints in the library code to show you what's going on.

any suggestions where i should best focus the search?

I'd get the raw sensor reading first and hand calculate what temperature that should give. That'll give you a clue as to whether you have a code or wiring issue. I assume it's code since you have used it successfully with other Arduinos.

Then add more prints and see what's being computed and where that produced the bad result.

resistance has 34 elements actually assigned to it.
temp_C has the full 39 assigned.
They are both indexed with the same i, which suggests to me that something may be wrong with the values in resistance.

It is ugly and error prone from a maintenance perspective to have the same constant tables defined twice in the two constructors. You don’t need those tables to be part of the class at all - you can define them as static within the cpp file and then skip their initialisation in the constructors. Or alternatively just use one constructor with default arguments.

int i = 0;
while(resistance[i]<r)i++;
float m = (temp_C[i]-temp_C[i-1])/(resistance[i]-resistance[i-1]);// m = (y1-y2)/(x1-x2)

If the while loop completes immediately and i is still 0, then you will be indexing the arrays with -1.

Wow, your'e right, there were some values missing in the lookup table...
After fixing that up it seems to be working fine.

As i said above, ive based it of an existing library, and said library had the two tables set up like that.
I would very much like to have just the one table, so I will try setting it up as you advised.

Thankyou very much

Your code sample should be included in the .h file? Im sorry, i dont understand completely how to set it up properly

mickymik:
Your code sample should be included in the .h file? Im sorry, i dont understand completely how to set it up properly

I'm not sure what you mean. If you are referring to the snippet of code that I posted then that was just to give you context for the bug (in my opinion at least) that I was describing in the following line.
Another point about that unbounded while loop is that it could have the potential to create an index i which points past the end of the arrays.
Whether either of these issues is a problem in the real world based on the values provided in reading is for you to figure out.

ok, yeah I see now that snippet is the potentential problem your were referring to.

Still trying to wrap my head around it all, could you give me some tips on how to implement what you are reccomending? then I could test it out and see if it brings any improvements in the raw data.

mickymik:
Still trying to wrap my head around it all, could you give me some tips on how to implement what you are reccomending?

It depends on how you want to handle the out-of-range situation, but one option is to return an invalid value which the caller can check for if desired, eg. NAN, (not a number). Here is an example:

TS-NTC-103_simple.h

...
class TS_NTC_103 {
private:
	float _vRef;
	int _RESO;
public:
	TS_NTC_103(float vRef = 5, byte RESO = 10);
	float getTemp(int reading);
};
...

TS-NTC-103_simple.cpp

#include "TS-NTC-103_simple.h"
#include <cmath>

static const float resistance[] = { //resistance array
	301,335,372,415,464,520,596,671,757,857,974,1108,
	1266,1451,1669,1925,2229,2589,3537,4162,4912,5829,6941,8314,
	10000,12090,14680,17950,22030,27250,33850,42390,53310,67640		
	};
	
static const float temp_C[] = { //temperature array in celcius
	150,145,140,135,130,125,120,115,110,105,100,95,90,85,80,75,70,65,60,
	55,50,45,40,35,30,25,20,15,10,5,0,-5,-10,-15,-20,-25,-30,-35,-40
	};

TS_NTC_103::TS_NTC_103(float vRef, byte RESO) : _vRef(vRef), _RESO(1023) {
	if (RESO==12) _RESO = 4095;
}

float TS_NTC_103::getTemp(int reading) {//input a bitrade value from analog input
	float Vin = 0;
	Vin = reading*_vRef/_RESO;	//find voltage in the input
	float r = (Vin / (_vRef - Vin) * rRef); //calculate the resistance
	//find between resistance in the table
	int i = 0;
	do {
		if (resistance[i] > r) break;
	} while (++i < (sizeof(resistance)/sizeof(*resistance)));
	if (i == 0 || i == (sizeof(resistance)/sizeof(*resistance))) return NAN;
	//find m and b value of y=mx+b ==>	
	float m = (temp_C[i]-temp_C[i-1])/(resistance[i]-resistance[i-1]);// m = (y1-y2)/(x1-x2)	
	float b = temp_C[i-1]-(m*resistance[i-1]);//find b = y1 - m*x1*/
	float temp = m*r+b; //y=mx+b
	return temp;
}

Your calling sketch can check for NAN using isnan(…)

first of all here is the updated resistance table:

static const float resistance[] = { //resistance array
	308.7,342.4,380.8,424.3,474.1,530.9,596.1,671,757.6,857.4,973.7,1108,
	1266,1451,1669,1925,2229,2589,3022,3537,4162,4912,5829,6941,8314,
	10000,12090,14680,17950,22030,27250,33850,42390,53310,67640,86180,
	11090,14340,18740		
	};

Ive updated the library using your code.

Normally I would write:

 TS_NTC_103 sensor; //for Arduino
...
or
...
  //TS_NTC_103 sensor(3.3,12); //For ESP32 (3.3v and 12bit)

after changes temp measurement appears to be correct on the ESP32 with arduino setting, and with ESP32 setting it reads approx 80°c

Ideas?

#include <TS-NTC-103_simple.h>

void setup() {
 Serial.begin(9600);
}

void loop() {
 TS_NTC_103 sensor; //start an instance of the library
  //TS_NTC_103 sensor(3.3,12);  //support for 3.3 volt board and/or 12bit analog read resolution
  Serial.print("temp: ");
  //Serial.println(sensor.getTemp(analogRead(A0)));
  Serial.println(sensor.getTemp(analogRead(36))); //Pin 36 for ESP32 board
  delay(1000);

}

This code yeilds what seems to be accurate readings on the ESP32, however the readings should be false, as the voltage and resolution are not correctly defined for the ESP32.

Or does it somehow automatically set the res and vref?

Please disregard above comments, I had a 47k pullup resistor installed as I was experimenting with other libraries.
I re installed the 10k pullup (as defined in lib) and the values are still about 10° too high.

I wanted to test again on the uno to confirm previous values, however code will nolonger compile on arduino boards due to

mickymik:
I wanted to test again on the uno to confirm previous values, however code will nolonger compile on arduino boards due to

You might not need the include at all, but if you do, then use “math.h” instead.

You know that you don’t have to use real readings from the sensor for testing the library; you can just run through all values from 0 - 4095, feed them to your conversion function and print them out.

Just a style note..

You might want to put the public stuff at the top because that's the stuff others need to use to make it work.

class TS_NTC_103 {
private:
 //lookup table
 const float resistance[39];
 const int16_t temp_C[39];
 float _vRef = 5;
 int _RESO = 1023;
public:
 TS_NTC_103();
 TS_NTC_103(float vRef, int RESO);
 float getTemp(int reading);
};

Or not..

-jim lee

Removed #include

Sketch compiled on both Uno and ESP32Uno

On the Arduino temperature reads accurate (25°c, confirmed with digital thermometer)

On the ESP32 temp reads high (29-30°c)

Starting to think its just the nonlinerarity of the ESP’s ADC.

Everything else is working fine.

@Arduan, How can I do that? I think thats a great way to determie if its a pronlem with the ADC or not

@ jimlee, thanks for the tip, note taken

mickymik:
@Arduan, How can I do that? I think thats a great way to determie if its a pronlem with the ADC or not

Call your getTemp() function inside a for loop 0 → <4096, with any step you like, +1 +3, whatever.

Sorry, typical noob problems here…

Can you tell me what I am doing wrong?

for (int i = 0; i < 4096; i+5){
  Serial.println (sensor.getTemp(i));
  delay(1000);
}

i+=5

You'll probably want to print i as well and you don't need the delay unless you like waiting.

I checked it out and got the following:
29.36
1885
29.39
1886

top is temp from the table followed by theretical ADC value for said temp, followed by temp from sensor.getTemp and finally actual raw value from analogread.

Safe to say that the values are being taken from the table correctly.

When i connect the sensor to the Uno and run the following code I get around 2030 as a comparison value.

#include <TS-NTC-103_simple.h>




void setup() {
 Serial.begin(9600);
}

void loop() {
  TS_NTC_103 sensor; //start an instance of the library
  //TS_NTC_103 sensor(3.3,12);  //support for 3.3 volt board and/or 12bit analog read resolution
 
  int adjusted;
  int raw = analogRead(A0);
  adjusted = map (raw,0,1023,0,4096);
  Serial.println (adjusted);
  delay(100);

}

I believe the deviation is from the non linear ADC. The raw value is being converted corectly, but the raw value itself not correct.

Do you have any ideas for possible solutions?
Is it feasible to add a second lookup table for ADC values? (i.e. would such a table work across all ESP32’s, or is an individual solution needed for each device)?