This is a C++ class for a simple NTC thermistor. I used the thermistor included in the cooking-hacks.com starter kit (datasheet) and the cooking-hacks.com Raspebby to Arduino shield, but this sample is easily adaptable for any NTC thermistor or also for Arduino platform. It can be used with another NTC thermistor: simply change the BasicThermistor.h values:
- BETA (o B-Value) : the beta value of thermistor
- THERMISTOR: zero power resistance at 25° C
Some notes:
- This class is designed for a read every 10 seconds.
- Check the real value of 10k resistance with a multimeter! The 10% tollerance changes the value of about ± 1° C!. In my example I use 9840 Ω instead of 10000 Ω
- I use a arithmetic mean over 12 readings (2 minutes) in order to normalize the temperature value and discard read errors
- I use a simple “is_valid_value” function that discard a macroscopic read error. A “digital” read error of ± 20 is converted to an error of ± 14° C ! So if the previous valueis too big or too small, discard the current value
Header file – BasicThermistor.h
/* * BasicThermistor.h * * Created on: 07/ago/2013 * Author: sarbyn * Website: http://www.sarbyn.com */ #ifndef BASICTHERMISTOR_H_ #define BASICTHERMISTOR_H_ #include "arduPi.h" #include /** * Based on cooking-hacks NTC thermistor - datasheet available at * http://www.cooking-hacks.com/skin/frontend/default/cooking/pdf/159-282-86001.pdf */ // The real 10k resistor value #define TENKRESISTOR 9840.0f // Thermistor beta value (from datasheet) #define BETA 3950.0f // The thermistor value at room temp (25 C) // the original value was 2800 ohm #define THERMISTOR 2700.0f // The room temperature (25 C) in kelvin #define ROOMTEMPK 298.15f // Number of readings over which calculate // the temperature #define READINGS 12 // Delay (in ms) between Wire operations #define DELAY_BETWEEN_OPERATION 20 // The digital value readed from ADC // must be lower than DIGITAL_TOLLERANCE // Otherwise it is treaded as a read error #define DIGITAL_TOLLERANCE 20 // If the digital value readed from ADC is wrong for // more than DIGITAL_TOLLERANCE_COUNTER, it is a correct value // and so use it. This is used in case of sudden // temperature change. If the temperature changes suddenly, // the value is discarded for DIGITAL_TOLLERANCE_COUNTER reads. After that // the value is accepted #define DIGITAL_TOLLERANCE_COUNTER 6 #define ADC_I2C_ADDRESS 8 class BasicThermistor { public: BasicThermistor(byte i2c_address, boolean debug_flag); float read_temperature(); private: byte address; boolean debug; int digital_value; float read_buffer[READINGS]; unsigned int cached_digital_value; float temperature; int invalid_read_counter; int buffer_pointer; int read_digital_value(); int is_valid_value(int value); float calc_temperature(int value); }; #endif /* BASICTHERMISTOR_H_ */
Class file – BasicThermistor.cpp
/* * BasicThermistor.cpp * * Created on: 07/ago/2013 * Author: sarbyn * Website: http://www.sarbyn.com * */ /** * Based on cooking-hacks NTC thermistor - datasheet available at * http://www.cooking-hacks.com/skin/frontend/default/cooking/pdf/159-282-86001.pdf */ #include "BasicThermistor.h" // Costructor BasicThermistor::BasicThermistor(byte i2c_address, boolean debug_flag) { address = i2c_address; debug = debug_flag; temperature = 0.0; cached_digital_value = 0; digital_value = 0; invalid_read_counter = 0; buffer_pointer = 0; for (int i = 0; i < READINGS; i++) { read_buffer[i] = -1.0f; } } // Read the digital value from ADC using Wire class int BasicThermistor::read_digital_value() { unsigned char val_0 = 0; unsigned char val_1 = 0; unsigned int digital_value; Wire.beginTransmission(ADC_I2C_ADDRESS); Wire.write(address); // sleep in order to reduce read error delay(DELAY_BETWEEN_OPERATION); Wire.requestFrom(ADC_I2C_ADDRESS, 2); // sleep in order to reduce read error delay(DELAY_BETWEEN_OPERATION); val_0 = Wire.read(); // sleep in order to reduce read error delay(DELAY_BETWEEN_OPERATION); val_1 = Wire.read(); // sleep in order to reduce read error delay(DELAY_BETWEEN_OPERATION); digital_value = int(val_0)*16 + int(val_1>>4); if (debug) { printf("[BT] val [%2x,%2x]\n", val_0, val_1); printf("[BT] Read digital value %d\n", digital_value); } return digital_value; } // Check if the readed value is valid int BasicThermistor::is_valid_value(int value) { if (cached_digital_value == 0) { cached_digital_value = value; return 1; } // check against DIGITAL_TOLLERANCE if (abs(cached_digital_value - value) < DIGITAL_TOLLERANCE) { if (debug) printf("[BT] Valid digital value %d\n", value); cached_digital_value = value; invalid_read_counter = 0; return 1; } if (invalid_read_counter > DIGITAL_TOLLERANCE_COUNTER) { // too many invalid readings ---> this is a valid read if (debug) printf("[BT] Too many invalid digital value %d..so use it\n", value); cached_digital_value = value; invalid_read_counter = 0; return 1; } // throw away invalid reading invalid_read_counter++; if (debug) printf("[BT] Invalid digital value %d\n", value); return 0; } // Convert the ADC value to Celsius Temperature float BasicThermistor::calc_temperature(int value) { // convert value float analog_value = value * 1023.0 / 4095.0; analog_value = (1023 / analog_value) - 1; analog_value = TENKRESISTOR / analog_value; analog_value = analog_value / THERMISTOR; if (debug) printf("[BT] Analog value %f\n", analog_value); float kelvin = log(analog_value); kelvin /= BETA; kelvin += 1.0 / ROOMTEMPK; kelvin = 1.0 / kelvin; return kelvin - 273.15; } // Main read function: read the current temperature and return it. // This is designed for a read every 10 seconds: it collects 12 readings // (READINGS macro value, 2 minutes) and calculate mean over all the values. // In this way the temperature value does not change suddenly and // become more stable float BasicThermistor::read_temperature() { digital_value = read_digital_value(); float single_temperature; if (is_valid_value(digital_value)) { single_temperature = calc_temperature(digital_value); if (debug) printf("[BT] Single current temperature is %f\n", single_temperature); } else { single_temperature = calc_temperature(cached_digital_value); if (debug) printf("[BT] Invalid temp, using cached value %f\n", single_temperature); } if (debug) printf("[BT] Storing the temp at pointer %d\n", buffer_pointer); read_buffer[buffer_pointer] = single_temperature; buffer_pointer++; if (read_buffer[buffer_pointer] == -1.0f) { // this is the first reading....init the buffer for (int i = buffer_pointer; i < READINGS; i++) { read_buffer[i] = single_temperature; } } // reset the pointer if (buffer_pointer == READINGS) buffer_pointer = 0; temperature = 0; if (debug) { printf("[BT] Temp. buffer["); for (int i = 0; i < READINGS; i++) { printf("%0.1f,", read_buffer[i]); } printf("]\n"); } for (int i = 0; i < READINGS; i++) { temperature += read_buffer[i]; } temperature /= READINGS; return temperature; }