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. Внимание. Сей опус является неубедительной моей попыткой перевести собственное творчество на ломанный английский язык. Поэтому, если вам русский язык кажется чем-то родным и близким, то прочтите, пожалуйста, оригинал этого манускрипта на родном языке автора. Впрочем, если вы при этом знакомы с языком, претерпевшем много боли ниже по тексту, и обладаете крепкими нервами и здоровым чувством юмора, то, как говорится, ю а вэлкам. Note. This is a weak translation of an article originally written in Russian. So, if you famous with Russian language, it is preferred to read it in the original language. 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 coefficient of temperature sensitivity or the B parameter. This parameter is calculated, when measuring two resistance values for two different temperatures. In most cases it is 25°С and 100°С. Usually, temperatures that was used to calculate B is printed after the B letter, for example: B25/100. The B parameter measured in Kelvins and can be calculated, using the formula: R1 and R2 - the values of resistance for temperatures T1 and T2 respectively, expressed in Kelvins. There are the reverse formulas: 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 B25/100 value could change their resistance in different ways over a temperature range. Thus formula [3] can be used only for a rough estimation of temperature. In addition, this formula requires heavy calculation, which requires much of CPU time. Since the CPU of the MC usually has no floating point math support, these calculations are not applicable. 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 [1] and [2]. Schemes of connectionConnecting of thermistor
The simplest way to connect thermistor to a MCU (or an ADC IC) is Scheme A. To minimize measurement error, the RA value should be close to thermistor resistance value in the measurement range – that makes ADC values changing closer to linear, and consequently, allows to minimize error while linear interpolation. When selecting values of thermistor resistance and RA, it is should be taking into account, that current that flow thru the thermistor, will provoke its heating, and, as consequence, distortion of the measured value. It is desirable, than dissipated power on thermistor never excess 1mW. Thus, if input voltage U0 = 5V, then values of RA and thermistor resistance at measured range should be at least 10 kiloOhms each. 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 (Uref) is lower than U0. 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 [1] and [2]. When the table is renewed, the source code under it is updating automatically. Note! Due to high non-linearity of thermistor parameters, calculations based on two values are rough and then calculated value of temperature can be significant different from actual one for high and low temperature measurements. 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.
Form for online calculating of ADC values
Explanation of table fields: Bold values of R/R1 and R columns are taken from preloaded array, or entered values. Non-bold values are obtained by calculations, using formulas. ADC – the rounded value that will be taken from ADC output, with respect to multiplier. Values that fallen out of ADC range, are not displayed here. I,µA - current in whole circuit. P,mW - power, dissipating on thermistor. E – heuristic estimation of a measured value error, when using the linear interpolation, taking into account a limited ADC accuracy. It enables to find parameters and scheme to minimize an error in a range of measured temperatures. This estimation does not taking into account an ADC noise, and a heating of thermistor due to power dissipation on it. 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. Code, corresponding to table #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); } 0 ms; mod: Mon, 11 Jan 2021 09:39:36 GMT; gen: Thu, 21 Nov 2024 09:33:27 GMT |