## Temperature measurement using a NTC thermistor and an AVR microcontroller
NTC thermistor characteristics
Calculating the temperature Schemes of connection Connecting of thermistor Connecting to ADC of MCU ATmega Online table calculation Example of usage Author: Pogrebnyak Dmitry Russia, Samara, 2013.
One of methods to measure temperature is to use a thermal resistor (or a thermistor for short). It has significant value of the thermal coefficient, i.e. changing of resistance with changing of temperature (at level of 2-10% per Kelvin). There are two types of thermistors – Positive Temperature Coefficient (PTC) which increases their resistance when temperature is growing up; and Negative Temperature Coefficient (NTC) which decreases resistance when temperature is growing. This article describes usage of a NTC only in link with an AVR MCU for purposes of temperature measurement. ## NTC thermistor characteristicsThermistors have a lot of parameters that characterize them, such as: maximum allowed current, resistance tolerance, resistance at particular temperature (usually 25°С). One of them is a B = (ln(R _{1}) – ln(R_{2})) / (1 / T_{1} - 1 / T_{2})[1],R There are the reverse formulas: R _{1} = R_{2} * e^{(B * (1 / T1 - 1 / T2))}[2].T _{1} = 1 / ((ln(R_{1}) – ln(R_{2})) / B + 1 / T_{2})[3].## Calculating the temperatureParameters of thermistors have high level of non-linearity. The B parameter has different values, when measurement based on different temperatures. Two different models of thermistors with same B Thus formula A better way is to store a table in the memory, whose cells will contain precalculated ADC values, corresponding to temperatures. For memory economy it is possible to store ADC values only for several temperature points (given with some step), then to find it using binary search and to calculate resulting temperature, using linear interpolation. To measure ambient temperature in range from -30°С to +70°С with accuracy up to 0.3°С, it is require to store 20 values (with step of 5°С). If every value will fit into 16 bits, it will require only 40 bytes of the flash-memory – that is much less, than memory required to store floating math routines. Decreasing table step down to 2°С, it is possible to take accuracy at level of 0.1°С on wide measurement range. Vendors of thermistors usually give tables of R/T characteristics, which show how resistance changed over temperature. For example, Siemens-EPCOS gives those tables with step of 5°С. To calculate intermediate values, it is possible to interpolate them with high accuracy, using formulas ## Schemes of connection## Connecting of thermistor
The simplest way to connect thermistor to a MCU (or an ADC IC) is Scheme A. To minimize measurement error, the R When selecting values of thermistor resistance and R Scheme B is used to minimize power dissipated on thermistor. Schemes C and D – is reverse for A and B. They are to use, if required to measure low temperatures, when ADC referent voltage (U ## Connecting to ADC of MCU ATmega
To minimize a noise, inducted by digital lines, MCUs ATmega use separate power supply pins for the ADC module. The datasheet recommends to connect these pins through a filter: the inductance L = 10µH, and the capacitor C2 = 0.1µF. The ADC of the MCU can use as referent voltage either external voltage, connected to AREF pin, or internal 2.56V or 1.1V (depend on MCU model), or use AVCC supply voltage as referent value. When internal or AVCC voltage is used, an external capacitor must be connected between the analog ground and the AREF pin. The datasheet gives no exact recommendation for choosing this capacitance. I recommend to use a ceramic capacitor 0.1µF or more. To minimize a noise, I recommend to use same filtered voltage, which is used for AVCC line, to supply thermistor scheme, and to use same AVCC as referent voltage. Additionally, to suprres noises in wires, the capacitor C3 (1-100nF) could be installed. Should be taken into account, that, besides of the ADC, the AVCC input used to supply digital levels on some pins (usually this is the same pins, where ADC inputs is located). Usage of those pins for digital input/output and connecting a load to it can produce an additional noise on the ADC. To minimize measured ADC noises, and increase accuracy, I recommend to perform several consequent measurements, and to sum their results. ATmegas have 10-bit ADC. Sum of 64 measurements still be in range of 16-bit integer, thus not require additional memory to store table of values. When making more measurements, it is possible to keep it in range of 16 bits, by dividing or shifting result. ## Online table calculationHere I brought for your comfort the online script for ADC values table calculation. Calculation is performed by: - Two values of temperature and corresponded to them values of thermistor resistance; - One pair of temperature/resistance and B coefficient; - Entered list of R/R1 values given with some step; - One of preloaded R/T characteristics. Now there are preloaded R/T characteristics for Siemens/EPCOS thermistors. Please, select one, which corresponds to yours. Preloaded characteristics are given with step of 5°С. When selecting the grid step less than 5°С, intermediate values are calculated using the formulas When the table is renewed, the source code under it is updating automatically.
To know what R/T characteristics correspond to your thermistor, please refer to vendor datasheets. Here the table of commonly used thermistors Siemens/EPCOS is given. Press to an R/T characteristic code to load it into the calculation form below.
The error value could be lowered when selecting a lower grid step, selecting the ADC of higher resolution, averaging of many measurements, and by selection of resistors values.
#include <avr/io.h> #include <avr/pgmspace.h> // Value when sum of ADC values is more than first value in table #define TEMPERATURE_UNDER 0 // Value when sum of ADC values is less than last value in table #define TEMPERATURE_OVER 0 // Value corresponds to first entry in table #define TEMPERATURE_TABLE_START 0 // Table step #define TEMPERATURE_TABLE_STEP 50 // Type of each table item. If sum fits into 16 bits - uint16_t, else - uint32_t typedef uint16_t temperature_table_entry_type; // Type of table index. If table has more than 255 items, then uint16_t, else - uint8_t typedef uint8_t temperature_table_index_type; // Access method to table entry. Should correspond to temperature_table_entry_type #define TEMPERATURE_TABLE_READ(i) pgm_read_word(&termo_table[i]) /* Table of ADC sum value, corresponding to temperature. Starting from higher value to lower. Next parameters had been used to build table: */ const temperature_table_entry_type termo_table[] PROGMEM = { 0 // Press "Build table" button on form above to fill this array }; // This function is calculating temperature in tenth of degree of Celsius // depending on ADC sum value as input parameter. int16_t calc_temperature(temperature_table_entry_type adcsum) { temperature_table_index_type l = 0; temperature_table_index_type r = (sizeof(termo_table) / sizeof(termo_table[0])) - 1; temperature_table_entry_type thigh = TEMPERATURE_TABLE_READ(r); // Checking for bound values if (adcsum <= thigh) { #ifdef TEMPERATURE_UNDER if (adcsum < thigh) return TEMPERATURE_UNDER; #endif return TEMPERATURE_TABLE_STEP * r + TEMPERATURE_TABLE_START; } temperature_table_entry_type tlow = TEMPERATURE_TABLE_READ(0); if (adcsum >= tlow) { #ifdef TEMPERATURE_OVER if (adcsum > tlow) return TEMPERATURE_OVER; #endif return TEMPERATURE_TABLE_START; } // Table lookup using binary search while ((r - l) > 1) { temperature_table_index_type m = (l + r) >> 1; temperature_table_entry_type mid = TEMPERATURE_TABLE_READ(m); if (adcsum > mid) { r = m; } else { l = m; } } temperature_table_entry_type vl = TEMPERATURE_TABLE_READ(l); if (adcsum >= vl) { return l * TEMPERATURE_TABLE_STEP + TEMPERATURE_TABLE_START; } temperature_table_entry_type vr = TEMPERATURE_TABLE_READ(r); temperature_table_entry_type vd = vl - vr; int16_t res = TEMPERATURE_TABLE_START + r * TEMPERATURE_TABLE_STEP; if (vd) { // Linear interpolation res -= ((TEMPERATURE_TABLE_STEP * (int32_t)(adcsum - vr) + (vd >> 1)) / vd); } return res; } ## Example of usageIn example below, temperature is displayed on 7-segment indicator. It utilizes the ledind_num() function that is described in my another article (in Russian).
ADMUX = 0b01000111; // ref voltage - Vcc, input ADC7, right-edged result ADCSRA = 0b10000111; // 1/128 prescaler, ADC enabled while(1) { temperature_table_entry_type summ = 0; for (uint8_t i = 0; i < 64; i++) { ADCSRA |= _BV(ADSC); loop_until_bit_is_clear(ADCSRA, ADSC); summ += ADC; } int16_t t = calc_temperature(summ); ledind_num(t, 1, 0b01010011); // Output value with t-styled prefix _delay_ms(250); } 5 ms; mod: Sat, 06 May 2017 20:41:51 GMT; gen: Tue, 24 Oct 2017 05:32:51 GMT |