-
I have a 10K NTC temperature sensor and I'm a bit lost how I can use it with my LoPy. How do I connect it? How do I read the temperature from it? I just know that I most probably need to use the adc functionality, but thats all.
Thanks for any hint!
-
@tobru said in NTC temperature sensor:
10K NTC
this is simple analog sensor - thermistor
connect it to any analog pin - here you have sample for arduino
but sample is valid for lopy - only difference is that you connect it to 3V3 pin not to 5V pin because pycom board are 3V3 compatibile and not tollerant to 5Vhere you have pinout of lopy
https://www.pycom.io/wp-content/uploads/2016/11/lopy_pinout.pdfand here you have how to program it
https://docs.pycom.io/pycom_esp32/pycom_esp32/tutorial/includes/adc.htmlhere you have sample scaling table

-
Thanks a lot for the explanation. But I don't get it yet =(
I connected 3V3 to the thermistor on one end, G3 (P16) and the 10k resistor to the other end of the termistor. GND is connected to the 10k resistor (other end).
10K Thermistor +-----------+ +-------+ | | | | | 3V3 +----------+ +----+ | | +-------+ | | | | | G3 +-----------------------+ | | | | | +-------+ | | | | | | | GND +----------+ +----+ +-----------+ +-------+ 10K ResistorAll I get is the value 4095 when I read it with the following code:
import machine import time adc = machine.ADC() apin = adc.channel(pin='P16') for i in range(10): val = apin() print(val) time.sleep(1)What did I understand wrong?
-
Ok, looks like the 10K resistor doesn't fit here with 3V3. Nevertheless I'm a bit lost and not sure how to chose the correct resistor and calculate the temperature from the measured value.
-
"The 10k resitor" should be the same value as your termistor resistance (it can be different than 10k, I used the one with 50k resistance). This schematic worked for me with esp8266 (on LUA), so I don't think it have a problem with 3.3V
-
@tobru The problem is that the ADC is saturating.
Try change the ADC input attenuation, which will increase the ADC full scale conversion voltage.
attn = (0 = 0db : 1.1V max), (1 = 2.5db : 1.4V max), (2 = 6db : 1.9V max), (3 = 11db : 3.2V max)
apin=adc.channel(attn=3, pin='P16') # should work for youEdit:
Be warned that the ESP32 ADC is nonlinear and rather noisy.
To reduce the jitter in readings, I take 5 readings at 100us cadence, discard the highest and lowest and average the remaining 3.The non linearity has to be dealt with using a lookup table or conversion function for now.
-
@Shaun said in NTC temperature sensor:
apin=adc.channel(attn=3, pin='P16') # should work for you
Great, this changes the bevahiour and looks much better now. Where do I find documentation about this? The official documentation about ADC doesn't talk f.e. about the
attnparameter. -
@tobru said in NTC temperature sensor:
Where do I find documentation about this?
I answer myself: Here in the forum under LoPy ADCs. Next step: How to calculate the temperature from the measured value. Any hints appreciated.
-
At least you need a known mapping between the temperature and the NTC value. If you have a data sheet of that part, you'll find it there.
From the adc value you can calculate back the resistor value of the NTC, and with the mapping between resistor value and the temperature the temperature.
Assuming that the ADC's range is set to 3.2 V, and the Range is 12 bit, and the connection is as shown below,R_NTC = R1 * (ADC_FULL_RANGE/adc_reading - 1)
R1 = 10000, and ADC_FULL_RANGE = 4096
Line said below, you might take the average of a few readings, and you might have to interpolate between values not in your mapping table.
-
You can find some Arduino code here: https://github.com/adafruit/Thermistor-test/blob/master/thermistortest.pde. Hope you can convert it to Python. Note that our ADC full range is 4096, so you should use 4095 instead of 1023
-
I've tried to convert the arduino code to MicroPython, but I'm not sure if I've done this right (especially the calculation part):
import machine import time import math # which analog pin to connect THERMISTORPIN = 'P16' # resistance at 25 degrees C THERMISTORNOMINAL = 10000 # temp. for nominal resistance (almost always 25 C) TEMPERATURENOMINAL = 25 # how many samples to take and average, more takes longer # but is more 'smooth' NUMSAMPLES = 5 # The beta coefficient of the thermistor (usually 3000-4000) BCOEFFICIENT = 3950 # the value of the 'other' resistor SERIESRESISTOR = 10000 # take N samples in a row, with a slight delay adc = machine.ADC(0) adcread = adc.channel(attn=3, pin=THERMISTORPIN) samples = [0.0]*NUMSAMPLES for i in range(NUMSAMPLES): samples[i] = adcread() print("sample %u: %u" %(i, samples[i])) time.sleep(1) # average all the samples out average = 0 for i in range(NUMSAMPLES): average += samples[i] average /= NUMSAMPLES print("average sample: %u" %average) # convert the value to resistance resistance = 4095 / average - 1 resistance = SERIESRESISTOR / resistance print("resistance: %u" %resistance) steinhart = resistance / THERMISTORNOMINAL # (R/Ro) steinhart = math.log(steinhart) # ln(R/Ro) steinhart /= BCOEFFICIENT # 1/B * ln(R/Ro) steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15) # + (1/To) steinhart = 1.0 / steinhart # Invert steinhart -= 273.15 # convert to C celsius = ((steinhart - 32) / 1.8) - 1 print("celsius: %u" %celsius)To test it, I've connected a 10k resistor instead of the NTC thermistor. The output is:
sample 0: 1879 sample 1: 1857 sample 2: 1863 sample 3: 1878 sample 4: 1863 average sample: 466 resistance: 1284 celsius: 25This looks good at first sight. But then I connected a 1k resistor instead of the NTC thermistor, this should output around 85c, but the output is this:
sample 0: 181 sample 1: 211 sample 2: 199 sample 3: 211 sample 4: 212 average sample: 52 resistance: 130 celsius: 75The value isn't really correct. Any ideas what I'm doing wrong? I'm also wondering about the comment
# convert to Cin the Steinhart equation, the output looks more like Farenheit to me, this is why I added the conversion to celsius (hopefully correct).For the record: I'm using the following NTC thermistor: http://shop.boxtec.ch/temperatursensor-ntc-mit-stahlkappe-p-42342.html
-
Hello @tobru. I see a small glitch in you code. Line 32 should not be indented. It should read:
average /= NUMSAMPLES
without the indents, otherwise the division is done in every loop.
and line 38 has to read
resistance = SERIESRESISTOR * resistanceThe Steinhart-Hart equation calculates Kelvin. I found another example here, which may be the same you were using: https://gist.github.com/100ideas/1119533.
-
I also think the problem was with average. I did not used your latest line (celsius = ((steinhart - 32) / 1.8) - 1) in my code and I think I got adequate results, but I didn't check it without thermistor connected. As of line 38 - it is actualy "/", not "*" - it make 1/x
-
Line 32 should not be indented
Ouch. This of course should not have happened! Thanks a lot to @robert-hh for spoting this! Looks much better now... But: It seems that the measurement is not really accurate, connecting the 10k resistor instead of the NTC thermistor should give me a value around this (I know that it won't be 100% perfect), but it looks like this:
sample 0: 1827 sample 1: 1869 sample 2: 1823 sample 3: 1843 sample 4: 1845 average sample: 1841 resistance: 8170the code:
import machine import time THERMISTORPIN = 'P16' NUMSAMPLES = 5 SERIESRESISTOR = 10000 adc = machine.ADC(0) adcread = adc.channel(attn=3, pin=THERMISTORPIN) samples = [0.0]*NUMSAMPLES for i in range(NUMSAMPLES): samples[i] = adcread() print("sample %u: %u" %(i, samples[i])) time.sleep(1) average = 0 for i in range(NUMSAMPLES): average += samples[i] average /= NUMSAMPLES print("average sample: %u" %average) resistance = SERIESRESISTOR / ((4095 / average) - 1) print("resistance: %u" %resistance)Could it be that the ADC isn't very accurate? What can I do to get a more accurate result of the measurement? Or could it be that the equation for calculating the resistance is wrong?
-
@tobru I think the problem could be also caused by non-exactly-accurate assumption about an ADC range. Even if we assume it's a 3.2V, it's still not the same as the one you are giving to thermister. I think it could cause some non-linear behavior. (In arduino I think they are using external Vref in this mode.)
-
@tobru
There is some known non-linearity in the ESP32 ADC which is not (yet) being compensated on the ESP-IDF (and thus neither in micropython)https://twitter.com/ba0sh1/status/815759185816129536/
For example up to 0.1v it registers 0.0. So at the least you need to account for that.
You may be able to compensate these in software. Personally I'd just use a much more accurate dedicated external ADC - connected over I2C for example - for NTC measurements. For example a ADS1115 breakout can be had for less than $2.
-
I'm still thinking how you have connected the thermistor a) between Vcc and ADC (like sketched below) or b) between ADC and GND. From your code, it looḱs like b)
And yes, there were quite a few notes about the ADC's poor performance. If you need more precise values, you should compensate at least for the actual range. -
@robert-hh said in NTC temperature sensor:
I'm still thinking how you have connected the thermistor a) between Vcc and ADC (like sketched below) or b) between ADC and GND. From your code, it looḱs like b)
It's currently connected like this:
3V3 + | | +-+ |-| |-| 10k resistor (instead of NTC) +-+ | | +--------------+ P16 | | +-+ |-| |-| 10k resistor +-+ | | + GNDDo you think the code doesn't fit this scheme?
@jmarcelino said in NTC temperature sensor:
use a much more accurate dedicated external ADC - connected over I2C for example
I've ordered a Velleman MM112 external ADC with I2C interface, I can then compare the values.
-
I think it should. If you NTC is connected between Vcc and ADC, this line:
resistance = SERIESRESISTOR / ((4095 / average) - 1)
should be:
resistance = SERIESRESISTOR * ((4095 / average) - 1)
For instance:
at 50°C, the value of the NTC is 3588 Ohm. That should give an ADC reading of:4095 * (10000/(3588 + 10000)) = 3014
Put that into your formula, and you get 27881 Ohm
Put that into the other formula, and you get 3587 Ohm.
Regards, Robert -
@robert-hh said in NTC temperature sensor:
resistance = SERIESRESISTOR * ((4095 / average) - 1)
Yes, that looks better, I use the following test code now:
import machine import time THERMISTORPIN = 'P16' NUMSAMPLES = 5 SERIESRESISTOR = 10000 adc = machine.ADC(0) adcread = adc.channel(attn=3, pin=THERMISTORPIN) samples = [0.0]*NUMSAMPLES for i in range(NUMSAMPLES): samples[i] = adcread() print("sample %u: %u" %(i, samples[i])) time.sleep(1) average = 0 for i in range(NUMSAMPLES): average += samples[i] average /= NUMSAMPLES print("average sample: %u" %average) resistance = SERIESRESISTOR * ((4095 / average) - 1) print("resistance: %u" %resistance) Vin = 3.2 buffer = average * Vin Vout = buffer / 4095 buffer = (Vin / Vout) - 1 R2 = 10000 * buffer print("resistance2: %u" %R2)and the output is:
sample 0: 1850 sample 1: 1836 sample 2: 1837 sample 3: 1845 sample 4: 1829 average sample: 1839 resistance: 12262 resistance2: 12262Nevertheless, the ADC accuracy seems to be very bad so measuring the temperature this way seems useless. I'll try it with an external ADC as soon as it arrived.
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login